All writing

Reserved subnet addresses across AWS, Azure and Google Cloud

The same IPv4 CIDR block does not provide the same assignable capacity across AWS, Azure and Google Cloud. Understanding provider-reserved addresses, range types, minimum subnet sizes and service consumption prevents deceptively small capacity mistakes.

about 20 minutes min read

A /24 contains 256 IPv4 address positions.

That fact does not change when I move from AWS to Azure or Google Cloud.

32 - 24 = 8 host bits

2^8 = 256 addresses

What changes is the number of addresses the platform lets me assign.

AWS subnet:

256 raw
- 5 provider-reserved
= 251 provider-assignable


Azure subnet:

256 raw
- 5 provider-reserved
= 251 provider-assignable


Google Cloud primary range:

256 raw
- 4 provider-reserved
= 252 provider-assignable


Google Cloud secondary range:

256 raw
- 0 subnet-edge reservations
= 256 provider-assignable

That final number is still not application capacity.

A managed service may allocate network interfaces, retain warm addresses, divide a range into blocks or require room for upgrades and replacement.

CIDR tells me how many address positions exist. The provider tells me which positions I may assign. The consuming service tells me how efficiently those positions become useful capacity. The operating model tells me how much must remain free.

Those are separate calculations.

A /24 does not mean 256 hosts.

It means 256 address positions before the platform and workload have applied their rules.

Four capacity terms

I use four terms throughout this article.

Raw capacity:
    every address position in the CIDR block

Provider-assignable capacity:
    raw capacity minus subnet-level provider reservations

Service-allocatable capacity:
    capacity remaining after service-specific allocation rules

Practical free capacity:
    capacity remaining after allocations, static holds and headroom

This gives a more useful planning sequence:

CIDR prefix
    │
    ▼
raw capacity
    │
    ▼
provider-assignable capacity
    │
    ▼
service-allocatable capacity
    │
    ▼
practical free capacity

The comparison table

The raw CIDR count is identical across the providers. The provider-assignable count is not.

Prefix Raw addresses AWS subnet Azure subnet Google Cloud primary Google Cloud secondary
/29 8 Not supported 3 4 8
/28 16 11 11 12 16
/27 32 27 27 28 32
/26 64 59 59 60 64
/25 128 123 123 124 128
/24 256 251 251 252 256
/23 512 507 507 508 512
/22 1,024 1,019 1,019 1,020 1,024

The formulas are:

Raw:
    2^(32 - prefix)

AWS:
    raw - 5

Azure:
    raw - 5

Google Cloud primary:
    raw - 4

Google Cloud secondary:
    raw

These are subnet-level figures. They do not promise one application instance, Pod or endpoint per address.

Scope: IPv4 capacity

This article focuses on IPv4 because losing four or five positions can materially change the usefulness of a small subnet.

An IPv4 /24 contains 256 positions. An IPv6 /64 contains 18,446,744,073,709,551,616.

IPv6 still has provider-specific subnet and delegation rules, but the capacity problem is not the same. IPv6 allocation deserves separate treatment rather than being described as larger IPv4 subnetting.

Why clouds reserve subnet addresses

Traditional IPv4 subnetting gives special meaning to the first and final positions.

For:

10.40.8.0/28

the range is:

10.40.8.0 - 10.40.8.15

The traditional special positions are:

10.40.8.0     network address
10.40.8.15    final or broadcast address

A traditional usable-host calculation is therefore:

16 total - 2 = 14

Public-cloud virtual networks also need addresses for routing, DNS and platform functions. Each provider reserves additional positions according to its own network model.

That matters when I am:

  • sizing a small subnet
  • selecting a static private address
  • moving an appliance between clouds
  • comparing Kubernetes capacity
  • validating reusable infrastructure as code
  • reserving upgrade and failover headroom

The numerical difference may be one address. At the edge of a small subnet, one address can decide whether a deployment fits.

AWS: first four and last

AWS reserves the first four IPv4 addresses and the last address in every ordinary VPC subnet.

For:

10.40.8.0/28

the reservations are:

Address Purpose
10.40.8.0 Network address
10.40.8.1 VPC router
10.40.8.2 Reserved for DNS-related platform use
10.40.8.3 Reserved for future use
10.40.8.15 Final address; reserved although VPC broadcast is unsupported

The provider-assignable range is:

10.40.8.4 - 10.40.8.14

Therefore:

