Limit access to your Azure Web App from your Azure Front Door only

Azure Front Door team just GA’d March 2020 updates which include easier lockdown for backends. Now instead of using multiple values for X-Forwarded-Host header for filtering traffic to your backends, you can use the Front Door ID field for a new header X-Azure-FDID to lockdown your backends for both production traffic as well as health probes.

Background

I’m working on a project in which we are using Azure Front Door to serve our application faster and more secure by having the Web Application Firewall intercepting incoming requests. Here is the architecture for a reference:

Hilma architecture

By default you can access resources behind the Front Door if you know (or guess) the correct endpoints such as xx-yy-production.azurewebsites.net. There is still very little documentation of how you can handle the issue so I decided to post a step-by-step walkthrough how you can lock down access to your Web App from your Front Door instance only.

IP restrictions

Configure IP ACLing for your backends to accept traffic from Azure Front Door’s backend IP address space and Azure’s infrastructure services only. Refer the IP details below for ACLing your backend:

  • Refer AzureFrontDoor.Backend section in Azure IP Ranges and Service Tags for Front Door’s IPv4 backend IP address range or you can also use the service tag AzureFrontDoor.Backend in your network security groups or with Azure Firewall.
  • Front Door’s IPv6 backend IP space while covered in the service tag, is not listed in the Azure IP ranges JSON file. If you are looking for explicit IPv6 address range, it is currently limited to 2a01:111:2050::/44
  • Azure’s basic infrastructure services through virtualized host IP addresses: 168.63.129.16 and 169.254.169.254

You Web App network restrictions should look something like this now:

Web App network restrictions Front Door

Now this of course doesn’t cut it yet. One can still create their own Azure Front Door instance and could still bypass your own Front Door. That’s why you have to make sure requests are coming from a specific Front Door.

Use .NET Core Middleware to constrain X-Azure-FDID header value

XAzureFDIDMiddleware.cs

First we need to create the middleware itself. All it has to do is to grab the X-Azure-FDID header value and compare it against a value in our appsettings (AzureFrontDoorId in my case) and if it’s not a match, short-circuit the rest of the pipeline.

using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;

namespace Hilma.Web.Middleware
{
    public class XAzureFDIDMiddleware
    {
        private readonly RequestDelegate _next;

        public XAzureFDIDMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task InvokeAsync(HttpContext context, IHostingEnvironment environment, IConfiguration configuration)
        {            
            var fdidHeaderValue = context.Request.Headers["X-Azure-FDID"].ToString();

            if (fdidHeaderValue != configuration["AzureFrontDoorId"])
            {
                await context.Response.WriteAsync("Blocked");
            }
            else
            {
                await _next(context);
            }
        }
    }
}

XAzureFDIDMiddlewareExtensions.cs

Create an extension to have your middleware available in Startup.Configure:

using Microsoft.AspNetCore.Builder;

namespace Hilma.Web.Middleware
{
    public static class XAzureFDIDMiddlewareExtensions
    {
        public static IApplicationBuilder UseXAzureFDID(
            this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<XAzureFDIDMiddleware>();
        }
    }
}

Startup.cs

Use the middleware by injecting it to the pipeline in Startup.Configure:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseXAzureFDID();
    }
    // ... (the rest of your pipeline)
}

GET your Front Door ID and put it in your app configuration

You can fetch the frontdoorId from Front Door’s management API. The easiest way to do this is going to https://docs.microsoft.com/en-us/rest/api/frontdoorservice/frontdoor/frontdoors/get and click “Try it”. Note that you have to use API version 2020-01-01 or newer for this.

It will ask you to log in and fill in information about your subscription, resource group and front door resource name. At the bottom of the response you can find the frontdoorId (GUID) that you can put in your App Configuration.

frontdoorId

Put the value in your App Configuration and you are done. Happy Front Dooring!

 

Limit access to your ASP.NET Core app by IP address with middleware

Update 12 Sep 2017: You can add IP restrictions to your Web App from Azure Portal now. https://docs.microsoft.com/en-us/azure/app-service/app-service-ip-restrictions

I’m working on a mini-project that should be seen only from inside our company network. This is my first ASP.NET Core project and I’m still kind of lost with the configuration part and there aren’t many examples in stackoverflow how to do this or that with ASP.NET Core. However I managed to do IP restrictions for my ASP.NET Core app running on Azure and here is how I did it. Read more…

 

How to secure your ASP.NET Azure Web App

One of the ASP.NET Azure Web applications I’ve been working with is going to be security audited tomorrow and I was “only checking” that everything is OK in my app security-wise. I figured that I should write down a cheat sheet for the future to make sure I have all the configurations needed in place in other apps as well.
Read more…

 

Tips for Microsoft Build attendees

We had quite many ahaa-moments during our trip to Build 2016 in San Francisco and I wish we had figured out certain things beforehand. That gave me an idea to write about tips and lessons learned for people who are attending Microsoft Build or similar events in the future.
Read more…

 

Output .NET MVC bundle content as a string with Razor

Sometimes you might run into situations when you need to output the contents of your style or script bundle as a raw string inline. For example if you need to pass your markup and stylesheets to somewhere else without having any external resources in it, this would be a handy solution.
Read more…

 

Running Jasmine unit tests in your Visual Studio Online build

I couldn’t find thorough enough tutorial of running Jasmine tests in Visual Studio Online build as part of my continuous integration workflow. I struggled for hours to get this work and decided to write a step-by-step guide about how to make it work. Read more…

 

Apply IP restrictions for Azure Cloud Service

Since Azure SDK 2.4 there’s been a possibility to configure IP restrictions for Azure Cloud Services with Access Control List (ACL).

Just add the following to your ServiceConfiguration.Cloud.cscfg. Read more…

 

Hide your .NET MVC site from search engines (robots.txt)

Short story short. Add routes.IgnoreRoute("robots.txt"); to your RouteConfig.cs and add a file called robots.txt to your project root folder.
Read more…

 

AngularJS SPA and .NET MVC routing

How hard can it be to do .NET MVC routing properly along with your AngularJS single page app? -Not very hard. Here is how you can do it:

MVC routing in RouteConfig.cs

Most of the guides you find tells you how to handle the routing if you wan’t to have your SPA routes with an app/ or angular/ prefix. For the sake of having as simple URLs as possible and Search Engine Optimization (SEO) you should avoid redundant stuff in URLs.
So what you want to do is to define the MVC Default route first to catch requests for your MVC controllers. In case the request doesn’t match any of your controllers, you should have a “fallback” CatchAllRoute that will hit your AngularController or whatever you have. Read more…

 

Validate Anti-Forgery Token using AngularJS, TypeScript, ASP.NET MVC and Web API

I’ve used Olav Nybø’s guide as a base for this article.
Read more…