Skip to content

InsightsCloud

Planning VPC IP address space before you need it

How to size VPC CIDR blocks, keep ranges unique across accounts and on-premises networks, lay out subnet tiers, and leave room for Kubernetes pod addresses.

Published August 27, 20245 min read

IP address planning is one of the few cloud decisions that is genuinely hard to undo. Instances can be resized and services rewritten, but a VPC's primary CIDR block is fixed at creation, and every network that will ever be peered or routed to it needs a range that does not overlap.

The usual story: the first VPCs are created with the console default of 10.0.0.0/16. A year later, two of them need to talk to each other, or to the office network, and they cannot, because they use the same addresses. The fix is a migration. A few hours of planning up front avoids it.

Allocate from one plan

Treat private address space as a shared resource with an owner and a register, not something each team picks when creating a VPC. The RFC 1918 ranges give you three blocks:

RangeSizeTypical use
10.0.0.0/8About 16.7 million addressesCloud networks, split into large regional blocks
172.16.0.0/12About 1 million addressesOften already used on-premises or by Docker defaults
192.168.0.0/1665,536 addressesHome and office networks; avoid for cloud

Before allocating anything, find out what is already in use: on-premises networks, VPN client pools, partner connections, and the default bridge networks of tools like Docker. These collide with cloud ranges more often than cloud ranges collide with each other.

A hierarchical plan keeps allocation simple and routes summarizable:

organization: 10.0.0.0/8region: /12environment: /14VPC: /16 to /20subnet tiers
fig. 1 — each level carves its block from the one above, so routes summarize cleanly

For instance, 10.0.0.0/12 for eu-west-1, 10.16.0.0/12 for us-east-1, and within eu-west-1 a /14 each for production, staging and development. A Transit Gateway or on-premises router can then carry one route per region or environment instead of one per VPC.

Sizing a VPC

AWS allows VPC CIDR blocks from /16 down to /28. The temptation is to give every VPC a /16 because it is the largest. With a /8 to divide, that allows only 256 VPCs in total, across every region, environment and team. Size by what the VPC will hold instead:

  • Shared or platform VPCs running Kubernetes clusters, large fleets or many services: /16 to /18.
  • Single-workload VPCs: /20 to /22 is usually plenty.
  • Inspection, egress or endpoint VPCs: often /24 or smaller.

When unsure, err larger for VPCs that will run Kubernetes and smaller for everything else. A VPC can gain secondary CIDR blocks later, but a secondary block has to come from somewhere in the plan too, and some services only use the primary range.

Subnet tiers

Within a VPC, subnets are usually split by tier and by Availability Zone. A common layout uses three tiers in three zones:

10.20.0.0/16 in eu-west-1 (one plan)
Public      10.20.0.0/22    10.20.4.0/22    10.20.8.0/22      load balancers, NAT gateways
Private     10.20.32.0/19   10.20.64.0/19   10.20.96.0/19     workloads, nodes
Data        10.20.128.0/21  10.20.136.0/21  10.20.144.0/21    databases, caches
Reserved    10.20.152.0/21  and above                         future tiers or zones
            eu-west-1a      eu-west-1b      eu-west-1c

Some principles behind those sizes:

  • Public subnets stay small. They hold load balancer nodes and NAT gateways, not workloads.
  • Private subnets get the most space, because that is where instances, containers and pod addresses live.
  • Data subnets are separate so network ACLs and route tables can treat them differently, and so database subnet groups have their own clear ranges.
  • Leave part of the range unallocated. A fourth Availability Zone or a new tier is much easier when there is space for it.

AWS reserves five addresses in every subnet: the network address, the next three for the VPC router, DNS and future use, and the broadcast address. This only matters for very small subnets, but it is why a /28 gives 11 usable addresses rather than 16.

Room for Kubernetes pods

Amazon EKS with the default VPC CNI gives every pod an address from the VPC. A node with 30 pods uses 31 or more addresses, and the CNI pre-allocates spare addresses per node so pods start quickly. A cluster that runs out of IP addresses while it still has spare CPU and memory is a common problem.

There are three ways to deal with it, and they combine:

  • Large private subnets. A /19 per zone gives about 8,000 addresses each, which suits a medium-sized cluster.
  • Prefix delegation. Setting ENABLE_PREFIX_DELEGATION=true on the VPC CNI assigns /28 prefixes to nodes instead of individual addresses. It raises the pod density per node and reduces API calls, but it needs contiguous free /28 blocks in the subnet, so fragmented subnets cause failures.
  • Custom networking on a secondary range. Add a secondary CIDR to the VPC, often from 100.64.0.0/10, and configure the CNI with ENIConfig resources so pods draw addresses from it while nodes stay on the primary range. Because pod traffic leaving the VPC is translated to the node address by default, the secondary range can be reused in every VPC without causing routing conflicts.

IPv6 is the other answer. EKS supports IPv6 clusters, where pods get addresses from a /56 assigned to the VPC and IPv4 exhaustion stops being a concern. It is worth evaluating for new clusters, but every dependency, including on-premises systems and third-party endpoints, needs to work with it.

Keep the register in code

A spreadsheet of allocations works until two people edit it in the same week. Better options:

  • Amazon VPC IP Address Manager (IPAM) lets you define pools per region and environment, and allocate VPC CIDRs from them automatically. Terraform can request an allocation with ipv4_ipam_pool_id and ipv4_netmask_length on aws_vpc, so nobody picks a range by hand.
  • A Terraform module or data file with the allocation table, reviewed through pull requests, is a lighter-weight alternative that works across clouds.

Either way, include on-premises and partner ranges in the register, marked as reserved, so they are never handed out.

Where to start

  1. List every range in use today: VPCs in all accounts and regions, on-premises networks, VPN pools, partner links.
  2. Pick a top-level block for cloud use that overlaps none of them, and split it by region and environment.
  3. Choose standard VPC sizes, such as /16 for cluster VPCs and /20 for single-workload VPCs.
  4. Define a standard subnet layout with tiers per zone and reserved space.
  5. Decide how EKS clusters will get pod addresses: large subnets, prefix delegation, a secondary range or IPv6.
  6. Move allocation into IPAM or a reviewed code module, and stop creating VPCs with hand-picked ranges.