Reusable CloudFront configuration with Terraform

How we host our static websites with two lines of code

We ❤ Terraform

At buildo, we’re avid users of AWS, both for our customers and for our internal infrastructure. Since last year, we started using Terraform, a tool by Hashicorp that enables managing infrastructure as code.

The idea behind Terraform is to describe your infrastructure in configuration files, store them under version control (we keep ours on GitHub) and let the tool manage the synchronization between what is configured and the real-world infrastructure (e.g., your Amazon AWS resources).

It’s not all sunshine and rainbows, but not having to fiddle with the AWS console is indeed a huge win that outweighs the occasional annoyances and bugs the tool may have.

Since the introduction of Terraform, changing a DNS or creating an S3 bucket is now done with a pull request on GitHub, which gets reviewed, merged and “deployed” like any other development task. It’s really liberating!

Deploying our beloved website

Our website has been hosted on S3 since forever, and its content has been served through a Cloudfront distribution, for faster assets transfers and SSL support. This simple setup served us well, but we had some issues with redirects from https://buildo.io to https://www.buildo.io and from http to https . In general, we wanted to have a website hosted at https://www.buildo.io and have these three to redirect there:

We realized that the simplest way of achieving this was using two CloudFront distributions (one for www and one for the “naked” domain), pointing to two S3 buckets (one holding the content, one redirecting to the other one).

NOTE: There are probably other solutions, but this was the most straightforward to serve our purposes. I’d love to hear about alternative approaches in the comments.

If you think about that, it’s now a lot of infrastructure to configure. Terraform helps in keeping it manageable, but we’re still talking about ~100LOC of configuration, for what it initially looked like a super-straightforward task.

Do we really want to write 100LOC just to manage our static website?

Meet the modules

At the same time, while we were rethinking the deploy of buildo.io, we needed to deploy another static website for a customer, with an identical setup.

Ok, now we definitely don’t want to duplicate the effort: the only thing that changes about the two websites is the domain name. Is there a way we can avoid the duplication?

Also, 100 * n LOC may be ok to write, but what if we discover a new strategy for managing the redirection? Do we go and fix n sites?

“There must be a better way”, we all thought. And (surprise!) there is one: Terraform modules. Modules allow us to group chunks of resources together, defining input variables and outputs that other resources can consume.

So, what does our website configuration code look like now?

module "website" {

source = "buildo/website/aws"

domain = "buildo.io"

}

Not bad, right?

This code is using the module buildo/website/aws , which we open-sourced and published on the Terraform public registry. The module does exactly what we described above: it creates two CloudFront distributions, two buckets, the DNS records, and links them all together.

You can check the source code of the module here.

As a bonus, you can also enable health checks on the website endpoint and get notified via SNS.

module "buildo-io" {

source = "buildo/website/aws"

domain = "buildo.io" enable_health_check = true

health_check_alarm_sns_topics = [

"<some ARN of an SNS topic to notify>"

]

}

We already had an SNS topic connected to a Lambda function that publishes messages on Slack.

This means that with those two extra lines we immediately get notified on our #devops Slack channel whenever the website is unreachable for some reason.

So what?

The main takeaways from this brief story are:

Terraform allows managing infrastructure as code (no more pointing and clicking in the AWS console!)

Terraform has support for modules, that can abstract away re-usable parts of functionality, much like a library in the context of a programming language

Modules allow to pay the cost of configuring a piece of infrastructure just once

Finally, we are now free to change the “deployment strategy” of all our websites only by editing the module code. A concrete example: moving to Cloudflare (also supported by Terraform) instead of Cloudfront? No problem.

I hope this article made you aware of what a fantastic tool Terraform is and how you can use it effectively to manage your team’s infrastructure, re-using code with modules.

—

If you want to work in a place where we care about the quality of our development workflow, down to the details of our infrastructure, take a look at https://buildo.io/careers