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.
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.
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:
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:
View the code on Gist.
and now I can see that my header is being set properly:
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.
In this case we’re going to configure an Apache origin:
View the code on Gist.
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:
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.