Reputation: 1059
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 this accepted answer. I know it's possible but I'm unsure on how to implement it. Should the destination cidr_block be the public subnet's cidr block? I also tried 0.0.0.0/0
and errored out.
resource "aws_route" "r" {
count = length(aws_nat_gateway.this)
route_table_id = aws_vpc.vpc.default_route_table_id
destination_cidr_block = "aws_subnet.public_subnets.${count.index}.cidr_block"
nat_gateway_id = "aws_nat_gateway.this.${count.index}.id"
depends_on = [aws_vpc.vpc,aws_subnet.public_subnets,aws_nat_gateway.this]
}
When I tried 0.0.0.0/0
error creating Route in Route Table (rtb-059eee10e310ade77) with destination (0.0.0.0/0): RouteAlreadyExists: The route identified by 0.0.0.0/0 already exists.
Upvotes: 3
Views: 3342
Reputation: 4486
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
}
Upvotes: 7