Privatize App Service with VNET integration and private endpoint - Glennverdale/cote-d-Azure GitHub Wiki

Azure App Service privatization

Privatize: to make private
Especially, to change from public to private control or ownership

This page will outline the services and features Azure offers for making an app service privately accessible only. The outline focusses on a templated approach using Azure resource manager (ARM) Templates for deploying a new (private) App Service or converting an existing (public) app service.

Resources

🔗 Template: App service with VNET integration and private endpoint

🔗 Template: App service plan

1. Why privatization?

View this section

Privatization is done to increase overall security of the solution the App Service is hosting. It decreases or removes network traffic bound to the app service from traversing the public Internet. This is especially desired when the app service is hosting an application that only needs to be accessed from a private network only.

While there are ways of securing the public endpoint of an app service by means of access restriction rules; if there is no need for public (inbound) access, you are better off to close down the public endpoint entirely.

2. Azure services and features involved

Azure has a several services and features to privatize app service network traffic. We will focus on VNET integration and private endpoints services (using private link services).

2.1. Regional VNET integration

A brief look into VNET integration, how its works and what requirements it has.

View this section

What is regional VNET integration?

The App Service VNET integration feature enables your apps to access resources in or through a virtual network. Virtual network integration doesn't enable your app to be accessed privately. ...Regional virtual network integration supports connecting to a virtual network in the same region and doesn't require a gateway.[1]

As above quote states, implementing the VNET integration feature on your app service only enables your app to communicate with resources in or through a virtual network. "Through a virtual network" basically means that the app service traffic coming into the virtual network can be forwarded to any other network as long as access control lists (ACL) and routing permits it. The Microsoft documentstion lists a great del of possible scenarios.

When enabling VNET integration you can control network traffic coming from your app through Azure route tables and network security groups (NSG).

  • NSG is used to control network access via outbound security rules
  • Azure route tables are used to reroute traffic to any other network connected to the virtual network the app service is integrating with, connection could be done by means of virtual network peering, virtual network gateways or Network Virtual Appliances (NVA).
  • App service will use same DNS set on VNET level by default

NVAs (e.g. firewall appliances) can do both access control and routing, they are commonly placed in a hub virtual network. Azure route tables are then used to route traffic from spokes towards the NVA.

In short; VNET integration allows traffic from your app service to reach resources in your virtual network, one way only. session can only be initiated by the app service.

Below diagram indicates the traffic flow direction VNET integration supports (blue line marked by 1).

image

What requirements does regional VNET integration have?

There are some requirements when implementing regional VNET integration;

  • App service plan of tier Standard or higher
  • App service and virtual network need to reside in the same Azure region.
  • A dedicated integration subnet is needed within the virtual network with minimum CIDR of /27
    • Use larger ranges when doing multiple integrations on the same subnet.
  • The integration subnet is delegated to Microsoft.Web/serverFarms
    • No resources other than app service plans can make use of the subnet.
  • Subnet has route tables and access control (NSG/NVA) set so that it can succesfully reach resources within the virtual network.
    • Consult a network engineer.

VNET route all

VNET integration comes with a property called VNET route all that can be enabled or disabled.

  • With VNET route all disabled, the app service will only route RFC1918 addresses towards the virtual network and automatically route public adresses to the Internet. In most cases, this is the wanted scenario.
  • With VNET route all enabled the app service will simply route all traffic towards the virtual network. This behaviour is wanted if you also want to control public traffic via route tables and NSGs. You can have the traffic rerouted via an NVA to inspect it.

❕ You'll also want to enable VNET route all if the private network is not using RFC1918 addresses. In this case you'll need to have "public" traffic routed towards your virtual network instead of having it automatically route to the Internet.

2.2. Private endpoint for app services

A brief look into private endpoints, how they work and what requirements they have.

View this section

What is private endpoint?

You can use Private Endpoint for your Azure App service to allow clients located in your private network to securely access the app over Private Link. The Private Endpoint uses an IP address from your Azure VNET address space. Network traffic between a client on your private network and the Web App traverses over the VNET and a Private Link on the Microsoft backbone network, eliminating exposure from the public Internet.[2]

In short; a network interface (NIC) is created in a subnet you define with a dynamic IP address (first available IP is taken!). After succesfull creation, the NIC is linked to your app service using the Private Link service. Private Link provides private connectivity from your virtual network to Azure PaaS services. You can reach the private endpoint from any network as long as access control and routing allows it. Private endpoints allow traffic from resources in and behind the virtual network to reach the app service privately, one way. Session can only be initiated from resources inside or behind the virtual network. This is the exact opposite as VNET integration provides.

Below diagram indicates the traffic flow direction private endpoints supports (green line marked by 2).

image

What requirements does a private endpoint have?

