Dave Michaels
Dave Michaels

Reputation: 937

Attach multiple private subnet to route table for each terraform

I have public and private subnets established in a VPC created with for each. I am now trying to create route tables for the subnets and nat gateways specifically for access for private instances. My subnets, route tables, and public subnet associations are working properly. I am having trouble getting my private subnets to attach to the route table connecting it to the NAT gateway. I believe my logic correct. My NAT gateways are sitting in my public subnets. The only issue is private subnets being attached to the route table that connects to the NAT gateway. Below is my code, any advice is appreciated.

resource "aws_route_table" "public" {
  for_each = var.pub_subnet
  vpc_id   = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main.id
  }

  tags = {
    Name = var.rt_tags
  }
}

resource "aws_route_table_association" "public" {
  for_each       = aws_subnet.public
  route_table_id = aws_route_table.public[each.key].id
  subnet_id      = each.value.id
}

resource "aws_route_table_association" "nat" {
  for_each       = aws_subnet.private
  route_table_id = aws_route_table.nat[each.key].id
  subnet_id      = each.value.id
}

resource "aws_route_table" "nat" {
  for_each = var.pub_subnet
  vpc_id   = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_nat_gateway.main[each.key].id
  }

  tags = {
    Name = var.rt_tags_private
  }
}

resource "aws_subnet" "public" {
  for_each                = var.pub_subnet
  vpc_id                  = aws_vpc.main.id
  cidr_block              = each.value.cidr_block
  availability_zone       = each.value.availability_zone
  map_public_ip_on_launch = true
  tags = {
    Name = each.key
  }
}

resource "aws_subnet" "private" {
  for_each                = var.priv_subnet
  vpc_id                  = aws_vpc.main.id
  cidr_block              = each.value.cidr_block
  availability_zone       = each.value.availability_zone
  map_public_ip_on_launch = false
  tags = {
    Name = each.key
  }
}

Variables

variable "pub_subnet" {
  type = map(object({
    cidr_block        = string
    availability_zone = string
  }))
  default = {
    "PubSub1" = {
      cidr_block        = "10.0.1.0/24"
      availability_zone = "us-west-1a"
    }
  }
}

variable "priv_subnet" {
  type = map(object({
    cidr_block        = string
    availability_zone = string
  }))
  default = {
    "PrivSub1" = {
      cidr_block        = "10.0.2.0/24"
      availability_zone = "us-west-1c"
    }
  }
}

Error

Error: Invalid index

  on vpc.tf line 61, in resource "aws_route_table_association" "nat":
  61:   route_table_id = aws_route_table.nat[each.key].id
    |----------------
    | aws_route_table.nat is object with 1 attribute "PubSub1"
    | each.key is "PrivSub1"

The given key does not identify an element in this collection value.

NAT Gateway

resource "aws_nat_gateway" "main" {
  for_each      = aws_subnet.public
  subnet_id     = each.value.id
  allocation_id = aws_eip.main[each.key].id
}

EIP

resource "aws_eip" "main" {
  for_each = aws_subnet.public
  vpc      = true

  lifecycle {
    create_before_destroy = true
  }
}

Upvotes: 2

Views: 3866

Answers (1)

Marcin
Marcin

Reputation: 238209

You are defining your route table for nat using var.pub_subnet which has the form of:

  "PubSub1" = {
      cidr_block        = "10.0.1.0/24"
      availability_zone = "us-west-1a"
    }

Thus to refer to aws_route_table you have to use PubSub1 key.

However, in your aws_route_table_association you are iterating over aws_subnet.private which has key of PrivSub1.

update

The issue can be overcome by creating a local mapping for private=>public subnets names, e.g.:

locals {
   private_public_mapping = zipmap(keys(var.priv_subnet), keys(var.pub_subnet))
}

resource "aws_route_table_association" "nat" {
  for_each       = aws_subnet.private
  route_table_id = aws_route_table.nat[local.private_public_mapping[each.key]].id
  subnet_id      = each.value.id
}

Upvotes: 2

Related Questions