I have 3 private and 3 public subnets, and I want to create either 1 or 2 NAT Gateways depending on the environment.
So, for dev
and staging
there should be 1 NAT Gateway, and for production
two.
Since I can’t use for_each
with subnets as it is one more than I need, I decided to create the Elastic IPs with count
.
resource "aws_eip" "elastic_ip" {
count = var.environment == "stg" ? 1 : 2
vpc = true
tags = merge(var.tags, {
Name = "eip-${var.name_suffix}-${count.index}"
Description = "Terraform Managed Elastic IP"
Project = var.project
Environment = var.environment
})
}
Now I want to create the NAT Gateways depending on the number of Elastic IPs created, like this:
resource "aws_nat_gateway" "nat_gw" {
for_each = aws_eip.elastic_ip
allocation_id = each.value.id
subnet_id = CHALLENGE 2
tags = merge(var.tags, {
Name = "nat-gw-${var.name_suffix}"
Description = "Terraform Managed NAT Gateway"
Project = var.project
Environment = var.environment
})
}
but here I have two challenges.
- it complaints about
aws_eip.elastic_ip
being a tuple. I have tried usingtoset()
, but it didn’t work - I need to dynamically pull the IDs of two out of three subnets.
Is this actually possible without extra locals
or variables
?
UPDATE
Here the code for subnets. I have two of this; one for private subnets and this one for public.
resource "aws_subnet" "public_subnet" {
for_each = var.public_subnet
availability_zone = each.value["az"]
cidr_block = each.value["cidr"]
vpc_id = aws_vpc.vpc.id
tags = merge(var.tags, {
Name = "public-subnet-${var.name_suffix}"
Description = "Terraform Managed Subnet"
Project = var.project
Environment = var.environment
AZ = each.value["az"]
})
}
And I’m passing a variable with the region
and cidr
blocks:
public_subnet = {
subnet_a = {
az = "eu-west-1a"
cidr = "10.10.0.0/24"
}
subnet_b = {
az = "eu-west-1b"
cidr = "10.10.1.0/24"
}
subnet_c = {
az = "eu-west-1c"
cidr = "10.10.2.0/24"
}
}
2
Answers
You can use count in
aws_nat_gateway.nat_gw
too and access theaws_eip.elastic_ip
resource with an index like this:aws_eip.elastic_ip[count.index]
.This would look something like this:
Another option might be to use the splat expression combined with
toset
. But I think terraform will complain because it cannot determine the values ofaws_eip.elastic_ip
until after the apply.But I still wanted to mention it and it would look like this:
After making some changes and playing around with the code, this example should work:
It does not provide much of the dynamic functionality you are probably aiming for, but the rest should work.
A bit more dynamic approach:
where the
public_subnet
would have to change to have a value:NOTE: the NAT Gateway should probably be in the public subnet(s), not private ones.