Modularizing terraform is a great way to make reusable code but it can often come with it's own difficulties.

  1. You always have to output everything you want to refer to
  2. You can't set count on a module
  3. You should be version controlling each module which means you then have to deal with bumping versions on at least two levels (the root module and child) when you want those changes to propagate
  4. You don't want to have you your whole stack in one folder deployment (vpc and all) as you make one wrong change there and you could bork your whole infrastructure
  5. Large deployments are fragile and difficult to reconstruct in a different context

Regardless, using battle tested modules (like the ones at terraform-aws-modules) is a great way to build strong deployments. You just need to think about how much modularization you are going to do. The top open source contributors in terraform all recommend the use of terragrunt which we rely on heavily at inight-infrastructure to put together modular deployments.

Here are a few links discussing how we approach things.

terragrunt

Terraform Modules


When you start to break up terraform into different sections (ie different deployments / folders) that refer to dynamic variables (think you setup VPC in one place and need to get vpc_id out of it to run a module in another) , have three options to pipe variables from one location to another.

Terraform:

  1. Data reference to remote state
data "terraform_remote_state" "vpc" {
  backend = "remote"

  config = {
    organization = "hashicorp"
    workspaces = {
      name = "vpc-prod"
    }
  }
}
resource "aws_instance" "foo" {
  # ...
  subnet_id = data.terraform_remote_state.vpc.outputs.subnet_id
}
  1. Data query by tag
data "aws_ami" "web" {
  filter {
    name   = "state"
    values = ["available"]
  }

  filter {
    name   = "tag:Component"
    values = ["web"]
  }

  most_recent = true
}

Terragrunt