How to List All Allocated IP Addresses in an AWS Subnet (Including NLB and Hidden Allocations)


10 views

When working with AWS subnets, you might encounter situations where the AWS console shows fewer available IPs than expected. This discrepancy often occurs because:

  • AWS reserves 5 IP addresses in every subnet (first 4 and last 1)
  • Network Load Balancers consume IP addresses invisibly
  • Elastic Network Interfaces (ENIs) might hold IPs even when not attached
  • VPC endpoints and other AWS services consume IPs silently

The most comprehensive way to check IP allocations is through AWS CLI. Here's a complete command sequence:


# First, get your subnet ID
aws ec2 describe-subnets --query 'Subnets[*].[SubnetId,CidrBlock]' --output table

# Then check all network interfaces in the subnet
aws ec2 describe-network-interfaces \
  --filters Name=subnet-id,Values=subnet-12345678 \
  --query 'NetworkInterfaces[*].[PrivateIpAddress,Description]' \
  --output table

# For VPC endpoints
aws ec2 describe-vpc-endpoints \
  --filters Name=subnet-id,Values=subnet-12345678 \
  --query 'VpcEndpoints[*].[NetworkInterfaceIds]' \
  --output text

# For Network Load Balancers (requires ELBv2)
aws elbv2 describe-load-balancers \
  --query 'LoadBalancers[?Type==network].[LoadBalancerArn]' \
  --output text | xargs -I {} aws elbv2 describe-target-groups \
  --load-balancer-arn {} \
  --query 'TargetGroups[*].[TargetGroupArn]' \
  --output text

For a more automated approach, this Python script using Boto3 generates a full report:


import boto3
import ipaddress

def get_subnet_ips(subnet_id):
    ec2 = boto3.client('ec2')
    elbv2 = boto3.client('elbv2')
    
    # Get subnet CIDR
    subnet = ec2.describe_subnets(SubnetIds=[subnet_id])['Subnets'][0]
    cidr = subnet['CidrBlock']
    network = ipaddress.ip_network(cidr)
    
    # Get all reserved AWS IPs (first 4 + last 1)
    reserved_ips = list(network.hosts())[:4] + [list(network.hosts())[-1]]
    
    # Get ENI IPs
    eni_ips = []
    paginator = ec2.get_paginator('describe_network_interfaces')
    for page in paginator.paginate(Filters=[{'Name': 'subnet-id', 'Values': [subnet_id]}]):
        for eni in page['NetworkInterfaces']:
            for ip in eni['PrivateIpAddresses']:
                eni_ips.append(ipaddress.ip_address(ip['PrivateIpAddress']))
    
    # Get NLB IPs (requires additional permissions)
    nlb_ips = []
    for lb in elbv2.describe_load_balancers()['LoadBalancers']:
        if lb['Type'] == 'network' and lb['VpcId'] == subnet['VpcId']:
            for az in lb['AvailabilityZones']:
                if az['SubnetId'] == subnet_id:
                    nlb_ips.extend([ipaddress.ip_address(az['LoadBalancerAddresses'][0]['IpAddress'])])
    
    # Get VPC endpoint IPs
    endpoint_ips = []
    for endpoint in ec2.describe_vpc_endpoints(
        Filters=[{'Name': 'subnet-id', 'Values': [subnet_id]}]
    )['VpcEndpoints']:
        for eni_id in endpoint['NetworkInterfaceIds']:
            eni = ec2.describe_network_interfaces(NetworkInterfaceIds=[eni_id])['NetworkInterfaces'][0]
            endpoint_ips.append(ipaddress.ip_address(eni['PrivateIpAddress']))
    
    return {
        'total_ips': network.num_addresses - 2,  # Exclude network and broadcast
        'reserved': reserved_ips,
        'enis': eni_ips,
        'nlbs': nlb_ips,
        'endpoints': endpoint_ips,
        'available': network.num_addresses - 2 - len(reserved_ips) - len(eni_ips) - len(nlb_ips) - len(endpoint_ips)
    }

When the NLB wizard reports insufficient IPs despite your calculations showing availability:

  1. Run the AWS CLI commands above to identify all consumers
  2. Check for stale network interfaces (Status=available but not attached)
  3. Verify if any previous NLBs were deleted but left interfaces behind
  4. Look for VPC endpoints created in the subnet
  • Always maintain a 10-20% IP buffer in your subnets
  • Consider using AWS IPAM for enterprise-scale management
  • For NLBs, create dedicated subnets to avoid IP conflicts
  • Regularly clean up unused network interfaces

When working with AWS Network Load Balancers (NLBs), you might encounter situations where AWS claims fewer available IPs than your internal scans show. This typically happens because AWS counts all allocated IPs, not just those assigned to EC2 instances.


# Using AWS CLI to list network interfaces in a subnet
aws ec2 describe-network-interfaces \
    --filters Name=subnet-id,Values=subnet-12345678 \
    --query 'NetworkInterfaces[*].PrivateIpAddresses[*].PrivateIpAddress' \
    --output text | sort -u
  • EC2 instances (including stopped instances with persistent ENIs)
  • RDS instances and other managed services
  • Elastic Network Interfaces (ENIs) attached to NLBs/ALBs
  • VPC endpoints and interface endpoints
  • NAT gateways
  • Elastic IP associations

When the NLB wizard reports insufficient IPs but your scans show availability:

  1. Check for "hidden" ENIs with:
    
    aws ec2 describe-network-interfaces \
        --filters Name=status,Values=available \
        Name=subnet-id,Values=subnet-12345678
    
  2. Verify VPC interface endpoints:
    
    aws ec2 describe-vpc-endpoints \
        --filters Name=vpc-id,Values=vpc-12345678
    

For better visibility, consider implementing:

  • AWS IPAM (IP Address Manager) service
  • Custom scripts to track IP allocations
  • Third-party IPAM solutions integrated with AWS