Expose applications with end-to-end TLS in a virtual network

Note

Azure Spring Apps is the new name for the Azure Spring Cloud service. Although the service has a new name, you'll see the old name in some places for a while as we work to update assets such as screenshots, videos, and diagrams.

This article applies to: ✔️ Basic/Standard ✔️ Enterprise

This article explains how to expose applications to the internet using Application Gateway. When an Azure Spring Apps service instance is deployed in your virtual network, applications on the service instance are only accessible in the private network. To make the applications accessible on the Internet, you need to integrate with Azure Application Gateway.

Prerequisites

Configure Application Gateway for Azure Spring Apps

We recommend that the domain name, as seen by the browser, is the same as the host name which Application Gateway uses to direct traffic to the Azure Spring Apps back end. This recommendation provides the best experience when using Application Gateway to expose applications hosted in Azure Spring Apps and residing in a virtual network. If the domain exposed by Application Gateway is different from the domain accepted by Azure Spring Apps, cookies and generated redirect URLs (for example) can be broken. For more information, see Host name preservation.

To configure Application Gateway in front of Azure Spring Apps, use the following steps.

  1. Follow the instructions in Deploy Azure Spring Apps in a virtual network.
  2. Follow the instructions in Access your application in a private network.
  3. Acquire a certificate for your domain of choice and store that in Key Vault. For more information, see Tutorial: Import a certificate in Azure Key Vault.
  4. Configure a custom domain and corresponding certificate from Key Vault on an app deployed onto Azure Spring Apps. For more information, see Tutorial: Map an existing custom domain to Azure Spring Apps.
  5. Deploy Application Gateway in a virtual network configured according to the following list:
    • Use Azure Spring Apps in the backend pool, referenced by the domain suffixed with private.azuremicroservices.io.
    • Include an HTTPS listener using the same certificate from Key Vault.
    • Configure the virtual network with HTTP settings that use the custom domain name configured on Azure Spring Apps instead of the domain suffixed with private.azuremicroservices.io.
  6. Configure your public DNS to point to Application Gateway.

Define variables

Next, use the following commands to define variables for the resource group and virtual network you created as directed in Deploy Azure Spring Apps in a virtual network. Customize the values based on your real environment. When you define SPRING_APP_PRIVATE_FQDN, remove https:// from the URI.

export SUBSCRIPTION='subscription-id'
export RESOURCE_GROUP='my-resource-group'
export LOCATION='eastus'
export SPRING_CLOUD_NAME='name-of-spring-cloud-instance'
export APPNAME='name-of-app-in-azure-spring-apps'
export SPRING_APP_PRIVATE_FQDN='$APPNAME.private.azuremicroservices.io'
export VIRTUAL_NETWORK_NAME='azure-spring-apps-vnet'
export APPLICATION_GATEWAY_SUBNET_NAME='app-gw-subnet'
export APPLICATION_GATEWAY_SUBNET_CIDR='10.1.2.0/24'

Sign in to Azure

Use the following command to sign in to the Azure CLI and choose your active subscription.

az login
az account set --subscription $SUBSCRIPTION

Acquire a certificate

For production deployments, you'll most likely use a publicly signed certificate. In this case, import the certificate in Azure Key Vault. For more information, see Tutorial: Import a certificate in Azure Key Vault. Make sure the certificate includes the entire certificate chain.

Configure the public domain name on Azure Spring Apps

Traffic will enter the application deployed on Azure Spring Apps using the public domain name. To configure your application to listen to this host name and do so over HTTPS, use the following commands to add a custom domain to your app:

export KV_NAME='name-of-key-vault'
export KV_RG='resource-group-name-of-key-vault'
export CERT_NAME_IN_AZURE_SPRING_APPS='name-of-certificate-in-Azure-Spring-Apps'
export CERT_NAME_IN_KEY_VAULT='name-of-certificate-with-intermediaries-in-key-vault'
export DOMAIN_NAME=myapp.mydomain.com

# provide permissions to Azure Spring Apps to read the certificate from Key Vault:
export VAULTURI=$(az keyvault show \
    --resource-group $KV_RG \
    --name $KV_NAME \
    --query properties.vaultUri \
    --output tsv)

# get the object id for the Azure Spring Apps Domain-Management Service Principal:
export ASADM_OID=$(az ad sp show \
    --id 03b39d0f-4213-4864-a245-b1476ec03169 \
    --query objectId \
    --output tsv)

# allow this Service Principal to read and list certificates and secrets from Key Vault:
az keyvault set-policy \
    --resource-group $KV_RG \
    --name $KV_NAME \
    --object-id $ASADM_OID \
    --certificate-permissions get list \
    --secret-permissions get list

# add custom domain name and configure TLS using the certificate:
az spring certificate add \
    --resource-group $RESOURCE_GROUP \
    --service $SPRING_CLOUD_NAME \
    --name $CERT_NAME_IN_AZURE_SPRING_APPS \
    --vault-certificate-name $CERT_NAME_IN_KEY_VAULT \
    --vault-uri $VAULTURI
az spring app custom-domain bind \
    --resource-group $RESOURCE_GROUP \
    --service $SPRING_CLOUD_NAME \
    --domain-name $DOMAIN_NAME \
    --certificate $CERT_NAME_IN_AZURE_SPRING_APPS \
    --app $APPNAME

