A subnetwork, or subnet, divides a virtual private cloud (VPC) into a network segment with its own IP address range. A Terraform module that launches an AWS instance can accept a subnet ID so the caller chooses where the instance goes, rather than being limited to a default subnet. section 10.2 section 3.8
When a module only needs to use an existing network, accept a VPC ID or subnet IDs and pass them to resources. For an instance module, declare a string input named `subnet_id` and set `aws_instance.subnet_id = var.subnet_id`. Input validation can check the ID’s expected format before the value reaches the resource. section 10.2 section 3.8.2
Listing 3.33 Using input variables
resource "aws_instance" "hello_world" {
ami = data.aws_ami.ubuntu.id
subnet_id = var.subnet_id #1
instance_type = var.instance_type #2
}
The instance resource takes its subnet from an input variable, allowing the same module to launch into different subnets. section 3.8.2
Creating subnets is a different job. A network module can take a CIDR block—the range of IP addresses it may use—and divide it with `cidrsubnet`. A two-segment design assigns one resulting range to a public subnet and the other to a private subnet. Its AWS subnet resources also specify a VPC and availability zone. section 10.2.3
Listing 10.6 Public and private subnet module
variable "cidr_block" {
description = "The CIDR block for the network."
type = string
}
variable "vpc_id" {
description = "The ID of the VPC."
type = string
}
variable "availability_zone" {
description = "The availability zone."
type = string
}
locals {
private_subnet_cidr_block = cidrsubnet(var.cidr_block, 1, 0) #1
public_subnet_cidr_block = cidrsubnet(var.cidr_block, 1, 1) #1
}
#
# Public Network
#
resource "aws_subnet" "public" {
vpc_id = var.vpc_id
cidr_block = local.public_subnet_cidr_block #2
map_public_ip_on_launch = true #3
availability_zone = var.availability_zone
tags = {
Network = "Public" #4
}
}
resource "aws_eip" "nat" {
tags = {}
}
resource "aws_nat_gateway" "main" { #5
allocation_id = aws_eip.nat.id #6
subnet_id = aws_subnet.public.id #7
tags = {}
}
#
# Private Network
#
resource "aws_subnet" "private" { #8
vpc_id = var.vpc_id
cidr_block = local.private_subnet_cidr_block #9
availability_zone = var.availability_zone #10
tags = {
Network = "Private"
}
}
resource "aws_route_table" "private" { #11
vpc_id = var.vpc_id
}
resource "aws_route_table_association" "private" { #12
subnet_id = aws_subnet.private.id
route_table_id = aws_route_table.private.id
}
resource "aws_route" "internet_access" { #13
route_table_id = aws_route_table.private.id
nat_gateway_id = aws_nat_gateway.main.id
destination_cidr_block = "0.0.0.0/0" #14
}
output "private_subnet_id" { #15
value = aws_subnet.private.id
}
output "public_subnet_id" { #16
value = aws_subnet.public.id
}
The two-segment module shows `cidrsubnet` deriving separate address ranges and `aws_subnet` placing a subnet in a VPC and availability zone. section 10.2.3
Subnet placement alone does not establish internet access. The public subnet enables public IP addresses; the private subnet disables them and uses a NAT gateway for outbound access. An internet gateway remains a responsibility of the higher-level network module. A three-segment design can add an isolated subnet without internet access. section 10.2.3




