DEV Community

Cover image for βœ… Task 2 β€” Create a Reusable VPC Module with Environments using Terraform (dev/stage/prod)
Latchu@DevOps
Latchu@DevOps

Posted on

βœ… Task 2 β€” Create a Reusable VPC Module with Environments using Terraform (dev/stage/prod)

πŸ“˜ 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:

  1. Build a reusable Terraform VPC module
  2. Deploy the module for dev, stage, prod
  3. 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

Enter fullscreen mode Exit fullscreen mode

🧩 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 = {}
}

Enter fullscreen mode Exit fullscreen mode

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
}

Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

🧩 Step 2: Create Environment Configurations

πŸ”Ή envs/dev/variables.tf

variable "vpc_cidr" {}
variable "public_subnets" {}
variable "private_subnets" {}
variable "enable_nat" {}

Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 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"
  }
}
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 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
Enter fullscreen mode Exit fullscreen mode

Same as dev, except NAT enabled:

πŸ”Ή envs/stage/variables.tf

variable "vpc_cidr" {}
variable "public_subnets" {}
variable "private_subnets" {}
variable "enable_nat" {}
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 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"
  }
}
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 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
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή envs/prod/variables.tf

variable "vpc_cidr" {}
variable "public_subnets" {}
variable "private_subnets" {}
variable "enable_nat" {}
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 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"
  }
}

Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 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

Enter fullscreen mode Exit fullscreen mode

1


πŸš€ Step 3: Deploy the VPC

Run dev environment

cd envs/dev
terraform init
terraform plan
terraform apply
Enter fullscreen mode Exit fullscreen mode

Run stage

cd envs/stage
terraform init
terraform plan
terraform apply
Enter fullscreen mode Exit fullscreen mode

Run prod

cd envs/prod
terraform init
terraform plan
terraform apply
Enter fullscreen mode Exit fullscreen mode

🌟 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)