Create network resources

The Azure Application Gateway to be created will join the same virtual network as--or peered virtual network to--the Azure Spring Apps service instance. First create a new subnet for the Application Gateway in the virtual network using az network vnet subnet create, and also create a Public IP address as the Frontend of the Application Gateway using az network public-ip create.

export APPLICATION_GATEWAY_PUBLIC_IP_NAME='app-gw-public-ip'
az network vnet subnet create \
    --name $APPLICATION_GATEWAY_SUBNET_NAME \
    --resource-group $RESOURCE_GROUP \
    --vnet-name $VIRTUAL_NETWORK_NAME \
    --address-prefix $APPLICATION_GATEWAY_SUBNET_CIDR
az network public-ip create \
    --resource-group $RESOURCE_GROUP \
    --location $LOCATION \
    --name $APPLICATION_GATEWAY_PUBLIC_IP_NAME \
    --allocation-method Static \
    --sku Standard

Create a managed identity for Application Gateway

Application Gateway will need to be able to access Key Vault to read the certificate. To do so, it will use a user-assigned managed identity. Create the managed identity by using the following command:

export APPGW_IDENTITY_NAME='name-for-appgw-managed-identity'
az identity create \
    --resource-group $RESOURCE_GROUP \
    --name $APPGW_IDENTITY_NAME

Then fetch the objectId for the managed identity as it will be used later on to give rights to access the certificate in Key Vault:

export APPGW_IDENTITY_CLIENTID=$(az identity show \
    --resource-group $RESOURCE_GROUP \
    --name $APPGW_IDENTITY_NAME \
    --query clientId \
    --output tsv)
export APPGW_IDENTITY_OID=$(az ad sp show \
    --id $APPGW_IDENTITY_CLIENTID \
    --query objectId \
    --output tsv)

Set policy on Key Vault

Configure Key Vault using the following command so that the managed identity for Application Gateway is allowed to access the certificate stored in Key Vault:

az keyvault set-policy \
    --name $KV_NAME \
    --resource-group $KV_RG \
    --object-id $APPGW_IDENTITY_OID \
    --secret-permissions get list \
    --certificate-permissions get list

Create Application Gateway

Create an application gateway using az network application-gateway create and specify your application's private fully qualified domain name (FQDN) as servers in the backend pool. Make sure to use the user-assigned managed identity and to point to the certificate in Key Vault using the certificate's Secret ID. Then update the HTTP setting using az network application-gateway http-settings update to use the public host name.

export APPGW_NAME='name-for-application-gateway'

export KEYVAULT_SECRET_ID_FOR_CERT=$(az keyvault certificate show \
    --name $CERT_NAME_IN_KEY_VAULT \
    --vault-name $KV_NAME \
    --query sid \
    --output tsv)

az network application-gateway create \
    --name $APPGW_NAME \
    --resource-group $RESOURCE_GROUP \
    --location $LOCATION \
    --capacity 2 \
    --sku Standard_v2 \
    --frontend-port 443 \
    --http-settings-cookie-based-affinity Disabled \
    --http-settings-port 443 \
    --http-settings-protocol Https \
    --public-ip-address $APPLICATION_GATEWAY_PUBLIC_IP_NAME \
    --vnet-name $VIRTUAL_NETWORK_NAME \
    --subnet $APPLICATION_GATEWAY_SUBNET_NAME \
    --servers $SPRING_APP_PRIVATE_FQDN \
    --key-vault-secret-id $KEYVAULT_SECRET_ID_FOR_CERT \
    --identity $APPGW_IDENTITY_NAME

It can take up to 30 minutes for Azure to create the application gateway.

Update HTTP Settings to use the domain name towards the backend

Update the HTTP settings to use the public domain name as the hostname instead of the domain suffixed with ".private.azuremicroservices.io" to send traffic to Azure Spring Apps with.

az network application-gateway http-settings update \
    --resource-group $RESOURCE_GROUP \
    --gateway-name $APPGW_NAME \
    --host-name-from-backend-pool false \
    --host-name $DOMAIN_NAME \
    --name appGatewayBackendHttpSettings

Check the deployment of Application Gateway

After it's created, check the backend health by using the following command. The output of this command enables you to determine whether the application gateway reaches your application through its private FQDN.

az network application-gateway show-backend-health \
    --name $APPGW_NAME \
    --resource-group $RESOURCE_GROUP

The output indicates the healthy status of backend pool, as shown in the following example:

{
  "backendAddressPools": [
    {
      "backendHttpSettingsCollection": [
        {
          "servers": [
            {
              "address": "my-azure-spring-apps-hello-vnet.private.azuremicroservices.io",
              "health": "Healthy",
              "healthProbeLog": "Success. Received 200 status code",
              "ipConfiguration": null
            }
          ]
        }
      ]
    }
  ]
}

Configure DNS and access the application

Now configure the public DNS to point to Application Gateway using a CNAME or A-record. You can find the public address for Application Gateway by using the following command:

az network public-ip show \
    --resource-group $RESOURCE_GROUP \
    --name $APPLICATION_GATEWAY_PUBLIC_IP_NAME \
    --query [ipAddress] \
    --output tsv

You can now access the application using the public domain name.

Next steps