TIL - Terraform Feature Flags

Feature Flags in Terraform

Introduction

I have been trying to figure out how we can support trunk-based development for our platform automation code. We have issues today where we merge one or more features into master after they are completed, but we cannot apply them because they are dependent on additional features that are still under development. To avoid these problems, we try to avoid merging partially completed features like these into master until all of the dependencies are also complete. This leads to having long-lived branches, which leads to merge conflicts, wailing and gnashing of teeth.

Enter Feature Flags

Feature flags are a way to separate feature deployment from feature release. In simple terms, it takes a feature and wraps a configuration toggle around it that controls when the feature is activated. This gives us the ability to deploy from the master branch and control feature releases through configuration. In terms of automation code, it means we can have partial features merged into the master branch and leave them deactivated until we are ready to release them.

Feature Flags in Terraform

There are libraries and tools available for implementing features flags in most general purpose languages. Terraform is a somewhat different since it is a declarative language and does not have normal flow control features. In a general purpose imperative language, a feature flag could be implemented using a simple if statement. Since Terraform does not have an if statement, we have to be a little more creative.

To implement feature flags in Terraform, we can combine the count property with a conditional expression. Most Terraform resources support the count property. Normally it is used to control creating multiple resources, but it also will allow us to control whether or not a specific resource gets created at all. For example, we can use count with an AWS EC2 resource to control whether or not it gets created when we apply our definition.

First we start by creating a boolean variable to represent the feature flag:

1
2
3
4
variable "feature_flag1" {
description = "Variable to control resources related to a feature"
default = false
}

This variable will control whether the resources related to a given feature get created when a terraform apply is run. We then combine it with a conditional expression when we define the EC2 resource:

1
2
3
4
5
resource "aws_instance" "feature1_instance" {
instance_type = "t2.micro"
ami = var.ami
count = var.feature_flag1 ? 1 : 0
}

The conditional expression checks the feature flag variable value we set, and then sets count to 1 if the flag is true, or 0 if the flag is false. When count is 0, Terraform will not create the resource on apply. A single feature flag can be applied to one or more resources to control their creation as a group. If you really wanted to get fancy, you could define the feature flags in a map and pass it to a custom module.

Next Steps

So far, this has been working within my own limited testing. I want to spend some more time testing this with custom modules to see if it works with them. I am hoping Hashicorp will add some sort of native support to Terraform in the future. Alternatively, I could use a more general language or a templating tool to generate my Terraform code based on the feature flag configuration.