There are some requirements when implementing private endpoints;

  • App service plan of tier Premium or higher
    • An App service environment is private by default, this doesn't need private endpoints, App service plans do.
  • Ready the DNS infrastructure to resolve the correct privatelink forward lookup zone.
    • For app services this is privatelink.azurewebsites.net and scm.privatelink.azurewebsites.net
  • Private endpoint NIC needs a dynamic IP address
    • The private endpoint is deployed to a subnet, the first available IP in teh subnet range will be taken
    • When deploying via ARM, if you designed the IPs to be used in a certain order, deploy the resources in the same order (you might even want to use the DependsOn property in ARM.
  • Subnet where the private endpoint resides has the network poliy for private endpoints disabled[3]
  • Network has routes and access control that allows the correct clients or resources to reach the private endpoint IP.

Private endpoints and DNS

As said earlier, private endpoints heavily rely on (Azure) DNS. The moment you enable a private endpoint on a supporting Azure service, Azure DNS will do some changes in the background. Lets take the example of private endpoints for App Services;

  1. A default app service is available on myAwsomeApp.azurewebsites.net
  2. Azure hosts the authoritive DNS servers for the public zone azurewebsites.net, it holds an A-record for your app service;
Record name Type address
myAwsomeApp A 80.5.9.8
  1. When a private endpoint is created Azure DNS changes the A-record to a CNAME-record in the azurewebsites.net* zone that will point to a new zone privatelink.azurewebsites.net;
Record name Type address
myAwsomeApp.azurewebsites.net CNAME myAwsomeApp.privatelink.azurewebsites.net
myAwsomeApp.privatelink.azurewebsites.net A 80.5.9.8
  1. The CNAME record will trigger a second lookup to myAwsomeApp.privatelink.azurewebsites.net, you can create this zone in your own private DNS (e.g. via Azure private DNS zones or Active Directory DNS) and set the same A-record for myAwsomeApp.privatelink.azurewebsites.net to the private endpoint IP in your network.
Record name Type address
myAwsomeApp.privatelink.azurewebsites.net A 192.168.10.5
  1. The second lookup to myAwsomeApp.privatelink.azurewebsites.net will now be resolved by your own DNS with your own IP adresses.
  2. If you don't have the zone in your private DNS the second lookup to AwsomeApp.privatelink.azurewebsites.net will be resolved by Azure DNS and return you the public endpoint IP of the app service;
Record name Type address
myAwsomeApp.azurewebsites.net CNAME myAwsomeApp.privatelink.azurewebsites.net
myAwsomeApp.privatelink.azurewebsites.net A 80.5.9.8

❕ The DNS lookup will return a public IP address and you will not be routed to your private endpoint. You will not be routed privately but publicly (this might be unintentionally or not knowingly)!

❕ When you are routed publicly and your app service public endpoint is disabled, you will get a 404 error. This can be an indicator of the DNS issue. It also brings forward the best practice of dosabling the app service public endpoint when configuring it with a private endpoint.

DNS zones to create when deploying private endpoint for app services

Below forward lookup zones need to be created (to catch teh CNAME lookup) when deploying a private endpoint on an app service;

zone purpose
privatelink.azurewebsites.net Access your app service privately
scm.privatelink.azurewebsites.net Access the Kudu console privately as it will be closed-off

3. ARM deployment of an app service

This section will outline how to deploy an app service via ARM.

3.1. Deploy app service plan

First, you'll want to deploy an app service plan (ASP)

View this section

Deploying an app service plan is pretty straight forward, it serves as the hardware on which you'll host app services. Depending on the App service plan tier, you will be able to use VNET integration (starting from standard) and private endpoints (starting from premium).

Deploying an app service plan

3.2. Deploy app service

Next, you'll want to deploy your app service with VNET integration and private endpoint

View this section

Property to define app service plan

View code

            "properties": {
                "serverFarmId": "[concat('/subscriptions/', subscription().subscriptionId,'/resourcegroups/', resourceGroup().name, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]"
            }
        

Property to define VNET integration

View code

            "properties": {
               "virtualNetworkSubnetId": "[resourceId(parameters('vnetResourceGroupName'),'Microsoft.Network/virtualNetworks/subnets', parameters('vnetName'), parameters('vnetIntegrationSubnetName'))]"
            }
        

Resource to define private endpoint

View code

{
            "type": "Microsoft.Network/privateEndpoints",
            "apiVersion": "2019-04-01",
            "name": "[parameters('peName')]",
            "location": "[parameters('location')]",
            "dependsOn": [
                "[resourceId('Microsoft.Web/sites', parameters('appName'))]"
            ],
            "properties": {
                "subnet": {
                    "id": "[resourceId(parameters('vnetResourceGroupName'),'Microsoft.Network/virtualNetworks/subnets', parameters('vnetname'), parameters('peSubnetName'))]"
                },
                "privateLinkServiceConnections": [
                    {
                        "name": "[parameters('privLinkServiceName')]",
                        "properties": {
                            "privateLinkServiceId": "[resourceId('Microsoft.Web/sites', parameters('appName'))]",
                            "groupIds": [
                                "sites"
                            ]
                        }
                    }
                ]
            } 
        }
        

Deploying an app service

3.3 App service "appSettings"

❕ Re-deploying an app service with no app settings defined in your ARM will remove all app settings from the app service (e.g. if your app settings were set via the portal or PowerShell).

Even with an incremental deploy, Azure only knows how to increment on a resource level, not so much on a configuration level. As a work-around, you'll simply include all app settings in json format as a parameter array.

View this section

Property to set app settings

Below code snippit is defined in your appservice.json

View code

"properties": {
                "siteConfig": {
                    "appSettings": "[parameters('appProperties')]",
                }

Parameter to create app settings array

Below code snippit is defined in your appservice.json

View code

        "appProperties": { 
            "type": "Array",
            "metadata": {
                "description": "Application settings."
            }
        }

Parameter example for populating the array of app settings

Below code snippit is defined in your appservice.parameters.json

View code

"appProperties": { 
            "value": [
                {
                  "name": "AppSettings:Logging:LogLevel",
                  "value": "Information",
                  "slotSetting": false
                },                
                {
                  "name": "WEBSITE_RUN_FROM_PACKAGE",
                  "value": "0",
                  "slotSetting": false
                }
               ]
              }

Footnotes

  1. 🔗 https://docs.microsoft.com/en-us/azure/app-service/overview-vnet-integration
  2. 🔗 https://docs.microsoft.com/en-us/azure/app-service/networking/private-endpoint
  3. 🔗 https://docs.microsoft.com/en-us/azure/private-link/disable-private-endpoint-network-policy
⚠️ **GitHub.com Fallback** ⚠️