Lesson 25 / 33
Defining a VPC in Terraform
Declare a VPC, subnet, internet gateway and route table as code so the network is reviewable and reproducible.
By Rahul Agarwal · 15 years in web development
Why networks belong in version control
Clicking through a console works once. Six months later nobody remembers why a route exists, and recreating the network in another region is guesswork. Infrastructure as code (IaC) tools such as Terraform, OpenTofu, AWS CloudFormation, AWS CDK and Pulumi describe the desired network in files. Running the tool compares that description with what exists and makes only the needed changes. The benefits for networking are large: every rule change goes through a pull request where a reviewer can spot 0.0.0.0/0 on port 22; environments are built from the same module so staging matches production; and a plan step shows exactly what will be created, changed or destroyed before anything happens. Resource references such as aws_vpc.main.id also let the tool work out creation order, so the VPC exists before its subnets. Many teams start from a well-maintained community VPC module rather than writing every resource by hand.
A minimal public subnet, as code
Five resources give one public subnet: the VPC, the subnet, an internet gateway, a route table with a default route, and the association that ties the table to the subnet.
resource "aws_vpc" "main" {
cidr_block = "10.42.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = { Name = "main" }
}
resource "aws_subnet" "public_a" {
vpc_id = aws_vpc.main.id
cidr_block = "10.42.0.0/20"
availability_zone = "ap-south-1a"
map_public_ip_on_launch = true
}
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
}
resource "aws_route_table_association" "public_a" {
subnet_id = aws_subnet.public_a.id
route_table_id = aws_route_table.public.id
}Read the plan, every time
A changed subnet CIDR or availability zone forces Terraform to destroy and recreate the subnet and everything in it. Look for 'must be replaced' in the plan output before you apply.
Quick check: In the Terraform example, what makes public_a a public subnet?
- map_public_ip_on_launch = true on its own
- The aws_route_table_association linking it to a table with 0.0.0.0/0 -> IGW
- The CIDR block 10.42.0.0/20
- enable_dns_hostnames on the VPC
Answer
The aws_route_table_association linking it to a table with 0.0.0.0/0 -> IGW — Public IPs alone do not make a subnet public. The association to a route table with an internet gateway default route does.