Terraform: How to avoid hard-coding of AWS account IDs?

When using multiple AWS accounts it very likely that you will have hard-coded AWS account IDs all over your Terraform codebase. Hard-coding is annoying and prone to errors. For example, you could use the production AWS account ID instead of pre-production one by mistake. So its always better to have these account numbers defined somewhere and consumed by name.

The immediate solution to this is to extract them as variables. However, if your codebase is complex and involves tons of modules and terraform files then you will have to copy these variable definitions all over the modules and terraform files.

So, to overcome this we can extract these variable definitions into a module. But, how do we access these variables from another module or terraform file? We cannot, because variables defined inside a module are scoped. Here comes the power of Terraform output variables. Using output variables a module can expose data to its consumers.

Following the above, we can create a module called account_ids and store all the AWS account IDs as follows:

# example/modules/account_ids/main.tf

output "usermanagement" {
  value = "123456789012"
}

output "tools" {
  value = "123456789123"
}

output "project_a_pre_prod" {
  value = "123456789456"
}

output "project_a_prod" {
  value = "123456789789"
}

Now we can consume the above module and get access to the variables from another module or terraform file as shown below:

# example/main.tf

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

locals {
  project_a_pre_prod = "${module.account_ids.project_a_pre_prod}"
  project_a_prod = "${module.account_ids.project_a_prod}"
  ...
}

...

Following the above pattern, we can also extract global variables into a separate module.

I can think of one place where this solution will not work. Its the Terraform backend configuration. Terraform does not allow interpolation in the backend configuration. So if you need to use any account ID in the backend configuration you will have to hard-code it. There are some workarounds in GitHub issues maybe I will write about it in another post.