Home > Enterprise >  Configure Multiple NAT gateways
Configure Multiple NAT gateways

Time:02-13

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 enter image description here

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
}
  • Related