We created and opened the source Terragrunt to solve this problem. One of the features of Terragrunt is the ability to load remote Terraform configurations. The idea is that you only define Terraform code for your infrastructure once, in one repo, called, for example, modules :
βββ modules βββ app β βββ main.tf βββ mysql β βββ main.tf βββ vpc βββ main.tf
This repo contains typical Terraform code with one difference: everything in your code, which should be different between environments, should display as an input variable. For example, an application module may display the following variables:
variable "instance_count" { description = "How many servers to run" } variable "instance_type" { description = "What kind of servers to run (eg t2.large)" }
In a separate repo, called, for example, live, you define code for all your environments, which now consists of just one .tfvars file for each component (for example, app/terraform.tfvars , mysql/terraform.tfvars , etc.) . This gives you the following file layout:
βββ live βββ prod β βββ app β β βββ terraform.tfvars β βββ mysql β β βββ terraform.tfvars β βββ vpc β βββ terraform.tfvars βββ qa β βββ app β β βββ terraform.tfvars β βββ mysql β β βββ terraform.tfvars β βββ vpc β βββ terraform.tfvars βββ stage βββ app β βββ terraform.tfvars βββ mysql β βββ terraform.tfvars βββ vpc βββ terraform.tfvars
Please note that in any of the folders there are no Terraform configurations ( .tf files). Instead, each .tfvars file specifies a terraform { ... } block terraform { ... } , which indicates where to download the Terraform code, as well as the environment values ββfor the input variables of this Terraform code. For example, stage/app/terraform.tfvars might look like this:
terragrunt = { terraform { source = "git:: git@github.com :foo/modules.git//app?ref=v0.0.3" } } instance_count = 3 instance_type = "t2.micro"
And prod/app/terraform.tfvars might look like this:
terragrunt = { terraform { source = "git:: git@github.com :foo/modules.git//app?ref=v0.0.1" } } instance_count = 10 instance_type = "m2.large"
See the Terragrunt documentation for more information.