16 raw - 5 reserved = 11 provider-assignable

AWS permits ordinary IPv4 VPC subnet prefixes from /28 to /16 and canonicalises a supplied subnet address to the network boundary. The .2 reservation exists in every subnet range even when the Amazon-provided DNS server is associated with the VPC’s primary CIDR.

The formula is:

AWS provider-assignable capacity
= 2^(32 - prefix) - 5

This is capacity before EC2 interfaces, load balancers, NAT gateways, interface endpoints, databases, EKS nodes, Pods and replacement capacity consume addresses.

Official source: AWS subnet CIDR blocks.

Azure: the same count, a different platform

Azure also reserves the first four IPv4 addresses and the last address in each VNet subnet.

For:

10.40.8.0/28

the reservations are:

Address Purpose
10.40.8.0 Network address
10.40.8.1 Default gateway
10.40.8.2 Azure DNS mapping
10.40.8.3 Azure DNS mapping
10.40.8.15 Broadcast address

The provider-assignable range is:

10.40.8.4 - 10.40.8.14

Therefore:

16 raw - 5 reserved = 11 provider-assignable

Azure supports IPv4 subnets as small as /29. A /29 contains eight positions, leaving three after Azure’s five reservations.

Azure provider-assignable capacity
= 2^(32 - prefix) - 5

Matching AWS’s arithmetic does not make the network platforms interchangeable. Azure services can require dedicated subnets, specific names and larger minimum prefixes. A subnet may contain enough provider-assignable addresses for a resource count and still fail the service contract.

Official sources:

Google Cloud primary ranges: first two and last two

A Google Cloud subnet has a primary IPv4 range and can also have secondary IPv4 ranges.

For the primary range, Google Cloud reserves the first two and last two addresses.

Using:

10.40.8.0/28

the reservations are:

Address Purpose
10.40.8.0 Network address
10.40.8.1 Virtual default gateway
10.40.8.14 Reserved for potential future use
10.40.8.15 Broadcast address

The provider-assignable range is:

10.40.8.2 - 10.40.8.13

Therefore:

16 raw - 4 reserved = 12 provider-assignable

The formula is:

Google Cloud primary provider-assignable capacity
= 2^(32 - prefix) - 4

The virtual gateway does not respond to ICMP echo requests and does not appear as an ordinary router hop in traceroute. A gateway ping should not be used as proof that the subnet is healthy.

Google Cloud secondary ranges: no subnet-edge reservations

Google Cloud lets customers use every address in a secondary IPv4 range. It does not remove the first two and last two positions as it does for a primary range.

For a /28 secondary range:

16 raw
- 0 subnet-edge reservations
= 16 provider-assignable

Primary and secondary ranges therefore behave differently even when their prefixes match:

Google Cloud primary /28:
    12 provider-assignable

Google Cloud secondary /28:
    16 provider-assignable

Both primary and secondary ranges can be as small as /29.

All positions being provider-assignable does not mean all become running Pods or application endpoints. A service can allocate the range in larger units and consider an entire unit allocated before every address inside it is active.

Official source: Google Cloud VPC subnets.

Small subnets magnify the reservation

Five addresses are negligible inside a /16:

65,536 - 5 = 65,531

They remove nearly one-third of a /28:

16 - 5 = 11
Prefix Raw Five reserved Unavailable Four reserved Unavailable
/24 256 5 1.95% 4 1.56%
/26 64 5 7.81% 4 6.25%
/28 16 5 31.25% 4 25%
/29 8 5 62.5% 4 50%

This is why the statement below fails:

The service needs eight addresses.
A /29 contains eight addresses.
Therefore a /29 is enough.

Across the providers:

AWS /29:
    not a valid VPC subnet

Azure /29:
    3 provider-assignable

Google Cloud primary /29:
    4 provider-assignable

Google Cloud secondary /29:
    8 provider-assignable

The smallest provider-supported range is not necessarily a useful service subnet.

Minimums and service contracts

There are several different minimums:

CIDR mathematical minimum

provider platform minimum

cloud-service minimum

workload capacity minimum

operational headroom minimum

The design must satisfy the largest one.

Platform Smallest ordinary IPv4 subnet or range
AWS VPC subnet /28
Azure VNet subnet /29
Google Cloud primary IPv4 range /29
Google Cloud secondary IPv4 range /29

