I have two public & private subnets across two AZs. I want to create a NAT in both public subnets. How do I route my private route table to use both NATs? Case three in
CodePudding user response:
Short answer: you need to have a separate route table for each private subnet.
Long answer: I would start by defining a map that contains configuration for each availability zone. I avoid count
in modern Terraform configs because it's too easy to cause incompatibilities down the road (especially if you're using it to index an array).
locals {
subnets = {
"1a" = { "public_cidr": "172.31.0.0/24", private_cidr: "172.31.1.0/24" }
"1b" = { "public_cidr": "172.31.2.0/24", private_cidr: "172.31.3.0/24" }
}
}
Now, you can use for_each
to create public and private subnets for each of these availability zones:
resource "aws_subnet" "public" {
for_each = local.subnets
vpc_id = aws_vpc.example.id
cidr_block = each.value["public_cidr"]
tags = {
Name = "public-${each.key}"
}
}
resource "aws_subnet" "private" {
for_each = local.subnets
vpc_id = aws_vpc.example.id
cidr_block = each.value["private_cidr"]
tags = {
Name = "private-${each.key}"
}
}
You can associate the public subnets with the default route table (which must have a route to the Internet Gateway). Personally, I prefer creating my own public route table, rather than updating the default.
Next, you'll need to create a NAT Gateway in each public subnet:
resource "aws_nat_gateway" "example" {
depends_on = [aws_internet_gateway.example]
for_each = local.subnets
allocation_id = aws_eip.nat_ip[each.key].id
subnet_id = aws_subnet.public[each.key].id
tags = {
Name = "nat-${each.key}"
}
}
And now the important part: each private subnet needs its own route table, which references the NAT Gateway specific to its availability zone.
resource "aws_route_table" "private" {
for_each = local.subnets
vpc_id = aws_vpc.example.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.example[each.key].id
}
tags = {
Name = "private-${each.key}"
}
}
resource "aws_route_table_association" "private" {
for_each = local.subnets
subnet_id = aws_subnet.private[each.key].id
route_table_id = aws_route_table.private[each.key].id
}