Terraform Conditionals

June 17, 2018 by mtchavez

Terraform is a very versatile tool to help automate your infrastructure and codify your infrastructure as code. With a large open source community and tons of providers across multiple cloud platforms it allows developers to create plans for spinning up infrastructure effortlessly. One thing I ran into that needed a little more effort was adding conditional steps to a configuration plan. Due to the complex nature of Terraform and how it attempts to plan out how it will execute your configuration it is a little more involved to get conditionals working.

HCL

Terraform uses it’s own custom language called HCL (HashiCorp Configuration Language). The language allows simple instructions to be used when writing up your terraform configuration. You can set variables and execute built in functions from dynamic contexts. An example of defining a variable and using it would be:

variable "subnet" {
  description = "Subnet to use"
}

resource "aws_instance" "web" {
  subnet = "${var.subnet}"
}

The built in conditional syntax allows you to make that a bit more dynamic based on the stage of your infrastructure:

resource "aws_instance" "web" {
  subnet = "${var.env == "production" ? var.prod_subnet : var.dev_subnet}"
}

Using these language features we are able to add conditional resources to our Terraform configuration.

Conditional Resources

The example I will use will be conditionally adding SSL certificates to resources. This will reqoure conditional resources and some dynamic configuration for your resources as well. First we want to create a variable that you want to use to describe your conditional resource, such as use_ssl. The following sets up a variable that defaults to false for when to use an SSL certificate or not.

variable "use_ssl" {
  description = "Set to true when using an SSL certificate on resources"
  value = false
}

Next for your resources that you want to conditionally be present for we have to configure the count setting which exists for each resource. When you do not want the resource you can set the count to 0. With that knowledge you can use your variable to conditionally set it to a count of zero or one.

resource "heroku_app" "serivce-app" {
  name = "org-serivce-app"
}

resource "heroku_addon" "ssl-addon" {
  app   = "${heroku_app.service-app.name}"
  count = "${var.use_ssl ? 1 : 0}"
  plan  = "ssl"
}

resource "heroku_cert" "ssl_certificate" {
  depends_on        = ["heroku_addon.ssl-addon"]
  count             = "${var.use_ssl ? 1 : 0}"
  app               = "${heroku_app.service-app.name}"
  certificate_chain = "${file("files/server.crt")}"
  private_key       = "${file("files/server.key")}"
}

This is doing a handful of things. First it is setting up an heroku app which will conditionally have an SSL addon and a SSL certificate. Using the count setting for a resource we can use our HCL conditional ternary syntax to say when use_ssl = false it will be a count = 0 and thus tells Terraform not to create this resource and include it in the state or plan.

If you ran terraform plan -var 'use_ssl=true' it would plan out the resources including the heroku_addon.ssl-addon and the heroku_cert.ssl_certificate. And by default runnign terraform plan would have a state that only included the heroku_app.service-app with no SSL resources considered.

Conclusion

Using the basics of HCL conditionals and the count attribute for Terraform resources we can pretty easily allow for even further dynamic resource configuration. Even though it sort of goes against some of the ideas behind Terraform one could see how using conditional resources is a useful trick to employ when it comes up as a way to solve a specific need.

mtchavez All rights reserved.