I'm creating two public subnets that will each contain a nat gateay. My code, attempts to create these nats per subnet, and then allocate the eip to each. However, since my for each starts the code block, it looks like the allocation id became us-east-* instead of the id of the eip.
Variables.tf:
variable "public_subnet_numbers" {
type = map(number)
description = "Map of AZ to a number that should be used for public subnets"
default = {
"us-east-1a" = 1
"us-east-1b" = 2
#"us-east-1c" = 3
}
}
variable "private_subnet_numbers" {
type = map(number)
description = "Map of AZ to a number that should be used for private subnets"
default = {
"us-east-1a" = 4
"us-east-1b" = 5
#"us-east-1c" = 6
}
}
variable "vpc_cidr" {
type = string
description = "The IP range to use for the VPC"
default = "192.168.0.0/16"
}
Main.tf:
resource "aws_eip" "nat" {
count = 2
vpc = true
lifecycle {
# prevent_destroy = true
}
tags = {
Name = "cf-${var.infra_env}-eip"
Project = "cf.io"
Environment = var.infra_env
VPC = aws_vpc.vpc.id
ManagedBy = "terraform"
Role = "private"
}
}
resource "aws_nat_gateway" "ngw" {
for_each = var.private_subnet_numbers
subnet_id = each.value.id #aws_subnet.public[each.key].id
allocation_id = aws_eip.nat[each.key].id
tags = {
Name = "cf-${var.infra_env}-ngw"
Project = "cf.io"
VPC = aws_vpc.vpc.id
Environment = var.infra_env
ManagedBy = "terraform"
Role = "private"
}
}
Error:
Error: Invalid index
│
│ on ../terraform/modules/networking/gateways.tf line 42, in resource "aws_nat_gateway" "ngw":
│ 42: allocation_id = aws_eip.nat[each.key].id
│ ├────────────────
│ │ aws_eip.nat is tuple with 2 elements
│ │ each.key is "us-east-1a"
│
│ The given key does not identify an element in this collection value: a number is required.
╵
╷
│ Error: Invalid index
│
│ on ../terraform/modules/networking/gateways.tf line 42, in resource "aws_nat_gateway" "ngw":
│ 42: allocation_id = aws_eip.nat[each.key].id
│ ├────────────────
│ │ aws_eip.nat is tuple with 2 elements
│ │ each.key is "us-east-1b"
│
│ The given key does not identify an element in this collection value: a number is required.
As Mark B mentioned mixing the count
and for_each
is not recommended. In your current setup using exclusively for_each
is the way to go based on the private_subnet_numbers
variable.
In your aws_eip.nat
resource change count
to for_each
resource "aws_eip" "nat" {
for_each = var.private_subnet_numbers
vpc = true
}
Next in your resource aws_nat_gateway.ngw
you should refer to subnet ids
using each
resource "aws_nat_gateway" "ngw" {
for_each = var.private_subnet_numbers
subnet_id = aws_subnet.public[each.key].id
....
}
And the code as a whole for clarity
resource "aws_vpc" "vpc" {
... vpc configurations ...
}
resource "aws_subnet" "public" {
for_each = var.private_subnet_numbers
vpc_id = aws_vpc.vpc.id
... subnet configurations ...
}
resource "aws_eip" "nat" {
for_each = var.private_subnet_numbers
vpc = true
lifecycle {
# prevent_destroy = true
}
tags = {
Name = "cf-${var.infra_env}-eip"
Project = "cf.io"
Environment = var.infra_env
VPC = aws_vpc.vpc.id
ManagedBy = "terraform"
Role = "private"
}
}
resource "aws_nat_gateway" "ngw" {
for_each = var.private_subnet_numbers
subnet_id = aws_subnet.public[each.key].id
allocation_id = aws_eip.nat[each.key].id
tags = {
Name = "cf-${var.infra_env}-ngw"
Project = "cf.io"
VPC = aws_vpc.vpc.id
Environment = var.infra_env
ManagedBy = "terraform"
Role = "private"
}
}