Skip to content

hugogirard/apimPrivateVnet

Repository files navigation

About this sample

This sample provide two Github action that will create all the infrastructure in place to have a private APIM exposed to public Internet using Application Gateway with WAF.

3 samples application are available in the Github repository but are not deployed today with the Github Actions, this need to be done manually if desired.

Prerequisites

First step is to Fork this repository.

Here the tool you need to installe on your machine.

Here the list of all supported clients if you want to implement your own logic for the Let's Encrypt Certificate.

Create Azure DNS Public Zone

This demo is using Azure Public DNS Zone, you will need to have a domain that you own from any register. Once is done you need to configure your DNS in your domain register with Azure DNS Public Zone entry.

It's all explain here.

Run this step ONLY if you don't have a SSL certificate

Be sure you already configured your Azure Public DNS Zone.

First create a service principal running the following command.

$ az ad sp create-for-rbac --name <ServicePrincipalName> --sdk-auth --role contributor

Take note of the output you will need it to create Github Secrets.

Now go to the folder scripts, there you have a powershell called letsEncrypt.ps1.

This script will connect to your Azure Subscription passed in parameters and create a TXT challenge in your Azure DNS Public Zone.

First run this command in a PowerShell terminal

$ Set-PAServer LE_PROD

Now with the information retrieved when you created the service principal you can create your certificate.

Be sure your Service Principal have access to modify your Azure Public DNS Zone. If you want to use least priviledge refer to this doc.

$ .\letsEncrypt.ps1 -certNames *.contoso.com -acmeContact [email protected] -aZSubscriptionId <subId> -aZTenantId <tenantId> -aZAppUsername "<sp_clientId>" -aZAppPassword "<sp_password>" -pfxPassword "<pfxPassword>"

Be sure the username, password and certificate password are in double quotes

When the command is finished, a new folder called pa will be created inside the scripts folder.

If you browse in it inside the last child folder of acme-v02.api.letsencrypt.org you will see those files. We want cert.pfx

Upload certificate to your certificate store

Here are the steps to upload the cert you created in your project directory to your certificate store:

  1. In your folder explorer, navigate to the location of your cert:
C:\Users\myUser\source\repos\apimPrivateVnet\scripts\pa\acme-v02.api.letsencrypt.org\...
  1. Right click on cert.cer -> Install Certificate

Creating Azure Resources

Create Github Secrets

To create the architecture and all Azure resources you need to setup some Github Secrets before.

Here the list of all Github secrets that need to create before running the Github Action.

Secret Name Description Link
ADMIN_VAULT_OBJECT_ID This is the object ID of the super admin that you want to give access to KeyVault. In the Azure portal, go to Azure AD ➡️ Users ➡️ choose the admin user which you will be using to deploy the resources in this repo ➡️ Copy "Object ID" value
PA_TOKEN You will need to have a Personal Access Token to write secrets after running the first GitHub Action. You can find the information here. The PA needs the public_repo scope. This is needed for this specific GitHub Action
SP_AZURE_CREDENTIALS Secret that contains the credential to run Az Login. Paste the entire JSON output from service principal creation above. The JSON object includes clientId, clientSecret, etc. GitHub Action
SP_PRINCIPAL_OBJECT_ID The object ID of the service principal created above. This is the service principal that will enable you to run the GitHub Action and log into Azure
PUBLISHER_NAME The publisher name associated to APIM (e.g. Contoso)
PUBLISHER_EMAIL The publisher email associated to APIM (e.g. [email protected])
ADMIN_USERNAME_SQL The admin username for the SQL Azure Database (e.g. azureadmin)
ADMIN_PASSWORD_SQL The password for the SQL Azure Database
HOSTNAME The hostname of your domain (e.g. contoso.com)
ADMIN_USERNAME The admin username of the Jumpbox and on-premises VM (e.g. azureadmin)
ADMIN_PASSWORD The password of the Jumpbox and on-premises VM
DEV_PORTAL_GW_HOSTNAME The DNS name of the Developer Portal (e.g. dev.contoso.com)
MANAGEMENT_GW_HOSTNAME The hostname of the management plane (e.g. mgt.contoso.com)
SUBSCRIPTION_ID The subscription ID for the Azure subscription used to deploy the resources in this repo
SHARED_KEY The shared key needed for the VPN connection. Provide a random key value here. Azure VPN Gateway documentation

