terraform: How to calculate subnets using the cidrsubnet function

3 min read | by Jordi Prats

If we are using terraform for creating subnets on AWS we are going to need to split the VPC's network range into several pieces, one for each AZ. We can let terraform handle all the details by using the cidrsubnet() function

The cidrsubnet function needs three arguments:

cidrsubnet(prefix, newbits, netnum)

These arguments are:

  • prefix: It's the network range we want to use as a base in CIDR notation
  • newbits: The number of bits we want to use for the range. For example, if the prefix is a /16 network and we want to pick slices of /24 networks we would it would be 8 (the difference)
  • netnum: An index of each of the slices, following the previous example: The network with netnum=0 for the prefix 10.12.0.0/16 slicing it on /24 ranges would be 10.12.0.0/24, with netnum=1 it would be 10.12.1.0/24 and so on.

Here you can find some example outputs:

> cidrsubnet("10.12.0.0/16", 8, 0)
"10.12.0.0/24"
> cidrsubnet("10.12.0.0/16", 8, 1)
"10.12.1.0/24"
> cidrsubnet("10.12.0.0/16", 8, 2)
"10.12.2.0/24"
> cidrsubnet("10.12.0.0/16", 8, 3)
"10.12.3.0/24"

Circling back to being able to create one subnet for each AZ from a fixed range we can use the following terraform code:

resource "aws_subnet" "vpc_subnets" {
  for_each          = toset(var.az_subnets)

  cidr_block        = cidrsubnet(var.main_vpc_cidr_block, 8, index(var.az_subnets, each.value))
  vpc_id            = aws_vpc.server_vpc.id
  availability_zone = each.value
}

Assuming that main_vpc_cidr_block is 10.12.0.0/16 and az_subnets is an array containing the following AZs: us-west-2a, us-west-2b, us-west-2c

When running this code it will create the following aws_subnet resources:

  # module.vpc.aws_subnet.vpc_subnets["us-west-2a"] will be created
  + resource "aws_subnet" "vpc_subnets" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = "us-west-2a"
      + availability_zone_id                           = (known after apply)
      + cidr_block                                     = "10.12.0.0/24"
      (...)
    }

  # module.vpc.aws_subnet.vpc_subnets["us-west-2b"] will be created
  + resource "aws_subnet" "vpc_subnets" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = "us-west-2b"
      + availability_zone_id                           = (known after apply)
      + cidr_block                                     = "10.12.1.0/24"
      (...)
    }

  # module.vpc.aws_subnet.vpc_subnets["us-west-2c"] will be created
  + resource "aws_subnet" "vpc_subnets" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = "us-west-2c"
      + availability_zone_id                           = (known after apply)
      + cidr_block                                     = "10.12.2.0/24"
      (...)
    }

Posted on 20/04/2022

Categories