Deploying Secure Asset Distribution with AWS and Terraform

I was recently asked to come up with a solution for hosting some media files for a site. The requirements were pretty straight forward:

  • Should be available via HTTP and HTTPS
  • Minimal support requirements
  • AWS Based
  • Assets can be uploaded to the hosting with minimal effort/knowledge
  • Site should be performant within Europe (in particular)

The rest of the post will detail why I chose the solution I did to satisfy those requirements and how I went about configuring it. It includes a generalised version of the configuration in Github and even a diagram to illustrate!

The solution I came up with looks like this (simplified):

Simplified Diagram

Six months ago I would likely have gone down a different path, but the minimal support and AWS requirements, along with some recent developments, meant that I looked at an all-AWS solution here. What were those developments?

For those uninitiated in the ways of AWS, ACM is Amazon’s attempt at SSL certificates as a service, Cloudfront is their CDN offering, and Terraform can be used to write the various pieces needed to configure and maintain these things (mostly) as code. Put those things together with some decent documentation, and you are on a path to that minimal support requirement mentioned above.

As long as you have access to the relevant e-mail and/or DNS configuration for a domain to allow you to validate your ownership of a domain, you can easily provision and deploy (within AWS) SSL certificates without having to go to a 3rd party.

The total time to go from no cert to deployable cert is basically the time taken to receive the validation mail and click on a link. Depending on how you manage certs within your company, this could be a saving of minutes, hours, or even days.

There is a caveat here, and that is that the certs are only usable fully in the us-east-1 region as of writing this post (more regions are coming soontm). However, if the ACM cert is used in a Cloudfront Distribution it will be distributed to other regions. Since I had a CDN requirement (for performance) anyway, this was still in the running.

My next check was to see if all of this was configurable with Terraform, and here my timing was impeccable. The 0.6.15 version had been released a week previously and had added support for Cloudfront distributions. ACM was not supported yet, but since that required a manual verification step anyway I was not particularly worried.

In the end, there were only 2 really tricky parts to this:

  1. Getting my bucket policy template file to interpolate correctly during the plan phase is not possible because of this bug
  2. The target zone for alias records is actually a hard coded value which I finally figured out after many failed guesses

All of this resulted in a configuration very similar to this one. It has been generalised for public consumption (of course) but the Readme covers what you need to do before it is fully usable.