Run Github Action Deploy APIM Infra

Now go in the Actions Tab

Select Deploy APIM Infra

On the right menu click the Run workflow button and click the Run workflow green button.

The Github action will take around 45 minutes to complete. The Github action will create 3 new Github secrets needed to execute the next pipeline.

Upload your certificate in Azure Key Vault

Now upload you generated or existing certificate in Azure KeyVault.

Go to the certificates tabs in your Azure KeyVault

From there click the Generate/Import button and import your pfx files from your certificate.

Once the certificate is imported in KeyVault click on it.

You will find a textbox with the label Secret Identifier.

Copy the value from that textbox you will need to create a Github secret.

Now you need to create a new Github secrets with the value copied before. The name of the secret is CERT_LINK.

Configure the Gateway of APIM

Next go to your API Management and custom domains

Create a new hostname for the API Gateway related to your private DNS zone and select the certificate you uploaded in the KeyVault.

Now retrieve the private IP of the Api Management

Go to your Azure Private DNS Zone and create a new A record entry

Configure the developer portal

Repeat the same step than before but this time is for the developer portal. Be sure to add the record in the Azure Private DNS Zone using the same private IP.

Do the same for the Management, at the end you should see something like this in your Domains for Azure API Management.

This will be what your Azure Private DNS Zone will look like at the end.

Publish Developer Portal

Login in to your jumpbox, from there go to the Azure Portal

Go to your APIM, and press the Developer Portal button.

From there, you will enter a designer, if an error occurs refresh the page.

In the designer you need to publish your website using the publish button.

Run the next Github Action

Now you are ready to run the next Github Action, go back to Github Action and select Deploy Application Gateway Infra and run the worflow.

Once the Github Action is executed go to your Application Gateway and in the menu Backend health. Be sure the Application Gateway can reach the APIM Gateway.

Configure in Azure Public DNS the IP of Application Gateway

Get the public ip of the App GW and add a record in your Azure Public DNS Zone.

Use the jumpbox to test the nslookup resolution like the example below.

Normally this should use the private IP

Now do a nslookup from your computer, this should use the public ip of the Application Gateway (it can take up to 24 hours to work depending of your DNS server).

Configure the Developer portal in the Azure Public DNS

Using again the public IP of the Application Gateway, you will do the same than the previous step but for the DNS name of the developer portal this time.

Now everything is setup.

Configure the Manegement plane in the Azure Public DNS

Using again the public IP of the Application Gateway, you will do the same than the previous step but for the DNS name of the management plane this time.

Create the VNET to VNET Gateway Connection

This sample create two resources group, each one with a VPN Gateway, you will need to create a connection between them to mock cloud to on premise environment.

For more details how to do this click here

Error during deploying KeyVault

If an error of Keyvault soft delete occurs when running the Github action this mean you have some keyvault pending because of the soft delete.

In this case you need to run those commands in the proper subscription using Azure CLI.

$ az keyvault list-deleted
$ az keyvault purge --name <name of the vault> 

Optional

Those steps are only required if you want to deploy the web application provided in this sample.

Deploy webapp provided

This Github contains 3 app used for the demo

The TodoWeb is the front end MVC app, the TodoApi is the one hosted in the cloud and Weather API is the one hosted in the Virtual Machine.

How to deploy those applications are out of this scope, but the next section will show you what you need to register in your Azure Active Directory to be able to run those sample apps.

Register in Azure Active Directory

You will need to create 3 applications registration in Azure AD, the flow used here is this one.

What is really important is the scope you create in TodoApi and WeatherApi.

For TodoApi you need to create one scope called Todo.Api.All and for WeatherApi the scope is Weather.Get.All.

Once you have those the two APIs created with the proper scope just give permission to those scope to TodoWeb.

Be sure next to create the Application Secret for the TodoWeb app.

For more details about using Azure Active Directory with .Net Application refer to the officiel Microsoft documentation.

Important

