Simple Static Site Provisioning With Terraform Modules

Gavin Johnson
Mojo Mortgages
Published in
4 min readFeb 22, 2021

We use lots of static sites here at Mojo, from our main gatsby-driven website through to simple utility sites to help our people get their jobs done.

In principle it’s really simple to get up and running; create an S3 bucket, create a CloudFront distribution pointing to the bucket and then add a Route53 record. Done!

As in life, things are never quite that simple. Taking S3 for example, there’s extra stuff that you really want to have in place including:

  1. Server-side encryption
  2. Versioning
  3. Access logging
  4. Tags
  5. Enforced SSL
  6. Blocking public access

What about adding some security headers into your site to help with the security posture? How about adding in the ability to blue/green the site? (tricky with CloudFront and that deserves a post in itself!)

This is where Terraform modules can be a real timesaver. They allow you to encapsulate all that logic and abstract the complexity away. It saves time and makes sure things are done in a consistent manner. There’s loads of existing modules that you can download from the Terraform Registry but if you don’t want them public you can host them in your own git repository.

In principle a Terraform module is just a directory that contains Terraform files. You use variables to define the inputs, config for the resources to be created and then outputs to send things back out to whatever is consuming the module.

At Mojo we created one for ourselves which will create something akin to this:

Now encapsulating that logic in a module we can create a site in a few simple lines:

Well, there are a few extra things like setting up the provider and state but that’s the same for any Terraform config. In the module, there are well over 500 lines of code that have been abstracted away. So, even if you include the extra code it’s still more than a 10 fold decrease in code! Plus everything is setup for us in a nice consistent manner without AWS SecurityHub firing out alerts for badly configured infrastructure. Party time! 🎆

Using count and dynamic blocks to enable and disable features

In the example above you’ll notice that we set blue_green_enabled = true. For some simple sites having a blue/green setup is just overkill so we allow it to be enabled and disabled. In normal languages, this is pretty straight forward but in HCL it’s a bit more complicated.

For a resource, the easiest way to make it optional is to use the count meta argument. We can then use an operator to check for the variable and then set count to either 1 or 0 which will have the effect for creating or not creating the resource. In the example below when blue_green_enabled is set to true we’ll create the lambda function otherwise we won’t.

This works great for when you want to control things at a resource level but it doesn’t work when you’re trying to do it at a block-level within the resource. For example, in a CloudFront distribution, a Lambda@Edge function is defined within a lambda_function_association block. So if you don’t want to use blue/green, we’d still want the CloudFront to be created, just without the lambda_function_association block.

Normally you’d create a lambda association within a behaviour block.

If blue_green_enabled is set to false, count gets set to 0, no resource is created and, alarm bells ringing, you’ll get a Terraform error as the aws_lambda_function.blue_green.qualified_arn can’t be found.

This is where dynamic blocks come to the rescue. The syntax is pretty simple as you can see in the example below:

The for_each statement references the blue_green lambda, as count for the lambda is either 1 or 0 the loop will either run once or not at all. The only other bit to note is how you then reference the lambda’s qualified_arn, you do this using the value property of the dynamic block name rather than the lambda itself. Now everything works as we’d like it, simple when you know how.

Hope you found this useful and if you want some more readings then here some useful links:

https://www.terraform.io/docs/language/modules/develop/index.html
https://www.terraform.io/docs/language/meta-arguments/count.html
https://www.terraform.io/docs/language/expressions/dynamic-blocks.html

Cheers,

Gav at Mojo

--

--