Skip to content

Commit

Permalink
fix issue of subnet ip check with ipam range
Browse files Browse the repository at this point in the history
  • Loading branch information
shikha372 committed Oct 15, 2024
1 parent 5db5f0c commit 4ced705
Show file tree
Hide file tree
Showing 9 changed files with 870 additions and 79 deletions.
11 changes: 11 additions & 0 deletions packages/@aws-cdk/aws-ec2-alpha/lib/ipam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ export interface IIpamPool{
*/
readonly ipamCidrs: CfnIPAMPoolCidr[];

/**
* Pool CIDR for IPv4 to be provisioned
*/
readonly ipamIpv4Cidrs?: string[];

/**
* Function to associate a IPv6 address with IPAM pool
*/
Expand Down Expand Up @@ -315,6 +320,11 @@ class IpamPool extends Resource implements IIpamPool {
*/
public readonly ipamCidrs: CfnIPAMPoolCidr[] = []

/**
* Pool CIDR for IPv4 to be provisioned
*/
public readonly ipamIpv4Cidrs: string[] = []

/**
* Reference to ipamPool resource created in this class
*/
Expand All @@ -340,6 +350,7 @@ class IpamPool extends Resource implements IIpamPool {
awsService: props.awsService,
});
this.ipamPoolId = this._ipamPool.attrIpamPoolId;
props.ipv4ProvisionedCidrs?.map(cidr => (this.ipamIpv4Cidrs.push(cidr)));
this.node.defaultChild = this._ipamPool;
}

Expand Down
43 changes: 39 additions & 4 deletions packages/@aws-cdk/aws-ec2-alpha/lib/subnet-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Construct, DependencyGroup, IDependable } from 'constructs';
import { IVpcV2 } from './vpc-v2-base';
import { CidrBlock, CidrBlockIpv6 } from './util';
import { RouteTable } from './route';
import { error } from 'console';

/**
* Interface to define subnet CIDR
Expand Down Expand Up @@ -476,9 +475,35 @@ function validateSupportIpv6(vpc: IVpcV2) {
* @returns True if the CIDR range falls within the VPC's IP address ranges, false otherwise.
* @internal
*/
// function checkCidrRanges(vpc: IVpcV2, cidrRange: string) {

// const vpcCidrBlock = [vpc.ipv4CidrBlock];

// if (vpc.secondaryCidrBlock) {
// for (const ipAddress of vpc.secondaryCidrBlock) {
// if (ipAddress.cidrBlock) {
// vpcCidrBlock.push(ipAddress.cidrBlock);
// }
// }
// const cidrs = vpcCidrBlock.map(cidr => new CidrBlock(cidr));

// const subnetCidrBlock = new CidrBlock(cidrRange);

// return cidrs.some(c => c.containsCidr(subnetCidrBlock));
// }
// if (vpc.ipv4ProvisionedCidrs) {

// const cidrs = vpc.ipv4ProvisionedCidrs.map(cidr => new CidrBlock(cidr));

// const subnetCidrBlock = new CidrBlock(cidrRange);

// return cidrs.some(c => c.containsCidr(subnetCidrBlock));
// } else {throw error('No secondary IP address attached to VPC');}
// }
function checkCidrRanges(vpc: IVpcV2, cidrRange: string) {

const vpcCidrBlock = [vpc.ipv4CidrBlock];
const allCidrs: CidrBlock[] = [];

if (vpc.secondaryCidrBlock) {
for (const ipAddress of vpc.secondaryCidrBlock) {
Expand All @@ -487,11 +512,21 @@ function checkCidrRanges(vpc: IVpcV2, cidrRange: string) {
}
}
const cidrs = vpcCidrBlock.map(cidr => new CidrBlock(cidr));
allCidrs.push(...cidrs);
}

if (vpc.ipv4ProvisionedCidrs) {

const cidrs = vpc.ipv4ProvisionedCidrs.map(cidr => new CidrBlock(cidr));
allCidrs.push(...cidrs);
}
if (allCidrs.length === 0) {
throw new Error('No secondary IP address attached to VPC');
}

const subnetCidrBlock = new CidrBlock(cidrRange);
const subnetCidrBlock = new CidrBlock(cidrRange);

return cidrs.some(c => c.containsCidr(subnetCidrBlock));
} else {throw error('No secondary IP address attached to VPC');}
return allCidrs.some(c => c.containsCidr(subnetCidrBlock));
}

/**
Expand Down
7 changes: 7 additions & 0 deletions packages/@aws-cdk/aws-ec2-alpha/lib/vpc-v2-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ export interface IVpcV2 extends IVpc {
*/
readonly ipv4CidrBlock: string;

/**
* IPv4 CIDR provisioned under pool
* Required to check for overlapping CIDRs after provisioning
* is complete under IPAM pool
*/
readonly ipv4ProvisionedCidrs?: string[];

