CloudFront Edge to Origin Auth

CloudFront, the CDN from Amazon Web Services, has long supported authenticating between the CDN’s edge and S3 using Origin Access Identity, allowing you to lock down your origin and ensure users can only access your content through CloudFront.

A more difficult problem is restricting access on a custom origin – ensuring that the only people who can talk to your back-end webservers are actually coming from CloudFront. This has traditionally “worked around” by adding the CloudFront IP ranges to a security group or FW in-front of your application. The issue with this approach is two fold:

  • Anyone can create a CloudFront distribution pointing at your origin to bypass this
  • You have to handle synchronisation of the IP JSON against your security groups / FW

As of December 2015, CloudFront now supports setting custom headers from edge to origin. This allows us to use a common pattern for handling authentication of the CDN edges – Pre Shared Keys, inserted into a header, validated by the origin webserver. These same steps can apply to many CDNs, but in this post we’ll cover the configuration of CloudFront and the origins. This also nicely coincides with Amazon’s release of Amazon Certificate Manager, which allows you free SSL certs for use with Amazon CloudFront or the Elastic Load Balancer.

Implementation

There are two parts to this – firstly we’ll configure CloudFront, and verify that the header is being set as expected. Afterwards, we’ll configure the origin to validate that Header and block unauthorised users.

CloudFront Configuration

Within a given CloudFront distribution, we have one or more origins. “Origin Custom Headers” are configured on a per-origin basis, and are of Header:Value pairs. In our case, we only need to add “X-PSK-Auth” and a value. All we need to do to have CloudFront send this to our origin is to edit your origin settings, and add this:

psk-auth

Once your CloudFront distribution has moved from InProgress to deployed, we can test this.

Testing the Configuration

In order to make sure we’re getting the correct header set, we can look on the origin at the headers that are being set. For this, I’ve used a simple PHP script which prints all of our headers:

and now I can see that my header is being set properly:

psk-origin

Controlling Access at the Origin

Actually controlling the access depends greatly on your origin webserver. I’ve provided a few sample references on this cdn-auth GitHub repo (pull requests welcome). Most of these have support for both an ‘old’ and ‘new’ key to allow rotation. This is pretty important when working with a third party CDN – as once you’ve hit ‘save’ on a configuration, you don’t have a guarantee of when that’ll be applied.

AWS WAF (ALB)

If we’re using Amazon Web Services for our origin – we can use the AWS WAF attached to an Application Load Balancer to support the filtering of traffic before it ever hits our own instances.

Put simply, we create a WebACL with a String Match Condition filter on the X-PSK-Auth header. We match for the string we choose as our PSK – and we then attached that to our ALB as a WAF policy.

Without the auth header, the traffic is filtered before ever hitting our origin — at the AWS ELB.


$ curl -vo/dev/null http://alb/

> GET / HTTP/1.1
> Host: alb
> User-Agent: curl/7.51.0

HTTP/1.1 403 Forbidden
Server: awselb/2.0

[...]

With the auth header, the traffic reaches our origin and our request is fulfilled by nginx


$ curl -vo/dev/null -H "X-PSK-Auth: e6e59c8c1dcca46fde36bf43b84487d8" http://alb/

> GET / HTTP/1.1
> Host: alb
> User-Agent: curl/7.51.0
> X-PSK-Auth: e6e59c8c1dcca46fde36bf43b84487d8

HTTP/1.1 200 OK
Date: Wed, 12 Apr 2017 07:49:39 GMT
Transfer-Encoding: chunked
Connection: keep-alive
Server: nginx/1.10.2
[...]

Apache

In this case we’re going to configure an Apache origin:

We simply insert this in our VirtualHost – but as per the linked GitHub repo, this could also sit within a specific Directory stanza.

Now we have this, we can validate that going direct to the origin fails:

psk-blocked

Whereas through the CDN is allowed through.

Considerations and Drawbacks

There’s one notable drawback to this approach, which is that the key is fixed between the edge and the origin. This means if you have untrusted users who can inspect or dump the headers between the CDN and your origin (for instance, if they can upload PHP) – then they’ll also be able to see the PSK between your edge and origin. Although if you have users who can upload arbitrary PHP – you probably have other issues.

This is in some way mitigated by stripping the X-PSK-Auth header at the terminating HTTP(S) server before it’s passed to an application server, and by using End-to-End SSL (Client to CDN, CDN to origin), it reduces the risk of sniffing.

Photo Old London Underground ticket barrier by Matt Brown (CC)