Managed services can impose larger minimums or require dedicated subnets. Those requirements can also change independently of the underlying VNet or VPC rules, so they belong in service-specific validation rather than a universal subnet formula.

A requirement for at least 60 addresses

Suppose an application needs capacity for at least 60 assignable IPv4 addresses. Ignore growth and replacement for the first calculation.

AWS and Azure

A /26 contains 64 positions:

64 - 5 = 59 provider-assignable

It fails. The next larger block is a /25:

128 - 5 = 123 provider-assignable

Google Cloud primary

A /26 provides:

64 - 4 = 60 provider-assignable

It fits mathematically.

Google Cloud secondary

A /26 provides all 64 positions at the provider-assignment layer.

Provider or range /26 provider-assignable Meets 60?
AWS 59 No
Azure 59 No
Google Cloud primary 60 Mathematically
Google Cloud secondary 64 Mathematically

The mathematical answer is not yet the design answer.

I still need to ask:

  • Is 60 the steady state or maximum?
  • Are addresses needed during replacement or upgrades?
  • Do load balancers or endpoints consume additional interfaces?
  • Can the service retain addresses after scale-down?
  • Does the allocator reserve blocks rather than individual addresses?
  • What growth is expected?

A Google Cloud primary /26 with exactly 60 assigned addresses has no room for the next endpoint or an unusual deployment afternoon. A /25 may therefore be sensible across all three clouds, not because every platform must imitate AWS, but because the workload needs headroom.

Kubernetes changes the allocation unit

Provider reservations are only the first layer of Kubernetes capacity planning.

Amazon EKS

With the Amazon VPC CNI, Pods receive VPC addresses through elastic network interfaces attached to nodes. The CNI also maintains warm ENIs, addresses or prefixes so Pods can start quickly.

The subnet therefore needs room for:

nodes
Pod addresses
CNI warm allocations
load-balancer interfaces
rolling replacements
autoscaling

An AWS /24 provides 251 provider-assignable addresses. It does not safely support 251 nodes or 251 Pods.

Official source: Amazon VPC CNI best practices.

Azure Kubernetes Service

AKS capacity depends on the networking model.

Azure CNI Overlay assigns node addresses from the VNet subnet while Pod addresses come from a separate Pod CIDR. Flat models assign Pod addresses from VNet subnets, including models with separate node and Pod subnets.

The same Azure /24 can therefore support very different cluster sizes depending on whether only nodes, or nodes and Pods, consume VNet subnet addresses.

Official source: AKS CNI networking overview.

Google Kubernetes Engine

VPC-native GKE commonly uses:

primary range:
    node addresses

secondary range:
    Pod addresses

secondary or GKE-managed range:
    Service addresses

By default, a Standard cluster can allocate a /24 Pod alias range to each node to support up to 110 Pods. GKE considers the complete node CIDR allocated even when individual addresses inside it are not assigned to Pods.

This separates two questions:

How many addresses did the subnet platform reserve?

How does GKE divide the provider-assignable range?

The first answer is zero for a secondary range. The second can still create substantial allocation overhead.

Official sources:

The useful Kubernetes comparison is not simply which cloud reserves the fewest addresses. It is:

Which objects consume addresses?

From which range?

In what allocation unit?

During which scaling, upgrade and recovery conditions?

Static addresses and migration

Provider-specific reserved positions can break a migration even when the CIDR itself is unchanged.

Suppose a virtual appliance uses:

10.40.8.2

inside a Google Cloud primary range.

That position can be assigned because Google Cloud reserves .0, .1, the second-to-last and the last address.

Move the design to AWS or Azure and .2 is provider-reserved.

Google Cloud primary:
    10.40.8.2 can be provider-assignable

AWS:
    10.40.8.2 is reserved

Azure:
    10.40.8.2 is reserved

A migration can therefore fail even when the subnet, routes and security rules are otherwise correct.

A provider-neutral convention such as allocating ordinary static addresses from base + 10 reduces that risk, but it deliberately gives up some low addresses. The value of that trade-off depends on subnet size, IPv4 scarcity, appliance requirements and the likelihood of migration.

Portability has an address cost.

Multi-cloud planning without erasing platform differences

One response to these differences is to subtract five everywhere. Another is to use /24 everywhere.

Both are simple. Neither is always good design.

A stronger approach separates shared planning concepts from provider-specific implementation.

Shared planning language

required address consumers
non-overlap
growth
deployment surge
failure and replacement headroom
environment and availability boundaries

