How Your AWS VPC IP Utilization Report Could Save Your Next Deployment

There’s a failure mode that catches even experienced cloud engineers off guard. A deployment pipeline runs flawlessly through staging, clears every gate, and then dies in production with a cryptic error: “There are not enough free addresses in the subnet ‘xyz’ to satisfy your request.” No dramatic alarm. No advance warning. Just a hard stop at the worst possible moment.

EC2 Launch Failure Error
EC2 Launch Failure Error

The root cause is almost always the same: nobody was tracking IP address utilization inside their AWS VPCs.

This article walks through why IP utilization reporting matters, how AWS counts addresses, how to calculate what you actually have, and what factors you need to account for before the numbers surprise you in production.

Why IP Utilization Reporting Matters

An AWS Virtual Private Cloud (VPC) is a logically isolated network. Every resource you launch inside it — EC2 instances, Lambda functions on VPC, RDS databases, NAT Gateways, load balancers, EKS pods, ECS tasks — consumes one or more private IP addresses from the subnets you have defined.

Unlike a public cloud address space where scale feels infinite, VPC subnets are hard-bounded. A /24 subnet has 256 addresses. A /28 has 16. Once those are gone, nothing new can launch in that subnet until something is released.

The consequences of running out of IPs are severe:

  • Auto Scaling Groups silently fail to launch replacement instances during a fault, leaving you under-provisioned when you need capacity most.
  • EKS node groups stall mid-rollout, leaving a cluster in a degraded state with half the intended nodes.
  • RDS Multi-AZ failovers fail if the standby AZ subnet has no room for the promoted instance.
  • CI/CD pipelines break at the deploy stage after passing all prior stages, wasting pipeline minutes and engineer time.
  • Incident response is slower because engineers diagnosing a production failure now also have to diagnose a networking constraint they didn’t know existed.

None of these failures announce themselves in advance. They happen the moment a resource tries to acquire an address that isn’t there. A proactive IP utilization report turns an invisible constraint into a visible metric you can act on before it becomes an incident.

On the flip side, over-allocation of IP space is a common phenomenon as well. Before you know it, the whole /15 (131,072) or /16 (65,536) IP allocation is exhausted. As a part of regular housekeeping, it is important to clean up unused VPCs and rightsize the over-allocated ones. You may be surprised to discover how application owners can be overly cautious to request excessive margin in IP space. In some cases, they may be unaware of the application architecture and required IP count to support it. A proper gatekeeping can keep help design right-sized VPCs. You can’t simply shrink a VPC’s IP allocation to reclaim the unused.

How AWS Counts IP Addresses

Before you can calculate utilization, you need to understand AWS’s reservation rules.

The Five Reserved Addresses Per Subnet

AWS automatically reserves five IP addresses in every subnet, regardless of its size. For a subnet with CIDR 10.0.1.0/24:

Address Reserved For
10.0.1.0 Network address
10.0.1.1 VPC router
10.0.1.2 DNS server (VPC base + 2)
10.0.1.3 Future AWS use
10.0.1.255 Broadcast (not used, but reserved)

This means a /24 gives you 251 usable addresses, not 256. A /28 gives you 11, not 16. This distinction matters most at small prefix sizes — a /28 loses nearly a third of its address space to reservations.

Consumable IPs by Prefix Length

CIDR Prefix Total Addresses AWS Reserved Usable (Provisioned)
/16 65,536 5 65,531
/20 4,096 5 4,091
/21 2048 5 2043
/22 1024 5 1019
/23 512 5 507
/24 256 5 251
/25 128 5 123
/26 64 5 59
/27 32 5 27
/28 16 5 11

The Three Numbers That Matter

Every IP utilization report should track three values per subnet and roll them up per VPC:

Provisioned IPs  =  2^(32 – prefix_length) – 5

Available IPs    =  Reported by AWS in real time (AvailableIpAddressCount)

Used IPs         =  Provisioned – Available

And the derived metric:

Utilization %  =  (Used / Provisioned) × 100

How to Read AvailableIpAddressCount

AWS exposes AvailableIpAddressCount on every subnet through the EC2 API. This is a live count — it decreases the moment a network interface is assigned an address and increases the moment one is released. It is the most accurate signal you have for real-time availability.

Bash Shell:

aws ec2 describe-subnets \

  –filters “Name=vpc-id,Values=vpc-0e123abc456defxyz” \

  –query ‘Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AvailableIps:AvailableIpAddressCount, Name:Tags[?Key==`Name`]| [0].Value}’

 

Combining that live number with the calculated provisioned count gives you utilization without any guesswork.

What Consumes IPs (More Than You Think)

The first thing most people think of is EC2 instances. But IP consumption in a modern AWS environment is far broader.

1) Primary Network Interfaces

Every EC2 instance gets one primary ENI with one primary private IP. That’s the baseline. But many workloads attach additional interfaces or additional IPs per interface.