In the manifest file of all three application be sure to set the version of the property accessTokenAcceptedVersion to the value 2.

Configure appsettings for TodoApi

Here the appsettings of TodoApi that you need to configure in the WebApp in the Azure Portal.

[
  {
    "name": "AzureAd:ClientId",
    "value": "<ClientID of the TodoApi in Azure AD>",
    "slotSetting": false
  },
  {
    "name": "AzureAd:Instance",
    "value": "https://login.microsoftonline.com/",
    "slotSetting": false
  },
  {
    "name": "AzureAd:TenantId",
    "value": "<Your AzureAD Tenant ID>",
    "slotSetting": false
  },
  {
    "name": "ConnectionStrings:Sql",
    "value": "<Sql Connection string of the SQL Azure>",
    "slotSetting": false
  },
  {
    "name": "WEBSITE_NODE_DEFAULT_VERSION",
    "value": "6.9.1",
    "slotSetting": false
  }
]

Now you can publish the TodoWeb to Azure using Visual Studio or Azure CLI.

You can now configure the TodoApi in APIM with the policy you want to test.

Configure appsettings for WeatherApp

This application is different and hosted in the virtual machine called win1api. You will need to connect to this virtual machine with RDP and first install IIS from the server role.

Once is done you will need to install .Net Core 3.1 hosting bundle

You can find the Microsoft .Net core here

Now you can install your .Net Core application in ISS, once is done modify the appsettings.json with those parameters.

{
    "AzureAd": {
        "Instance": "https://login.microsoftonline.com/",
        "TenantId": "<TenantId of your Azure AD>",
        "ClientId": "<ClientId of Weather App in Azure AD>"
    }
}

You can now configure the Weather in APIM with the policy you want to test.

Configure appsettings for TodoWeb

Here the appsettings of TodoWeb that you need to configure in the WebApp in the Azure Portal.

[
  {
    "name": "AzureAd:CallbackPath",
    "value": "/signin-oidc",
    "slotSetting": false
  },
  {
    "name": "AzureAd:ClientId",
    "value": "<The ClientId of TodoWeb in AzureAD>",
    "slotSetting": false
  },
  {
    "name": "AzureAd:ClientSecret",
    "value": "<The ClientSecret of TodoWeb in AzureAD>",
    "slotSetting": false
  },
  {
    "name": "AzureAd:Instance",
    "value": "https://login.microsoftonline.com/",
    "slotSetting": false
  },
  {
    "name": "AzureAd:SignedOutCallbackPath",
    "value": "/signout-callback-oidc",
    "slotSetting": false
  },
  {
    "name": "AzureAd:TenantId",
    "value": "<Your Azure AD TenantId>",
    "slotSetting": false
  },
  {
    "name": "TodoList:ApiAccessKey",
    "value": "<Subscription Key of APIM to call TodoApi>",
    "slotSetting": false
  },
  {
    "name": "TodoList:TodoListAppId",
    "value": "<ClientId of TodoApi>",
    "slotSetting": false
  },
  {
    "name": "TodoList:TodoListBaseAddress",
    "value": "<BaseUrl Of TodoApi from APIM>",
    "slotSetting": false
  },
  {
    "name": "TodoList:TodoListScope",
    "value": "api://<ClientId of TodoApi>/Todo.Api.All",
    "slotSetting": false
  },
  {
    "name": "WeatherApp:ApiAccessKey",
    "value": "<Subscription Key of APIM to call Weather Api>",
    "slotSetting": false
  },
  {
    "name": "WeatherApp:WeatherAppId",
    "value": "<ClientId of WeatherApi>",
    "slotSetting": false
  },
  {
    "name": "WeatherApp:WeatherBaseAddress",
    "value": "<BaseUrl of WeatherApi From APIM>",
    "slotSetting": false
  },
  {
    "name": "WeatherApp:WeathertScope",
    "value": "api://<ClientId of WeatherApi>/Weather.Get.All",
    "slotSetting": false
  },
  {
    "name": "WEBSITE_NODE_DEFAULT_VERSION",
    "value": "6.9.1",
    "slotSetting": false
  }
]

Now you can publish the TodoWeb to Azure using Visual Studio or Azure CLI.