Anyone who has developed a highly modular Terraform project has wished at some point that there was a simple way to implement global variables.  This feature will probably not be developed though, because as Paul Hinze of HashiCorp stated:

In general we’re against the particular solution of Global Variables, since it makes the input -> resources -> output flow of Modules less explicit, and explicitness is a core design goal.

I am an advocate of the DRY software development principle, and two of the key goals for my open source VMUG Labs project are simplicity & ease of use for the end user, so I started brainstorming for a better way to implement this- a solution where you do not have to remember to specify a shared tfvars file, use a a script that specifies the shared tfvars file or run-line variables for you, group resources that you want segregated, or reference the value from the state file of one of the other modules or use a default value for the variable when those doesn’t make sense.

Eventually, it dawned on me- create a global variable module with static outputs and reference the module in your Terraform resource configuration files.  The optimal implementation of this would be to store the module in a private source control repository because remote modules can reference specific versions, though this can also implemented via a local module, which was the best fit for my VMUG Labs project since it is open source (public) and I wanted to minimize the number of components necessary for end users.

At first, I thought that I was the first to think of this solution (and document it publicly), but then I found that @keirhbadger beat me to it by almost a year.  Oh well.

Here are a couple of example output values from the outputs.tf.example file in the local global_variables module in the VMUG Labs project.  You would make your own copy of this file named outputs.tf and set the values appropriately. The new outputs.tf will be ignored by your git client per the entry in the .gitignore file to prevent the sensitive data in this file from being accidentally committed into source control.

output "aws_profile" {
  value = "aws_profile"
}

output "aws_region" {
  value = "us-west-2"
}

I can then use the static output values in the global_variables module to set input parameters in segregated resources with separate state files.  For example, the domain_controller and jumphost Terraform config files:

module "global_variables" {
  source = "../../../modules/global_variables"
}

provider "aws" {
  version = "~> 1.13"
  profile = "${module.global_variables.aws_profile}"
  region = "${module.global_variables.aws_region}"
}

Voila! That’s it!

This solution can be a more intuitive approach for end users that may be less experienced with Terraform.

Enjoy!

Improve this page

Comments