Terraform Modules

Module Structure

modules/ └── vpc/ ├── main.tf # Resources ├── variables.tf # Input variables ├── outputs.tf # Output values ├── versions.tf # Required providers/versions └── README.md # variables.tf variable "vpc_cidr" { type = string description = "CIDR block for the VPC" default = "10.0.0.0/16" validation { condition = can(cidrhost(var.vpc_cidr, 0)) error_message = "Must be a valid CIDR block." } } variable "tags" { type = map(string) description = "Resource tags" default = {} } variable "enable_nat_gateway" { type = bool default = true }

Module Sources

# Local path module "vpc" { source = "./modules/vpc" } # Terraform Registry (public) module "eks" { source = "terraform-aws-modules/eks/aws" version = "~> 20.0" } # GitHub module "vpc" { source = "github.com/my-org/terraform-modules//vpc?ref=v2.0.0" } # Git over HTTPS module "vpc" { source = "git::https://github.com/my-org/modules.git//vpc?ref=v2.0.0" } # Git over SSH module "vpc" { source = "git::ssh://[email protected]/my-org/modules.git//vpc?ref=main" } # Terraform Cloud / Enterprise private registry module "vpc" { source = "app.terraform.io/my-org/vpc/aws" version = "~> 2.0" } # S3 bucket module "vpc" { source = "s3::https://s3-eu-west-1.amazonaws.com/my-modules/vpc.zip" }

Calling a Module

# main.tf (root module) module "production_vpc" { source = "./modules/vpc" vpc_cidr = "10.0.0.0/16" public_subnets = ["10.0.1.0/24", "10.0.2.0/24"] private_subnets = ["10.0.10.0/24", "10.0.11.0/24"] enable_nat_gateway = true tags = { Environment = "production" Team = "platform" } } # Use module outputs resource "aws_security_group" "app" { vpc_id = module.production_vpc.vpc_id } output "vpc_id" { value = module.production_vpc.vpc_id } # Pass provider to module module "replica" { source = "./modules/storage" providers = { aws = aws.us_west } }

Outputs

# modules/vpc/outputs.tf output "vpc_id" { description = "The ID of the VPC" value = aws_vpc.main.id } output "public_subnet_ids" { description = "List of public subnet IDs" value = aws_subnet.public[*].id } output "private_subnet_ids" { description = "List of private subnet IDs" value = aws_subnet.private[*].id sensitive = false } output "nat_gateway_ip" { description = "Elastic IP for NAT gateway" value = try(aws_eip.nat[0].public_ip, null) }

Module Composition & Count/For_each

# Create multiple instances of a module variable "environments" { default = { dev = { cidr = "10.0.0.0/16", az_count = 2 } staging = { cidr = "10.1.0.0/16", az_count = 2 } prod = { cidr = "10.2.0.0/16", az_count = 3 } } } module "vpcs" { for_each = var.environments source = "./modules/vpc" name = each.key vpc_cidr = each.value.cidr az_count = each.value.az_count } # Access specific instance output output "prod_vpc_id" { value = module.vpcs["prod"].vpc_id } # Combine outputs from all instances output "all_vpc_ids" { value = { for k, v in module.vpcs : k => v.vpc_id } }