/**
* Add an Egress only Internet Gateway to current VPC.
* Can only be used for ipv6 enabled VPCs.
Expand Down
127 changes: 86 additions & 41 deletions packages/@aws-cdk/aws-ec2-alpha/lib/vpc-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Arn, CfnResource, Lazy, Names, Resource, Stack } from 'aws-cdk-lib/core
import { Construct, DependencyGroup, IDependable } from 'constructs';
import { IpamOptions, IIpamPool } from './ipam';
import { IVpcV2, VpcV2Base } from './vpc-v2-base';
import { ISubnetV2, ImportedSubnetV2, SubnetV2Attributes } from './subnet-v2';
import { ISubnetV2, ImportedSubnetV2, SubnetV2Attributes } from './subnet-v2';;

/**
* Additional props needed for secondary Address
Expand Down Expand Up @@ -112,6 +112,14 @@ export interface VpcCidrOptions {
* @default - no name for primary addresses
*/
readonly cidrBlockName?: string;

/**
* IPv4 CIDR provisioned under pool
* Required to check for overlapping CIDRs after provisioning
* is complete under IPAM pool
* @default - no IPAM IPv4 CIDR range is provisioned using IPAM
*/
readonly ipv4ProvisionedCidrs?: string[];
}

/**
Expand Down Expand Up @@ -233,7 +241,7 @@ export interface VpcV2Attributes {
* Import Secondary CIDR blocks associated with VPC
* @default - No secondary IP address
*/
readonly secondaryCidrBlocks?: VPCCidrBlockProps[];
readonly secondaryCidrBlocks?: VPCCidrBlockattributes[];

}

