AWS VPC Subnet Creation Error: Why ‘10.8.0.0/24’ is Invalid Within ‘10.0.0.0/16’ CIDR Block


2 views

When working with AWS VPCs, a common misunderstanding arises around how subnet CIDR blocks relate to the parent VPC's CIDR. Many assume that any IP range numerically within the VPC's range is valid, but that's not how AWS's subnet validation works.

AWS performs strict binary validation where the subnet's CIDR must be a proper subset of the VPC CIDR. For '10.0.0.0/16', valid subnets must have their first 16 bits identical to the VPC's.

VPC CIDR:     10.0.00000000.00000000/16
Valid subnet: 10.0.XXXXXX.XXXXXXXX/17-28
Invalid:      10.8.00000000.00000000/24 (bits 9-16 differ)

These would work within '10.0.0.0/16':

10.0.1.0/24
10.0.128.0/20
10.0.0.0/17

Let's examine why '10.8.0.0/24' fails:

VPC:    00001010.00000000.00000000.00000000 (10.0.0.0)
Subnet: 00001010.00001000.00000000.00000000 (10.8.0.0)
                ^^^^^^^^ - These bits differ from VPC

If you need subnets in different octets, you must:

  1. Create a VPC with larger CIDR (e.g., '10.0.0.0/8')
  2. Use AWS CLI to verify CIDR compatibility first:
aws ec2 describe-subnets \
--filters "Name=vpc-id,Values=vpc-123456" \
--query "Subnets[].CidrBlock"

Watch for these in your Terraform configurations:

# Wrong
resource "aws_subnet" "bad_example" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.8.0.0/24" # Will fail
}

# Correct
resource "aws_subnet" "good_example" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.1.0/24" # Valid
}

For complex networks, associate additional CIDR blocks with your VPC:

aws ec2 associate-vpc-cidr-block \
--vpc-id vpc-123456 \
--cidr-block "10.8.0.0/16"

When working with AWS VPCs, many developers assume that any subnet whose CIDR falls numerically within the VPC's main CIDR block should work. However, the actual validation rules are more nuanced. Let's examine why 10.8.0.0/24 fails within 10.0.0.0/16 VPC.

The fundamental issue lies in how CIDR blocks are mathematically evaluated. A /16 VPC means:

VPC CIDR: 10.0.0.0/16
Binary:   00001010.00000000.00000000.00000000
Mask:     /16 means first 16 bits are fixed

Your attempted subnet 10.8.0.0/24:

Subnet:   00001010.00001000.00000000.00000000
Problem:  The 2nd octet (8 = 00001000) changes bits within the /16 mask

Here are valid subnet creations within 10.0.0.0/16:

# AWS CLI valid examples
aws ec2 create-subnet --vpc-id vpc-123456 --cidr-block 10.0.1.0/24
aws ec2 create-subnet --vpc-id vpc-123456 --cidr-block 10.0.128.0/20

The key misunderstanding is thinking that "10.8.x.x" is numerically within "10.0.0.0-10.0.255.255" range. However, AWS validates that:

  • The subnet must exactly match the VPC's fixed prefix bits
  • For 10.0.0.0/16, only the 3rd and 4th octets can vary

Here's correct Terraform code for subnet creation:

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "valid" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.8.0/24"  # This works - only varies after /16
}

Use this Python function to validate subnets before creation:

import ipaddress

def is_valid_subnet(vpc_cidr, subnet_cidr):
    vpc_net = ipaddress.IPv4Network(vpc_cidr)
    subnet_net = ipaddress.IPv4Network(subnet_cidr)
    return subnet_net.subnet_of(vpc_net) and \
           str(subnet_net).startswith(str(vpc_net.network_address))