How to run an App Service behind a WAF-enabled Application Gateway

Introduction

You may have heard of the Azure Application Gateway which is a Layer-7 HTTP load balancer that provides application-level routing and load balancing services that let you build a scalable and highly-available web front end in Azure. It works by accepting traffic and based on rules that are defined with it, routes the traffic to the appropriate back-end instances.

It has pretty neat features too like:

  • Web Application Firewall (WAF)
  • HTTP load balancing
  • Cookie-based session affinity
  • SSL offloading and End-to-end SSL
  • URL-based content routing
  • Multi-site routing
  • Websocket support
  • Health monitoring

For more details about what Application Gateway can do, have a look at the Introduction to Application Gateway article on the Azure documentation website.

Architecture overview

What I'm trying to achieve here is hosting a website in an App Service Environment and protect it with the Web Application Firewall that is provided by the Application Gateway. Ultimately, this should look like the diagram below:

Let's go

Create your Virtual Network

The virtual network with at least 1 subnet. That subnet would be used by the Application Gateway. In the next step, the App Service Environment subnet will be create as part of the provisioning process.

Create an App Service Environment

When you are creating the App Service Environment, make sure you create it in the same Virtual Network. Choose the VIP type to be Internal, select a subdomain and create the required subnet for the App Service Environment. This step may take up to 2 hours to complete. Be patient.

Create an App Service Plan and Web App

In the App Service Environment, create an App Service Plan and create a new Web App with the hostname of yoursite.internal.sabbour.me. You may also add a custom domain now that will be externally resolved, in my case I went with protected.sabbour.me.

Create a "jump-box" and a DNS server

Remember that this Web App is living within a VNET that isn't publicly accessible, so in order to be able to deploy stuff, access Kudu console and so on, you need to create a Virtual Machine that is living within the same Virtual Network and use that to access the Web App with its internal IP. While you're at it, you may configure this machine with a DNS role to be able to resolve the Web App specific domains (and other hostnames within your Virtual Network).
You need to create A-records pointing to the App Service Environment's Internal Load Balancer IP address for the following hostnames (*, *.scm, ftp, publish).

Set the Virtual Network to use this newly created DNS server.

Create the Application Gateway

Now it is time to create the Application Gateway and select whether you want it WAF enabled or not.

In the settings, make sure to select the same Virtual Network you configured earlier and the subnet you created specifically for the Application Gateway. While you're at it, also configure the public IP address.

Review the results and create the gateway.

Configure the Application Gateway

After the gateway is ready, go to the Backend Pools and create a new pool with the App Service Environment Internal Load Balancer IP.

Create a Custom Probe with the Host set as your custom Web App domain, for example protected.sabbour.me.

Go to the HTTP settings, and make sure that the setting has Custom Probes turned on and select the probe you just created. Otherwise, the Application Gateway will try to go to the IP of the App Service Environment without passing a Host header, which won't work and will throw the probe into an Unhealthy state resulting in the 502 Gateway Proxy error.

Test!

By this point, you should be able to use something like ModHeader Chrome extension to open the public IP address/hostname of the Application Gateway in the browser, pass in the Custom Domain you configured on the Web App as a Host Header and the website should come up.

Setup the CNAME

To connect to the custom hostname you setup protected.sabbour.me, all what you need to do now is to configure a CNAME on your domain pointing protected to the hostname of the Application Gateway.

Test - take 2

Go to http://protected.sabbour.me and it should now open up without any Host Header trickery.

Summary

To summarize, we've setup a Web App in an App Service Environment. This Web App isn't publicly accessible as it is sitting in a subnet inside a Virtual Network and it isn't exposed to the internet. The only way to access the site is through a Web Application Firewall enabled Application Gateway.

And all of it is done in Platform as a Service (well, other than the jump-box server at least!).