Provider implementation

reserved positions
minimum subnet size
dedicated-subnet requirements
primary and secondary ranges
Kubernetes networking model
resizing behaviour

A planning record might look like this:

subnet:
  name: application-a
  environment: production
  region: provider-region
  availability_boundary: zone-a
  purpose: kubernetes-workloads

capacity:
  current_consumers: 80
  deployment_surge: 20
  failover_headroom: 20
  growth_reserve: 40
  required_assignable: 160

provider:
  name: aws
  range_type: vpc-subnet
  subnet_edge_reservations: 5

allocation:
  prefix: 24
  raw_capacity: 256
  provider_assignable: 251
  planned_free_after_requirement: 91

For Google Cloud, the range type must be explicit:

provider:
  name: google-cloud
  range_type: secondary
  subnet_edge_reservations: 0

For Kubernetes, I would also record:

service_consumption:
  consumer: kubernetes
  node_range: primary
  pod_range: secondary
  service_range: provider-specific
  allocation_unit: provider-specific
  maximum_nodes: calculated
  maximum_pods_per_node: configured

The shared document records architectural intent. The provider section records platform truth.

A focused capacity function

A planning tool can encode the subnet-level arithmetic without pretending to understand every managed service.

This version uses Enum rather than StrEnum, so it also works on Python versions before 3.11.

from enum import Enum


class SubnetModel(str, Enum):
    AWS = "aws"
    AZURE = "azure"
    GOOGLE_CLOUD_PRIMARY = "google-cloud-primary"
    GOOGLE_CLOUD_SECONDARY = "google-cloud-secondary"


SUBNET_EDGE_RESERVATIONS = {
    SubnetModel.AWS: 5,
    SubnetModel.AZURE: 5,
    SubnetModel.GOOGLE_CLOUD_PRIMARY: 4,
    SubnetModel.GOOGLE_CLOUD_SECONDARY: 0,
}


def provider_assignable_ipv4_addresses(
    prefix: int,
    model: SubnetModel,
) -> int:
    if not 0 <= prefix <= 32:
        raise ValueError("IPv4 prefix must be between 0 and 32")

    raw_capacity = 2 ** (32 - prefix)
    provider_assignable = (
        raw_capacity - SUBNET_EDGE_RESERVATIONS[model]
    )

    if provider_assignable < 0:
        raise ValueError(
            "Subnet-edge reservations exceed raw CIDR capacity"
        )

    return provider_assignable

For a /26:

aws 59
azure 59
google-cloud-primary 60
google-cloud-secondary 64

The function calculates one layer accurately. It does not approve a subnet.

It still does not know:

  • whether the provider accepts the prefix
  • whether a service requires a larger or dedicated subnet
  • how Kubernetes allocates addresses
  • whether an appliance uses multiple interfaces
  • whether surge and recovery capacity are included
  • whether the range overlaps another network

Those checks belong in separate validation rules.

The design checklist

Area Question
Raw capacity How many address positions does the CIDR contain?
Provider and range Which cloud and range type implement it?
Reservations Which exact positions are provider-reserved?
Minimums Does the platform and service accept this prefix?
Consumers Which resources, interfaces, Pods or blocks consume addresses?
Allocation unit Are addresses allocated individually or in larger units?
Resilience What is needed during upgrades, replacement and failure?
Static addressing Does any resource depend on a provider-specific position?
Monitoring Am I measuring assignable, allocated or actively used addresses?
Growth How much capacity must remain after the first deployment?

The mental model

The weak model is:

/24
= 256 addresses
= 256 resources

The stronger model is:

CIDR prefix
    │
    ▼
raw capacity
    │
    ▼
provider reservations
    │
    ▼
provider-assignable capacity
    │
    ▼
service allocation model
    │
    ▼
active allocations and static holds
    │
    ▼
surge, recovery and growth headroom
    │
    ▼
practical free capacity

AWS and Azure reserve five addresses in an ordinary IPv4 subnet.

Google Cloud primary ranges reserve four.

Google Cloud secondary ranges have no subnet-edge reservations.

Those differences are worth knowing, but they are not the whole capacity plan.

The useful number is the capacity left after the platform, the service and the operating model have all taken their share.

The binary has done its job.

Now the platform gets a vote.

References and further reading

Verified against official documentation on 30 July 2026.

AWS

Microsoft Azure

Google Cloud