Search code examples
amazon-web-servicesterraformcidr

Terraform next available CIDR on AWS


I would like to see if it is possible for our Terraform code to programmatically figure out the next CIDR to use for a VPC.

VPC CIDR range 172.20.1-255.0/24

What I have so far:

data "aws_vpcs" "existing_vpcs" {

}

data "aws_vpc" "details" {
  count = "${length(data.aws_vpcs.existing_vpcs.ids)}"
  id = "${element(data.aws_vpcs.existing_vpcs.ids, count.index)}"
}

output "all_vpc_ids" {
  value = "${data.aws_vpcs.existing_vpcs.ids}"
}
output "current_vpc_cidrs" {
  value = "${data.aws_vpc.details.*.cidr_block}"
}
output "Current VPCs" {
  value = "${length(data.aws_vpcs.existing_vpcs.ids)}"
}

This will output something like this:

Outputs:

Current VPCs = 8
all_vpc_ids = [
    vpc-xxx,
    vpc-xxx,
]
current_vpc_cidrs = [
    172.20.1.0/24,
    172.20.5.0/24,
]

I would like to set a variable to 172.20.2.0/24 since it is technically the next available.


Solution

  • Terraform's data sources feature is intended to fetch data that changes infrequently and (usually) changes only as a result of deliberate action on behalf of an operator. The next "available" CIDR block is, unfortunately, not a good candidate for that because the act of creating the next VPC would change the result, causing the resulting configuration to never converge.

    Terraform instead expects this sort of assignment to be made explicitly. In this situation, that would mean establishing an explicit numbering convention for your networks which you can then describe in the Terraform configuration, allowing Terraform to find or calculate a suitable VPC based on information already available in the configuration.

    For example, AWS users often define a mapping such that each region and regional availability zone is assigned a number in a central table (e.g. a map value directly in the configuration, or an external system accessed via a data source) and then the address for a VPC or subnet can be discovered by consulting that table.

    If your system has the more unusual characteristic of networks being regularly created and destroyed with no direct relation to AWS regions and availability zones, I'd suggest using some external software outside of Terraform to manage the assignment of subnets and then passing the decision made by that software into Terraform as an input variable. That way the decision can be recorded in that external system (e.g. in a database) and recalled again later if changes need to be applied.

    Users with unusual use-cases also sometimes find it better to factor out the main part of their configuration into a re-usable module and then dynamically generate (using a preprocessing tool) a minimal root module that calls that module using some data or decisions made outside of Terraform. This sort of usage is not within Terraform's primary use-cases, but it can be made to work. For very dynamic environments, Terraform may not be the right tool for the job.