π Scenario
Your company wants to standardize the AWS network setup across all environments β dev, stage, and prod.
Architects want a Terraform VPC module that:
- Creates a VPC with configurable CIDR
- Creates customizable public and private subnets
- Creates an Internet Gateway
- Creates NAT Gateways (only for stage & prod)
- Expose outputs so other teams can use the VPC module
Your task is to:
- Build a reusable Terraform VPC module
- Deploy the module for dev, stage, prod
- Make the module flexible using variables
π― What You Will Learn
- How to write a Terraform module
- How to structure multi-environment Terraform directories
- How to use variables & outputs
- How to control resources using count and conditional logic
- How to avoid repeated code
π Final Directory Structure (Goal)
terraform-task-02/
βββ envs
β βββ dev
β β βββ main.tf
β β βββ variables.tf
β β βββ terraform.tfvars
β βββ stage
β β βββ main.tf
β β βββ variables.tf
β β βββ terraform.tfvars
β βββ prod
β βββ main.tf
β βββ variables.tf
β βββ terraform.tfvars
βββ modules
βββ vpc
βββ main.tf
βββ variables.tf
βββ outputs.tf
π§© Step 1: Create the VPC Module
modules/vpc/variables.tf
variable "vpc_cidr" {
type = string
}
variable "public_subnets" {
type = list(string)
}
variable "private_subnets" {
type = list(string)
}
variable "enable_nat" {
type = bool
default = false
}
variable "tags" {
type = map(string)
default = {}
}
modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(var.tags, {
Name = "main-vpc"
})
}
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
tags = {
Name = "igw"
}
}
resource "aws_subnet" "public" {
count = length(var.public_subnets)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnets[count.index]
map_public_ip_on_launch = true
tags = {
Name = "public-${count.index}"
}
}
resource "aws_subnet" "private" {
count = length(var.private_subnets)
vpc_id = aws_vpc.main.id
cidr_block = var.private_subnets[count.index]
tags = {
Name = "private-${count.index}"
}
}
# NAT only if enabled
resource "aws_eip" "nat" {
count = var.enable_nat ? 1 : 0
}
resource "aws_nat_gateway" "nat" {
count = var.enable_nat ? 1 : 0
subnet_id = aws_subnet.public[0].id
allocation_id = aws_eip.nat[0].id
}
modules/vpc/outputs.tf
output "vpc_id" {
value = aws_vpc.main.id
}
output "public_subnets" {
value = aws_subnet.public[*].id
}
output "private_subnets" {
value = aws_subnet.private[*].id
}
output "nat_gateway_id" {
value = var.enable_nat ? aws_nat_gateway.nat[0].id : null
}
π§© Step 2: Create Environment Configurations
πΉ envs/dev/variables.tf
variable "vpc_cidr" {}
variable "public_subnets" {}
variable "private_subnets" {}
variable "enable_nat" {}
πΉ envs/dev/main.tf
provider "aws" {
region = "us-east-1"
}
module "vpc" {
source = "../../modules/vpc"
vpc_cidr = var.vpc_cidr
public_subnets = var.public_subnets
private_subnets = var.private_subnets
enable_nat = var.enable_nat
tags = {
Environment = "dev"
}
}
πΉ envs/dev/terraform.tfvars
vpc_cidr = "10.0.0.0/16"
public_subnets = [
"10.0.1.0/24",
"10.0.2.0/24"
]
private_subnets = [
"10.0.11.0/24",
"10.0.12.0/24"
]
enable_nat = false
Same as dev, except NAT enabled:
πΉ envs/stage/variables.tf
variable "vpc_cidr" {}
variable "public_subnets" {}
variable "private_subnets" {}
variable "enable_nat" {}
πΉ envs/stage/main.tf
provider "aws" {
region = "us-east-1"
}
module "vpc" {
source = "../../modules/vpc"
vpc_cidr = var.vpc_cidr
public_subnets = var.public_subnets
private_subnets = var.private_subnets
enable_nat = var.enable_nat
tags = {
Environment = "stage"
}
}
πΉ envs/stage/terraform.tfvars
vpc_cidr = "10.1.0.0/16"
public_subnets = [
"10.1.1.0/24",
"10.1.2.0/24"
]
private_subnets = [
"10.1.11.0/24",
"10.1.12.0/24"
]
enable_nat = true
πΉ envs/prod/variables.tf
variable "vpc_cidr" {}
variable "public_subnets" {}
variable "private_subnets" {}
variable "enable_nat" {}
πΉ envs/prod/main.tf
provider "aws" {
region = "us-east-1"
}
module "vpc" {
source = "../../modules/vpc"
vpc_cidr = var.vpc_cidr
public_subnets = var.public_subnets
private_subnets = var.private_subnets
enable_nat = var.enable_nat
tags = {
Environment = "prod"
}
}
πΉ envs/prod/terraform.tfvars
vpc_cidr = "10.2.0.0/16"
public_subnets = [
"10.2.1.0/24",
"10.2.2.0/24"
]
private_subnets = [
"10.2.11.0/24",
"10.2.12.0/24"
]
enable_nat = true
π Step 3: Deploy the VPC
Run dev environment
cd envs/dev
terraform init
terraform plan
terraform apply
Run stage
cd envs/stage
terraform init
terraform plan
terraform apply
Run prod
cd envs/prod
terraform init
terraform plan
terraform apply
π Thanks for reading! If this post added value, a like β€οΈ, follow, or share would encourage me to keep creating more content.
β Latchu | Senior DevOps & Cloud Engineer
βοΈ AWS | GCP | βΈοΈ Kubernetes | π Security | β‘ Automation
π Sharing hands-on guides, best practices & real-world cloud solutions

Top comments (0)