Expand Down Expand Up @@ -315,10 +323,17 @@ export class VpcV2 extends VpcV2Base {
public readonly internetConnectivityEstablished: IDependable;

/**
* reference to all secondary blocks attached
*/
* reference to all secondary blocks attached
*/
public readonly secondaryCidrBlock?: IVPCCidrBlock[] = new Array<IVPCCidrBlock>;

/**
* IPv4 CIDR provisioned under pool
* Required to check for overlapping CIDRs after provisioning
* is complete under IPAM pool
*/
public readonly ipv4ProvisionedCidrs?: string[];

/**
* For validation to define IPv6 subnets, set to true in case of
* Amazon Provided IPv6 cidr range
Expand Down Expand Up @@ -385,15 +400,17 @@ export class VpcV2 extends VpcV2Base {
throw new Error('CIDR block should be in the same RFC 1918 range in the VPC');
}
}
// const cfnVpcCidrBlock = new CfnVPCCidrBlock(this, secondaryVpcOptions.cidrBlockName, {
// vpcId: this.vpcId,
// cidrBlock: secondaryVpcOptions.ipv4CidrBlock,
// ipv4IpamPoolId: secondaryVpcOptions.ipv4IpamPool?.ipamPoolId,
// ipv4NetmaskLength: secondaryVpcOptions.ipv4NetmaskLength,
// ipv6NetmaskLength: secondaryVpcOptions.ipv6NetmaskLength,
// ipv6IpamPoolId: secondaryVpcOptions.ipv6IpamPool?.ipamPoolId,
// amazonProvidedIpv6CidrBlock: secondaryVpcOptions.amazonProvided,
// });

if (secondaryVpcOptions.ipv4ProvisionedCidrs!) {
let isOverlap;
for (const provisionedCidr of secondaryVpcOptions.ipv4ProvisionedCidrs) {
isOverlap = validateIpv4address(provisionedCidr, secondaryVpcOptions.ipv4CidrBlock);
}
if (isOverlap === false) {
throw new Error('CIDR block should be in the same RFC 1918 range in the VPC');
}
this.ipv4ProvisionedCidrs?.push(...secondaryVpcOptions.ipv4ProvisionedCidrs);
}
const cfnVpcCidrBlock = new VPCCidrBlock(this, secondaryVpcOptions.cidrBlockName, {
vpcId: this.vpcId,
cidrBlock: secondaryVpcOptions.ipv4CidrBlock,
Expand Down Expand Up @@ -510,6 +527,7 @@ class IpamIpv4 implements IIpAddresses {
ipv4NetmaskLength: this.props.netmaskLength,
ipv4IpamPool: this.props.ipamPool,
cidrBlockName: this.props?.cidrBlockName,
ipv4ProvisionedCidrs: this.props.ipamPool?.ipamIpv4Cidrs,
};
}
}
Expand All @@ -534,6 +552,9 @@ class ImportedVpcV2 extends VpcV2Base {

public readonly vpcCidrBlock: string;

// required to do CIDR range test on imported VPCs to create new subnets
public readonly ipv4ProvisionedCidrs: string[] = [];

constructor(scope: Construct, id: string, props: VpcV2Attributes) {
super(scope, id, {
region: props. region,
Expand All @@ -548,15 +569,22 @@ class ImportedVpcV2 extends VpcV2Base {
this.ipv4CidrBlock = props.vpcCidrBlock;
this._vpnGatewayId = props.vpnGatewayId; //TODO if we need it for other gateways
if (props.publicSubnets) {
this.publicSubnets = props.publicSubnets.map(subnet => new ImportedSubnetV2(scope, 'ImportedPublicSubnet', subnet));
this.publicSubnets = props.publicSubnets.map(subnet => new ImportedSubnetV2(scope, subnet.subnetName?? 'ImportedPublicSubnet', subnet));
}
if (props.privateSubnets) {
this.privateSubnets = props.privateSubnets.map(subnet => new ImportedSubnetV2(scope, 'ImportedPrivateSubnet', subnet));
this.privateSubnets = props.privateSubnets.map(subnet => new ImportedSubnetV2(scope, subnet.subnetName?? 'ImportedPrivateSubnet', subnet));
}
if (props.isolatedSubnets) {
this.isolatedSubnets = props.isolatedSubnets.map(subnet => new ImportedSubnetV2(scope, 'ImportedPrivateSubnet', subnet));
this.isolatedSubnets = props.isolatedSubnets.map(subnet => new ImportedSubnetV2(scope, subnet.subnetName?? 'ImportedIsolatedSubnet', subnet));
}
this.secondaryCidrBlock = props.secondaryCidrBlocks?.map(cidrBlock => VPCCidrBlock.fromVPCCidrBlockattributes(scope, cidrBlock.cidrBlockName ?? 'ImportedSecondaryCidrBlock', { ...cidrBlock }));
if (props.secondaryCidrBlocks) {
for (const cidr of props.secondaryCidrBlocks) {
if (cidr.ipv4ProvisionedCidrs) {
this.ipv4ProvisionedCidrs.push(...cidr.ipv4ProvisionedCidrs);
}
}
}
this.secondaryCidrBlock = props.secondaryCidrBlocks?.map(cidrBlock => VPCCidrBlock.fromVPCCidrBlockattributes(scope, cidrBlock.cidrBlockName ?? 'ImportedSecondaryCidrBlock', cidrBlock));
}
}

Expand Down Expand Up @@ -603,13 +631,10 @@ function validateIpv4address(cidr1?: string, cidr2?: string): boolean {
}

/**
* Interface VPCCidrBlock
* Attributes for VPCCidrBlock used for defining a new VPCCIDRBlock
* and also importing an existing VPCCIDRBlock
*/
export interface VPCCidrBlockProps {
/**
* The VPC Id
*/
readonly vpcId: string;
export interface VPCCidrBlockattributes {

/**
* The secondary IPv4 CIDR Block
Expand All @@ -618,40 +643,60 @@ export interface VPCCidrBlockProps {
readonly cidrBlock?: string;

/**
* CIDR Block Name
* @default - no CIDR Block name generated, this field is required while importing CIDR block for VPC
*/
* CIDR Block Name
* @default - no CIDR Block name generated, this field is required while importing CIDR block for VPC
*/
readonly cidrBlockName?: string;

/**
* Opt for amazonProvided Ipv6 CIDR address
* @default false
*/
* Opt for amazonProvided Ipv6 CIDR address
* @default false
*/
readonly amazonProvidedIpv6CidrBlock?: boolean;

/**
* IPAM pool Id for IPv6 address type
* @default - no IPAM pool Id provided
*/
* IPAM pool Id for IPv6 address type
* @default - no IPAM pool Id provided
*/
readonly ipv6IpamPoolId?: string;

/**
* IPAM pool Id for IPv4 address type
* @default - no IPAM pool Id provided
*/
* IPAM pool Id for IPv4 address type
* @default - no IPAM pool Id provided
*/
readonly ipv4IpamPoolId?: string;

/**
* Net mask length for IPv4 address type
* @default - no Net mask length configured and it would fail the deployment
*/
* Net mask length for IPv4 address type
* @default - no Net mask length configured and it would fail the deployment
*/
readonly ipv4NetmaskLength?: number;

/**
* Net mask length for IPv6 address type
* @default - no Net mask length configured and it would fail the deployment
* IPv4 CIDR provisioned under pool
* Required to check for overlapping CIDRs after provisioning
* is complete under IPAM pool
* @default - no IPAM IPv4 CIDR range is provisioned using IPAM
*/
readonly ipv4ProvisionedCidrs?: string[];

/**
* Net mask length for IPv6 address type
* @default - no Net mask length configured and it would fail the deployment
*/
readonly ipv6NetmaskLength?: number;

}

/**
* Interface VPCCidrBlock
*/
interface VPCCidrBlockProps extends VPCCidrBlockattributes {
/**
* The VPC Id
*/
readonly vpcId: string;

}

/**
Expand All @@ -660,7 +705,7 @@ export interface VPCCidrBlockProps {
*/
class VPCCidrBlock extends Resource implements IVPCCidrBlock {

public static fromVPCCidrBlockattributes(scope: Construct, id: string, props: VPCCidrBlockProps) : IVPCCidrBlock {
public static fromVPCCidrBlockattributes(scope: Construct, id: string, props: VPCCidrBlockattributes) : IVPCCidrBlock {
class Import extends Resource implements IVPCCidrBlock {
public readonly cidrBlock = props.cidrBlock;
public readonly amazonProvidedIpv6CidrBlock ?: boolean = props.amazonProvidedIpv6CidrBlock;;
Expand Down
Loading

0 comments on commit 4ced705

Please sign in to comment.