If using Python, the boto3
package along with the built-in ipaddress
module together are sufficient to list unused candidate subnets of a given prefix length for a specified VPC.
This script was tested with Python 3.9, but it should work with Python ≥3.6. Define the values of VPC_NAME
and REQUIRED_PREFIX_LEN
. It will print all relevant unused subnets of the required length, although you can choose to adapt it to print fewer. From the printed candidates, you can carefully pick the ones which minimize further fragmentation.
import ipaddress
from typing import List
import boto3
# Customize these parameters:
VPC_NAME = 'my-vpc'
REQUIRED_PREFIX_LEN = 23
# Get VPC CIDR
vpcs = boto3.client('ec2').describe_vpcs(Filters=[{'Name': 'tag:Name', 'Values': [config.EC2_VPC_NAME]}])['Vpcs']
assert len(vpcs) == 1
vpc = vpcs[0]
vpc_cidr = vpc['CidrBlock']
vpc_net = ipaddress.ip_network(vpc_cidr)
assert vpc_net.prefixlen < REQUIRED_PREFIX_LEN
print(f'VPC {VPC_NAME} has CIDR {vpc_cidr}.')
def print_subnets(networks: List, description: str) -> None:
print(f"\nThe {len(networks)} {description} subnets are: {' '.join(map(str, networks))}")
# Get used subnets
used_subnets = boto3.client('ec2').get_paginator('describe_subnets').paginate(Filters=[{'Name': 'vpc-id', 'Values': [vpc['VpcId']]}]).build_full_result()['Subnets']
used_subnets = [ipaddress.ip_network(s['CidrBlock']) for s in used_subnets]
print_subnets(used_subnets, 'used')
collapsed_used_subnets = list(ipaddress.collapse_addresses(used_subnets))
print_subnets(collapsed_used_subnets, 'collapsed used')
# Get unused subnets
unused_subnets = list(vpc_net.subnets(new_prefix=REQUIRED_PREFIX_LEN))
for used_subnet in collapsed_used_subnets:
unused_subnets = [unused_subnet for unused_subnet in unused_subnets if not unused_subnet.overlaps(used_subnet)]
print_subnets(unused_subnets, 'relevant unused')
collapsed_unused_subnets = list(ipaddress.collapse_addresses(unused_subnets))
print_subnets(collapsed_unused_subnets, 'relevant collapsed unused')
It is not an algorithmically efficient script, but unless you are doing this at scale, it doesn't have to be.