exists [Editor’s note: It did exist this way at the time it was written. This is no longer true.] as a series of programmatically generated static pages that end up in an S3 bucket. (The generation process, while fascinating, is going to be the subject of a different blog post at some point and is out of scope for the rant upon which I’m about to embark.) To enable TLS, I slap CloudFront in front of that S3 bucket, and then restrict access on the bucket to the CloudFront distribution (I don’t leave it open to the world, as I couldn’t afford to hire Accenture to do my cloud security). So far this is standard, and everything works about like you’d expect it to.

The trouble comes in when I wanted to inject a few security headers in so I could get the A+ at SSL Labs (spoiler: I did). In a typical webserver environment, it’s not hard to tell Apache, Nginx, IIS, etc. to set a few arbitrary headers and call it a day. Since you’re reading this post, you might surmise that it’s not nearly so straighforward.

To insert a static header from CloudFront, you have to use a Lambda@Edge function in Javascript to add static headers.

Let me repeat that.

To insert a static header in CloudFront– a CDN service– you must use a freaking Javascript function to dynamically insert what you want into every godforsaken request.

It was around this point that I began screaming at my laptop and scaring the hell out of my chihuahua.

It turns out that you can only have Lambda@Edge functions in us-tirefire-1, they can only be written in Node, and they counter-intuitively need to have a trigger of “Viewer Response,” or they simply won’t work at all.

When the red haze faded, I disappointed my mother and wrote a node.js function that would inject the headers I wanted, but that’s not where the fun stopped.

As a final indignity, I now get to pay $0.91 per 1 million requests (a combination of the per-request charge plus compute time per invocation) just to add a static header.

You can’t have the trigger point to “latest.” You have to publish a version, and then rebuild the trigger. At some point I’m going to shove this into CloudFormation, Terraform, or a terrifying bash script and make this straightforward, but I’m really hoping I won’t ever have to touch this monster again.

AWS CloudFront team, if you’re out there: please let me set custom headers on response. I will send you an Edible Arrangement if you do. I’m not kidding.