2) Secondary and Alias IPs

EC2 instances support multiple private IPs per ENI. Some applications bind to multiple addresses. Elastic IPs still consume a private IP from the subnet in addition to the public address.

3) EKS and Container Networking

This is the single biggest surprise for teams moving to Kubernetes on AWS. The AWS VPC CNI plugin (the default EKS networking mode) assigns a real VPC IP address to every pod, not just every node. A single /24 subnet with 251 usable addresses can fill up with pods alone — especially with smaller instance types that have lower ENI limits, since the CNI pre-warms ENIs by allocating IPs speculatively.

For EKS clusters, plan your subnets an order of magnitude larger than you think you need, or use prefix delegation(assigning /28 blocks to nodes rather than individual IPs) to extend subnet capacity significantly.

4) RDS and ElastiCache

Each RDS instance consumes at least one IP. Multi-AZ deployments consume one per AZ. Read replicas consume additional IPs. ElastiCache clusters consume one per node.

5) Load Balancers

Application Load Balancers and Network Load Balancers consume IPs from the subnets they are placed in — one per AZ, per load balancer. A highly available ALB spanning three AZs consumes three IPs from your subnet allocation.

6) NAT Gateways

Each NAT Gateway consumes one IP in its subnet.

7) VPC Endpoints and PrivateLink

Interface VPC endpoints (for services like S3, ECR, Secrets Manager) consume one IP per AZ they’re deployed into. A single endpoint across three AZs consumes three IPs.

8) Lambda on VPC

Lambda functions attached to a VPC consume IPs from the subnet. At high concurrency, this can be significant — though AWS has introduced Hyperplane ENIs to reduce the per-function IP cost, the consumption is not zero.

9) Transit Gateway Attachments

Each Transit Gateway attachment to a VPC consumes one IP per subnet used for the attachment.

10) Cloud WAN Attachments

Each Cloud WAN attachment to a VPC consumes one IP per subnet used for the attachment.

Factors to Consider in Your Utilization Report

Raw numbers tell you where you are. Context tells you whether to act.

1) Growth Trajectory

A subnet at 60% utilization is fine today. If your EKS cluster is growing by 15% a month, you may have three months before it becomes a problem. Your report should include a trend over time, not just a point-in-time snapshot.

2) Subnet Role and Traffic Pattern

Transit subnets, management subnets, and data plane subnets have very different consumption profiles. A /28 is appropriate for a management subnet hosting a handful of bastion hosts. It is catastrophically undersized for a pod subnet.

3) AZ Symmetry

AWS does not balance resources across Availability Zones automatically in all cases. If Auto Scaling prefers one AZ due to spot pricing or capacity, that AZ’s subnets can become exhausted while the others remain largely empty. Report utilization per subnet, not just per VPC.

3) Reserved Headroom for Failover

If a subnet is at 80% utilization under normal load, a failover event that doubles the instance count in that subnet will immediately exhaust it. Design for peak failover load, not steady-state load.

IPAM and Secondary CIDRs

AWS VPC IPAM (IP Address Manager) allows you to add secondary CIDR blocks to a VPC when the primary space is running low. If you’re approaching exhaustion, a secondary CIDR block buys time — but it adds operational complexity and should be planned, not scrambled for during an incident.

Thresholds Worth Acting On

As a practical starting point for alert thresholds:

Utilization

Recommended Action

< 60%

Healthy — monitor on a regular schedule

60–75%

Review growth trend; plan subnet expansion timeline

75–85%

Plan and schedule expansion; raise with infrastructure team

85–90%

Immediate planning required; restrict non-critical launches

> 90%

Critical — add capacity or restrict new deployments now

These thresholds should be tighter for subnets serving Auto Scaling workloads or EKS pods, where consumption can spike rapidly and without warning.

Building the Report

A minimal IP utilization report needs to answer five questions for every subnet:

  1. What is the subnet’s CIDR and therefore its provisioned IP count?
  2. How many IPs are currently available?
  3. How many are in use, and what is the utilization percentage?
  4. What workload type does this subnet serve?
  5. Is utilization trending up, stable, or down?

The AWS CLI and SDKs give you everything needed to answer the first three. Tagging strategy answers the fourth — subnets tagged with their role (public, private, data, transit, management) make it trivial to segment your report by workload type. CloudWatch metrics and scheduled Lambda functions can answer the fifth by storing historical snapshots.

At the VPC level, roll up the per-subnet numbers to give a total provisioned, used, and available count across all subnets in that VPC. This gives leadership and platform teams a single number per VPC without losing the subnet-level detail needed for operational decisions.

