Error: Invalid index - For_each

Hi,
I’m trying to create route tables within AWS tied to a NAT Gateway. What I want to do, is create an RTB PER subnet IF multiple NATGW are created )one per AZ) or use the same NATGW if only one is created (Prod vs Dev).

I’m using the following:

locals {
azs = [“eu-west-2a”, “eu-west-2b”, “eu-west-2c”]
nat_gateways = {
“AZ1” = { az = “eu-west-2a” }/* ,
“AZ2” = {az = “eu-west-2a”},
“AZ3” = {az = “eu-west-2a”} */
}
compute_subnets = {
“AZ1” = { cidr = “10.100.11.0/24”, az = “eu-west-2a” },
“AZ2” = { cidr = “10.100.12.0/24”, az = “eu-west-2b” },
“AZ3” = { cidr = “10.100.13.0/24”, az = “eu-west-2c” }
}
}

resource “aws_eip” “nat” {
for_each = local.nat_gateways
vpc = true
lifecycle {
create_before_destroy = true
}
depends_on = [aws_internet_gateway.igw]
tags = {
Name = “EIP-NAT-GW-{each.key}" } } resource "aws_nat_gateway" "nat" { for_each = local.nat_gateways subnet_id = aws_subnet.public[each.key].id allocation_id = aws_eip.nat[each.key].id tags = { Name = "NAT-GW-{each.key}”
}
}

resource “aws_subnet” “compute” {
for_each = (local.compute_subnets != null ? local.compute_subnets : {})
vpc_id = aws_vpc.vpc.id
cidr_block = each.value.cidr
availability_zone = each.value.az
tags = {
Name = “Private-Compute-${each.key}”
}
}

resource “aws_route_table” “compute_rtb” {
for_each = local.compute_subnets
vpc_id = aws_vpc.vpc.id
route {
cidr_block = “0.0.0.0/0”
nat_gateway_id = aws_nat_gateway.nat[each.key].id
}
}

This works if 3 NATGW’s are specified (3 AZ’s) but fails with Error: Invalid index - aws_nat_gateway.nat is object with 1 attribute “AZ1”
each.key is “AZ2”
The given key does not identify an element in this collection value.

I understand why it is failing, but can’t think of a way of determining the NATGW_ID if only 1 AZ is deployed (I’ve been able to determine the logic for 1 or 3 using a comparison between compute_subnets and nat_gateway, but then not sure how/what to do from there).

I have the feeling this should be relatively simple, but cannot find an example (all of the VPC type modules seem to be using count).
The only way I can see at the moment if a conditional on the RTB resource (if length =) and duplicate the resource creation (single nat/multinat) but that seems a real kludge!

Basically count of keys and keys have to be equal on structures local.nat_gateways and local.compute_subnets.
So this means if a single NAT Gateway should be used for multiple subnets then the data structure of local.nat_gateways has to be expanded.

This might be a starting point:

locals {
  nat_gateways = {
    "AZ1" = { az = "eu-west-2a" } /* ,
"AZ2" = {az = "eu-west-2a"},
"AZ3" = {az = "eu-west-2a"} */
  }
  compute_subnets = {
    "AZ1" = { cidr = "10.100.11.0/24", az = "eu-west-2a" },
    "AZ2" = { cidr = "10.100.12.0/24", az = "eu-west-2b" },
    "AZ3" = { cidr = "10.100.13.0/24", az = "eu-west-2c" }
  }
  trans_nat_gateways = { for ck, cv in local.compute_subnets : ck => {
    az = try(local.nat_gateways[ck].az, local.nat_gateways["AZ1"].az) 
    }
  }
}

output "trans" {
  value = local.trans_nat_gateways
}

Thanks - I’ll give this a go (I did get it working with the duplicate resource kludge, but am not happy with it).