Scoring A+ for Security Headers on My Cloudfront-Hosted Static Website2019-04-15
On Saturday, I posted my guide on Scoring A+ for Security Headers in Django, following my talk at DjangoCon Europe. I thought it would be a good idea to step up and make my own site score A+, rather than a dismal F! My site isn’t built in Django, but as a Jekyll static site. It’s hosted on AWS S3 and CloudFront.
I found Tom Cook’s guide on Medium, which got me most of the way. Rather than using the AWS web console, I deploy my site with AWS’ Infrastructure-as-Code tool CloudFormation. Thus I needed to translate the guide into some CloudFormation template changes.
First I added an IAM role for my Lambda function and gave it permission to write logs:
Then I created the function, including the code inline in my template so I don’t have to upload it to an S3 bucket. Thanks to Tom Cook for the code, which I tweaked for my headers. I rolled out the headers iteratively, but the final version looks like:
After this I had to tackle the complexity of Lambda versioning. CloudFront’s Lambda@Edge configuration requires a specific version of the Lambda function. This is a bit hard to configure with CloudFormation.
With the default behaviour updating to create a new version would mean deleting the old one.
The easiest fix to this is to create the version with CloudFormation’s
This tells CloudFormation to retain old instances of the resource instead of deleting them.
Another downside is that if I deploy a new version of the code, I need to rename the version resource in the template to creates a new one.
So the version looks like this in my template (note it’s my eigth iteration here, so I suffixed it ‘8’):
Then I needed to point my CloudFront distribution to execute the Lambda function version. There are multiple events one can hook into, here I needed the ‘viewer response’ event.
Configuring CloudFront with CloudFormation is my least favourite time so use AWS. It’s hard to get right first time and updating is super slow so testing can take hours. (I wrote most of this blog post in the time it took to update and iterate to A+.)
I added function in the
LambdaFunctionAssociations key under the
My full CloudFront configuration looks like this :
But now I have my A+ rating!
(No, I didn’t bother adding
Feature-Policy, since it’s still experimental and I haven’t got many scripts.)
Hope this helps you configure your site,
Or perhaps you'd like to read a related post:
- How to Score A+ for Security Headers on Your Django Website
- Feature-Policy updates - now required for an A+ on SecurityHeaders.com
- Django's Test Case Classes and a Three Times Speed-Up
© 2019 All rights reserved.