Infrastructure as code

Designing a reusable AWS VPC module without hiding risk

Good modules remove repetition. They should not remove the visibility of cost, trust boundaries, routing, or failure consequences.

Choose a useful module boundary

A VPC module can reasonably own the network, subnets, routing, gateways, and common tags. It should not automatically absorb unrelated application resources simply because they connect to the network.

A clear boundary makes replacement, review, and security reasoning easier.

Expose decisions, not implementation noise

Inputs should describe choices a caller must understand: CIDR ranges, availability zones, public/private layout, NAT strategy, naming, and tags.

module "network" {
  source = "./modules/network"

  name               = "education-platform"
  vpc_cidr           = "10.20.0.0/16"
  availability_zones = ["ap-south-1a", "ap-south-1b"]
  enable_nat_gateway = true
}

A module with dozens of obscure toggles may be flexible, but it often transfers complexity rather than removing it.

Make NAT cost visible

A managed NAT gateway provides a reliable path for private workloads, but it has hourly and data-processing cost. Small labs may choose a different design. Production systems may value the managed operational model. The module should not hide this trade-off behind an innocent default.

Security groups belong near workloads

The network module can provide shared boundaries, but workload-specific ingress should usually remain with the workload that understands the required traffic. This reduces a central file full of unrelated exceptions.

Return identifiers that support composition

Useful outputs include VPC ID, public and private subnet IDs, route-table IDs, and gateway details. Avoid returning internal values simply because they are available.

Plan output is not the final verification

Review the plan, apply through a controlled path, then verify actual routes, public exposure, DNS behavior, egress, and tagging. Automated policy checks can catch broad risks, but targeted connectivity tests answer whether the intended path works.

Version the module contract

Callers depend on input meaning and output shape. Breaking changes should be deliberate, documented, and tested against representative consumers.

Explore the AWS infrastructure lab →