Using Terraform variables, how can I output a CIDR block for each availability zone in a region?
I can get close, but I’m obviously missing something with the cidrsubnet function.
[for az in data.aws_availability_zones.available.names : cidrsubnet("10.0.0.0/16", 8, 101)]
My current output is –
[
"10.0.101.0/24",
"10.0.101.0/24",
"10.0.101.0/24",
"10.0.101.0/24"
]
What I desire is –
[
"10.0.101.0/24",
"10.0.102.0/24",
"10.0.103.0/24",
"10.0.104.0/24"
]
Example Code
data "aws_ami" "app_ami" {
most_recent = true
filter {
name = "name"
values = ["bitnami-tomcat-*-x86_64-hvm-ebs-nami"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["979382823631"] # Bitnami
}
data "aws_availability_zones" "available" {
state = "available"
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = data.aws_availability_zones.available.names
public_subnets = [for az in data.aws_availability_zones.available.names : cidrsubnet("10.0.0.0/16", 8, 101)]
enable_nat_gateway = true
}
resource "aws_instance" "blog" {
ami = data.aws_ami.app_ami.id
instance_type = "t3.nano"
vpc_security_group_ids = [module.blog_security_group.security_group_id]
tags = {
Name = "HelloWorld"
}
}
module "blog_security_group" {
source = "terraform-aws-modules/security-group/aws"
version = "5.1.0"
name = "blog"
description = "Allow HTTP and HTTPS from my IP in."
vpc_id = data.aws_vpc.default.id
ingress_rules = ["http-80-tcp", "https-443-tcp"]
ingress_cidr_blocks = ["0.0.0.0/0"]
egress_rules = ["all-all"]
egress_cidr_blocks = ["0.0.0.0/0"]
}
3
Answers
I’ve tested this and it works for me using Terraform version 1.5.3
It sounds like you want to create a list depending on how many elements are present in
data.aws_availability_zones.available.names
, in which case you can use:One tricky aspect of a design like this is that AWS availability zones are not inherently ordered, and the zones available to your account could potentially change over time in ways that might renumber previously-allocated subnets, which would be very disruptive.
To avoid such problems, a typical approach is to preallocate a subnet number to each possible availability zone letter, and then sparsely populate your address space with only the subnets corresponding to availability zones that are really available in your account. For example:
local.available_zone_cidr_blocks
will then be a map from availability zone to generated CIDR prefix address, such as:Notice that in this example
us-east-1b
isn’t available and so it’s left10.0.0.102/24
unassigned. Ifus-east-1b
were to become available later then it could be allocated10.0.0.102/24
without renumbering anything else. Ifus-east-1c
were to become unavailable later then10.0.0.103/24
would become vacant butus-east-1d
would stay allocated to"10.0.0.104/24"
rather than being reallocated to"10.0.0.103/24"
, preventing disruption to objects in that availability zone.