CloudFront Edge to Origin Auth
- 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:
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:
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:
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)
I have followed the same steps but it shows error “Internal Server Error 500”