Assumption Made

  1. Consumable IPs per subset = Provisioned IPs (per subnet IP prefix) – 5 (IP overhead per subnet)
  2. Free IP as AWS subnet metric (AvailableIpAddressCount)
  3. Transit subnet excluded from consumable IPs as it is strictly used for Transit Gateway or Cloud WAN attachment in my use case.
    • Transit Subnet Size:  /28
    • Transit Subnet Name:  <Corp>-<Env>-<WorkLoad>-<Category>-<Region>-transit-<AZ>
    • Example-1:    agill-dev-asset-reporting-app-use1-transit-a
    • Example-2:   agill-prod-log-aggregation-infra-usw2-transit-c
  4. Firewall subnet is excluded from consumable IPs as it is strictly used for Palo Alto Cloud NGFW Endpoint deployment in my test case.
    • Firewall Subnet Size: /28
    • Firewall Subnet Name:  <Corp>-<Env>-<WorkLoad>-<Category>-<Region>transit-<AZ>
    • Example:   agill-qa-inspection-infra-euc2-firewall-c

Please remember to update the script to reflect your use case and subnet naming standards. Transit and Firewall subnets are off-limits for Application workloads in my scenario. Based on my assumptions, I filtered out these subnets as in snippet below. Feel free to enhance the script by querying the VPC attachment and subnets specified for it. Same way, firewall deployment can be easily verified by additional CLI commands API calls

if [[ "$SUBNET_NAME" =~ -transit-[abcd]?$ && "${SUBNET_CIDR: -2}" == "28" ]] ; then
   #echo "transit subnet found, skipping addition to total consumable and total available"
   SUBNET_SKIPPED=true
elif [[ "$SUBNET_NAME" =~ -firewall-[abcd]?$ && "${SUBNET_CIDR: -2}" == "28" ]] ; then
   #echo "firewall subnet found, skipping addition to total consumable and total available"
   SUBNET_SKIPPED=true

How to Run Report

You can run it in a variety of ways.

  1. Download the script.
  2. Run the provided script “as is” in AWS Cloud Shell. You either same the script into a file or simply copy paste into shell prompt.
    • ./vpc-report.sh > vpc-report.csv
    • copay and past the script into shel prompt.
  3. Run from a Linux EC2. AWS CLI, jq and EC2 Role with proper ReadOnly permissions will be required. Amazon Linux 2023 comes with preinstalled AWS CLI. g
  4. Embed the script into a Lambda with “Amazon Linux 2023” runtime.
  5. Port the logic into  Python and use with it with Lambda runtime.
  6. Distribute the output file via S3 bucket, an email distribution list and any other form of fire share.
  7. CSV file can be opened into MS Excel or Mac Numbers for easy viewing.
  8. The last column “percentage free” can be easily converted into “percentage utilized:
    • if [ "$TOTAL_CONSUMABLE" -ne 0 ]; then
      PERCENT_FREE=$((TOTAL_AVAILABLE * 100 / TOTAL_CONSUMABLE))  #what's in the script now
      PERCENT_UTILIZED=$(((TOTAL_CONSUMABLE-TOTAL_AVAILABLE) * 100 / TOTAL_CONSUMABLE))  #can be updated to this

It will generate comma separated values like following.

vpc-0a123abd456xyz789,agill-dev-integration-euc2-vpc,10.10.255.64/27,11,1,9%
vpc-0b123abd456xyz789,agill-dev-security-euc2-vpc,10.10.192.0/24,162,161,99%
vpc-0c123abd456xyz789,agill-dev-reporting-euc2-vpc,10.10.57.0/24,162,140,86%
vpc-0d123abd456xyz789,agill-dev-finance-euc2-vpc,10.10.226.0/23,408,313,76%
vpc-0e123abd456xyz789,agill-dev-marketing-euc2-vpc,10.10.219.0/24,66,66,100%
vpc-0f123abd456xyz789,agill-dev-sales-euc2-vpc,10.10.255.0/27,11,0,0%

Download Script File

vpc-ip-report.sh

The Takeaway

IP address space inside an AWS VPC is a finite resource with no built-in guardrails. AWS will not warn you when you’re running low. It will simply refuse to launch the next resource that needs an address.

The teams that avoid IP exhaustion incidents aren’t the ones with the biggest CIDR blocks — they’re the ones that treat IP utilization as a first-class operational metric, report on it regularly, and act on it before the threshold becomes a crisis. A well-built utilization report costs a few hours to build and saves potentially hours of incident response, failed deployments, and emergency re-architecture.

Start with the numbers. Know your subnets. Know your headroom.

References

Subnet CIDR blocks and Reserved IPs

AWS command line tools & Amazon Linux 2

Installing, updating, and uninstalling the AWS CLI

Installing JQ on Amazon Linux 2

AWS CLI: describesubnets

AWS CLI: describe-vpcs

Tagged: AWS, VPC, Networking, Cloud Infrastructure, DevOps, Site Reliability, IP Management

Previous Article

Leave a Reply

Your email address will not be published. Required fields are marked *