Skip to content

(aws-ec2): Support IPAM CIDR allocation in L2 Subnet construct #34296

Open
@betchi207

Description

@betchi207

Describe the feature

The L2 construct Subnet currently does not support IPAM CIDR allocation, while the L1 construct CfnSubnet already supports it. This feature request proposes to add IPAM support to the L2 construct to provide a more consistent and user-friendly experience.

Current Behavior

  • L1 construct (CfnSubnet) supports IPAM CIDR allocation
  • L2 construct (Subnet) only supports direct CIDR specification
  • VPC level IPAM support exists but subnet level support is missing

Proposed Solution

The L2 Subnet construct should be enhanced to support IPAM allocation through a new property in SubnetProps:

new ec2.Subnet(stack, 'MySubnet', {
  vpcId: vpc.vpcId,
  availabilityZone: 'us-east-1a',
  ipamAllocation: {
    ipamPoolId: 'ipam-pool-123',
    netmaskLength: 24
  }
});

Implementation Details

  • Add ipamAllocation property to SubnetProps interface
  • Update Subnet construct to handle IPAM configuration
  • Add validation for IPAM and CIDR mutual exclusivity
  • Add integration with VPC-level IPAM settings
  • Add comprehensive test coverage
  • Update documentation

Use Case

I'm always frustrated when trying to use IPAM for subnet CIDR allocation in a CDK application. While the VPC construct supports IPAM, individual subnets do not, forcing us to:

  1. Either use L1 constructs directly, losing the benefits of L2 abstractions
  2. Or manually manage CIDR blocks, defeating the purpose of using IPAM

This feature would allow us to:

  • Maintain consistent IP address management across our infrastructure
  • Leverage IPAM's centralized control at both VPC and subnet levels
  • Keep using the convenient L2 constructs while benefiting from IPAM features

Proposed Solution

Proposed Solution

The implementation will involve the following changes:

  1. Update SubnetProps interface in packages/aws-cdk-lib/aws-ec2/lib/subnet.ts:
export interface SubnetProps {
  // ... existing properties ...

  /**
   * IPAM allocation configuration
   * If specified, cidrBlock must not be set
   * @default - no IPAM allocation
   */
  readonly ipamAllocation?: {
    /**
     * The ID of the IPAM pool to allocate the CIDR from
     */
    readonly ipamPoolId: string;

    /**
     * The netmask length for the CIDR
     * Must be a value between 16 and 28
     */
    readonly netmaskLength: number;
  };
}
  1. Update Subnet class implementation:
export class Subnet extends Resource implements ISubnet {
  constructor(scope: Construct, id: string, props: SubnetProps) {
    super(scope, id);

    if (props.ipamAllocation && props.cidrBlock) {
      throw new Error('Cannot specify both ipamAllocation and cidrBlock');
    }

    const subnet = new CfnSubnet(this, 'Resource', {
      vpcId: props.vpcId,
      availabilityZone: props.availabilityZone,
      // ... other properties ...
      
      // Add IPAM properties when specified
      ...(props.ipamAllocation && {
        ipv4IpamPoolId: props.ipamAllocation.ipamPoolId,
        ipv4NetmaskLength: props.ipamAllocation.netmaskLength
      })
    });

    // ... rest of the implementation ...
  }
}
  1. Add test cases in packages/aws-cdk-lib/aws-ec2/test/subnet.test.ts:
test('subnet with ipam allocation', () => {
  const stack = new Stack();
  new Subnet(stack, 'Subnet', {
    vpcId: 'vpc-123',
    availabilityZone: 'us-east-1a',
    ipamAllocation: {
      ipamPoolId: 'ipam-pool-123',
      netmaskLength: 24
    }
  });

  Template.fromStack(stack).hasResourceProperties('AWS::EC2::Subnet', {
    VpcId: 'vpc-123',
    AvailabilityZone: 'us-east-1a',
    Ipv4IpamPoolId: 'ipam-pool-123',
    Ipv4NetmaskLength: 24
  });
});

test('cannot specify both cidrBlock and ipamAllocation', () => {
  const stack = new Stack();
  expect(() => {
    new Subnet(stack, 'Subnet', {
      vpcId: 'vpc-123',
      availabilityZone: 'us-east-1a',
      cidrBlock: '10.0.0.0/24',
      ipamAllocation: {
        ipamPoolId: 'ipam-pool-123',
        netmaskLength: 24
      }
    });
  }).toThrow(/Cannot specify both ipamAllocation and cidrBlock/);
});
  1. Update VPC integration:
export class Vpc extends Resource implements IVpc {
  private allocateSubnet(props: AllocateSubnetProps): Subnet {
    // ... existing allocation logic ...
    
    // If VPC uses IPAM, prefer VPC's IPAM settings unless subnet explicitly specifies its own
    const ipamAllocation = props.ipamAllocation ?? (this.ipamPool && {
      ipamPoolId: this.ipamPool.poolId,
      netmaskLength: this.defaultSubnetMask
    });

    return new Subnet(this, subnetId, {
      // ... other properties ...
      ipamAllocation,
    });
  }
}
  1. Documentation Updates:
  • Add new section in packages/aws-cdk-lib/aws-ec2/README.md about IPAM support
  • Update API reference documentation
  • Add examples showing IPAM usage with subnets

Backward Compatibility

This change is fully backward compatible:

  • Existing code using cidrBlock continues to work as before
  • New ipamAllocation property is optional
  • VPC-level IPAM configuration remains unchanged

Integration Testing

Will add integration tests to verify:

  • IPAM allocation works correctly at subnet creation
  • VPC and subnet level IPAM configurations work together
  • Error cases are handled appropriately

Other Information

No response

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

CDK version used

v2.192.0

Environment details (OS name and version, etc.)

macOS 15.4.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    @aws-cdk/aws-ec2Related to Amazon Elastic Compute Cloudeffort/mediumMedium work item – several days of effortfeature-requestA feature should be added or improved.p2

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions