Using App Service Environment as a Private Reverse Proxy with User Authentication


Azure App Service Environment (ASE) has been available in Azure Commercial for a while and is now available in Azure Government as well. As discussed previously, ASE offers some very specific advantages for Government web applications or more generally for web applications that require network isolation and careful control of traffic routing. In this blog post, I will discuss another use for the ASE. Specifically, I will show how to use an ASE to create a private reverse proxy with user authentication.

It is common for organizations to access services and data sources through APIs published within their networks. As applications move to the cloud, they may want to provide access to these APIs from cloud applications through a reverse proxy, but they may want to have some kind of access control, i.e., user authentication. Azure API Management is one way to do this, but virtual network integration requires the premium version of API Management, and it may be not be the right fit for all applications. Azure Application Gateway can provide the reverse proxy capabilities, but it does not allow user authentication. Another alternative would be to set up a virtual machine running something like HA Proxy, but that introduces IaaS VMs with associated operations and management overhead. If the organization is already using ASE or they are willing to introduce an ASE into their cloud deployment, it can be configured to provide a reverse proxy with user authentication for an API (or other HTTP based service). The configuration would look something like this:

In this example, there are two legacy API services on-premises. A virtual network in Azure is connected to the on-premises network (Express Route or VPN) and an ASE is deployed in the VNET in Azure. A Web App in the ASE is configured to be a reverse proxy and it is configured with Azure Active Directory Authentication (Easy Auth). The on-premises firewall rules are configured such that the on-premises services can only be reached from Azure through the ASE. When workloads in Azure need to access the on-premises services, they access it through a URL on the ASE. After authentication, the URL is rewritten to access the on-premises service.

In the following, I will walk through how to configure this. First step is to set up an ASE with a Web App. I have previously described how to do that. You can find a template on GitHub for deploying an ASE or use this other template if you would like an ASE with a jump box and a VSTS build agent. Once the ASE is deployed, you need to set up Azure Active Directory (AAD) authentication. I have described how to do this in this blog post, and I have some convenience PowerShell scripts in my HansenAzurePS module. You can set up the AAD authentication by first installing the PowerShell Module:

Install-Module HansenAzurePS

Then create an App Registration in AAD. Here is how to create the app registration in Azure Commercial:

$appreg = New-AppRegForAADAuth -Environment AzureCloud `
-SiteUri https://ase-site.contoso-internal.us

Finally configure the Web App in the ASE with easy auth:

Set-WebAppAADAuth -ResourceGroupName RGNAME `
-WebAppName ase-site -ClientId $appreg.ClientId `
-ClientSecret $appreg.ClientSecret `
-IssuerUrl $appreg.IssuerUrl -Environment AzureUsGovernment

In this example we are using an Azure Commercial AAD tenant to authenticate a Web App in Azure Government. This is a common scenario for Organizations with Office 365 in GCC and web applications in Azure Government. At this point, it is probably a good idea to check that your ASE is up and running, you can hit the Web App from a machine in virtual network (e.g., a jumbox) and that you will be asked to authenticate.

Next step is to configure the Web App to be a reverse proxy. This is something I have discussed in the context of mitigating HSTS compliance problems for legacy apps. There are two steps involved. First we need to make sure the ARR features of the Web App are enabled by installing a applicationHost.xdt in the D:\home\site folder of the Web App. This can be done using the Kudu interface. The file should contain the following:

<?xml version="1.0"?>  
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">  
    <system.webServer>  
        <proxy xdt:Transform="InsertIfMissing" enabled="true" preserveHostHeader="false" reverseRewriteHostInResponseHeaders="false" />  
    </system.webServer>  
</configuration>  
 

And the final step is to add a web.config file to the wwwroot folder. Here is an example of rewriting the urls for /msdn/ and /technet/ to point to those two blog sites:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="Proxy1" stopProcessing="true">  
                    <match url="^msdn/(.*)" />  
                    <action type="Rewrite" url="https://blogs.msdn.microsoft.com/{R:1}" />  
                </rule>
                <rule name="Proxy2" stopProcessing="true">  
                    <match url="^technet/(.*)" />  
                    <action type="Rewrite" url="https://blogs.technet.microsoft.com/{R:1}" />  
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

After this, restart the Web App to make sure all the changes are picked up and then try to hit one of the URLs. You should first be prompted to log in and after that reach the backend sites:

After logging in:

Notice how we are reaching the MSDN blog site through the ASE reverse proxy.

And that is it, you now private reverse proxy with user authentication. In a real-world scenario, there would be no need to access a public web site like this, but for internal APIs or other services that require a reverse proxy and user authentication this approach can be an alternative to Azure API management or proxy VMs, especially if ASEs are already deployed in the organizations Azure environment.

Let me know if you have questions/comments/suggestions.

Comments (0)

Skip to main content