From 4deb5d6cc1beaa3d2551e5f7fcf6a060158a37db Mon Sep 17 00:00:00 2001 From: maz Date: Sun, 22 Dec 2024 15:34:18 +0900 Subject: [PATCH] add ip address type --- .../integ.vpc-endpoint-ip-address-type.ts | 28 +++++++++ packages/aws-cdk-lib/aws-ec2/README.md | 12 ++++ .../aws-cdk-lib/aws-ec2/lib/vpc-endpoint.ts | 44 +++++++++++++- .../aws-ec2/test/vpc-endpoint.test.ts | 57 +++++++++++++++++++ 4 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-ec2/test/integ.vpc-endpoint-ip-address-type.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-ec2/test/integ.vpc-endpoint-ip-address-type.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-ec2/test/integ.vpc-endpoint-ip-address-type.ts new file mode 100644 index 0000000000000..f3d6327f388ae --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-ec2/test/integ.vpc-endpoint-ip-address-type.ts @@ -0,0 +1,28 @@ +import { App, Stack } from 'aws-cdk-lib/core'; +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; + +const app = new App(); +const stack = new Stack(app, 'VpcEndpointIpAddressTypeStack'); + +const vpc = new ec2.Vpc(stack, 'DualStackVpc', { + ipProtocol: ec2.IpProtocol.DUAL_STACK, +}); + +vpc.addInterfaceEndpoint('IPv4', { + privateDnsEnabled: false, + service: ec2.InterfaceVpcEndpointAwsService.BEDROCK, + subnets: { subnetType: ec2.SubnetType.PUBLIC }, + ipAddressType: ec2.IpAddressType.IPV4, +}); + +vpc.addInterfaceEndpoint('IPv6', { + privateDnsEnabled: false, + service: ec2.InterfaceVpcEndpointAwsService.S3_TABLES, + subnets: { subnetType: ec2.SubnetType.PUBLIC }, + ipAddressType: ec2.IpAddressType.IPV6, +}); + +new IntegTest(app, 'VpcEndpointIpAddressTypeTest', { + testCases: [stack], +}); diff --git a/packages/aws-cdk-lib/aws-ec2/README.md b/packages/aws-cdk-lib/aws-ec2/README.md index 8bbdf160355bd..b3db94c3490a7 100644 --- a/packages/aws-cdk-lib/aws-ec2/README.md +++ b/packages/aws-cdk-lib/aws-ec2/README.md @@ -1078,6 +1078,18 @@ new ec2.InterfaceVpcEndpoint(this, 'VPC Endpoint', { }); ``` +You can choose ip address type by setting `ipAddressType` property: + +```ts +declare const vpc: ec2.Vpc; + +new ec2.InterfaceVpcEndpoint(this, 'VPC Endpoint', { + vpc, + service: ec2.InterfaceVpcEndpointAwsService.EC2, + ipAddressType: ec2.IpAddressType.IPV6, // ip address type +}); +``` + #### Security groups for interface VPC endpoints By default, interface VPC endpoints create a new security group and all traffic to the endpoint from within the VPC will be automatically allowed. diff --git a/packages/aws-cdk-lib/aws-ec2/lib/vpc-endpoint.ts b/packages/aws-cdk-lib/aws-ec2/lib/vpc-endpoint.ts index 58f46b4f3dc67..c8396b323f246 100644 --- a/packages/aws-cdk-lib/aws-ec2/lib/vpc-endpoint.ts +++ b/packages/aws-cdk-lib/aws-ec2/lib/vpc-endpoint.ts @@ -756,7 +756,7 @@ export interface InterfaceVpcEndpointOptions { readonly securityGroups?: ISecurityGroup[]; /** - * Whether to automatically allow VPC traffic to the endpoint + * Whether to automatically allow VPC traffic to the endpoint when ipAddressType is IPv4 or Dual-stack. * * If enabled, all traffic to the endpoint from within the VPC will be * automatically allowed. This is done based on the VPC's CIDR range. @@ -774,6 +774,43 @@ export interface InterfaceVpcEndpointOptions { * @default false */ readonly lookupSupportedAzs?: boolean; + + /** + * The supported IP address types. + * + * @default IpAddressType.IPV4 + */ + readonly ipAddressType?: IpAddressType; +} + +/** + * The supported IP address types. + * + * @see https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html#create-interface-endpoint-aws + */ +export enum IpAddressType { + /** + * Assign IPv4 addresses to the endpoint network interfaces. + * This option is supported only if all selected subnets have IPv4 address ranges and the service accepts IPv4 requests. + */ + IPV4 = 'ipv4', + + /** + * Assign IPv6 addresses to the endpoint network interfaces. + * This option is supported only if all selected subnets are IPv6 only subnets and the service accepts IPv6 requests. + */ + IPV6 = 'ipv6', + + /** + * Assign both IPv4 and IPv6 addresses to the endpoint network interfaces. + * This option is supported only if all selected subnets have both IPv4 and IPv6 address ranges and the service accepts both IPv4 and IPv6 requests. + */ + DUAL_STACK = 'dualstack', + + /** + * not specified + */ + NOT_SPECIFIED = 'not-specified', } /** @@ -878,7 +915,9 @@ export class InterfaceVpcEndpoint extends VpcEndpoint implements IInterfaceVpcEn }); if (props.open !== false) { - this.connections.allowDefaultPortFrom(Peer.ipv4(props.vpc.vpcCidrBlock)); + if (props.ipAddressType === undefined || [IpAddressType.IPV4, IpAddressType.DUAL_STACK].includes(props.ipAddressType)) { + this.connections.allowDefaultPortFrom(Peer.ipv4(props.vpc.vpcCidrBlock)); + } } // Determine which subnets to place the endpoint in @@ -892,6 +931,7 @@ export class InterfaceVpcEndpoint extends VpcEndpoint implements IInterfaceVpcEn vpcEndpointType: VpcEndpointType.INTERFACE, subnetIds, vpcId: props.vpc.vpcId, + ipAddressType: props.ipAddressType, }); this.vpcEndpointId = endpoint.ref; diff --git a/packages/aws-cdk-lib/aws-ec2/test/vpc-endpoint.test.ts b/packages/aws-cdk-lib/aws-ec2/test/vpc-endpoint.test.ts index 6faa231a475dd..6e5a5f77170a9 100644 --- a/packages/aws-cdk-lib/aws-ec2/test/vpc-endpoint.test.ts +++ b/packages/aws-cdk-lib/aws-ec2/test/vpc-endpoint.test.ts @@ -4,6 +4,7 @@ import * as cxschema from '../../cloud-assembly-schema'; import { ContextProvider, Fn, Stack } from '../../core'; // eslint-disable-next-line max-len import { GatewayVpcEndpoint, GatewayVpcEndpointAwsService, InterfaceVpcEndpoint, InterfaceVpcEndpointAwsService, InterfaceVpcEndpointService, SecurityGroup, SubnetFilter, SubnetType, Vpc } from '../lib'; +import { IpAddressType } from '../lib/vpc-endpoint'; describe('vpc endpoint', () => { describe('gateway endpoint', () => { @@ -954,5 +955,61 @@ describe('vpc endpoint', () => { VpcEndpointType: 'Interface', }); }); + + test.each([ + IpAddressType.IPV4, + IpAddressType.IPV6, + IpAddressType.DUAL_STACK, + IpAddressType.NOT_SPECIFIED, + ])('test vpc interface endpoint when ip address type is %s.', (ipAddressType) => { + //GIVEN + const stack = new Stack(undefined, 'TestStack', { env: { account: '123456789012', region: 'us-west-2' } }); + const vpc = new Vpc(stack, 'VPC'); + + //WHEN + vpc.addInterfaceEndpoint('EC2 Endpoint', { + service: InterfaceVpcEndpointAwsService.EC2, + privateDnsEnabled: false, + ipAddressType, + }); + + //THEN + Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpoint', { + ServiceName: 'com.amazonaws.us-west-2.ec2', + VpcId: stack.resolve(vpc.vpcId), + PrivateDnsEnabled: false, + VpcEndpointType: 'Interface', + IpAddressType: ipAddressType, + }); + }); + + test.each([ + IpAddressType.IPV4, + IpAddressType.DUAL_STACK, + ])('test security group with vpc interface endpoint when ip address type is %s.', (ipAddressType) => { + //GIVEN + const stack = new Stack(undefined, 'TestStack', { env: { account: '123456789012', region: 'us-west-2' } }); + const vpc = new Vpc(stack, 'VPC'); + + //WHEN + vpc.addInterfaceEndpoint('EC2 Endpoint', { + service: InterfaceVpcEndpointAwsService.EC2, + privateDnsEnabled: false, + ipAddressType, + open: true, + }); + + //THEN + Template.fromStack(stack).hasResourceProperties('AWS::EC2::SecurityGroup', { + SecurityGroupIngress: [ + { + CidrIp: stack.resolve(vpc.vpcCidrBlock), + FromPort: 443, + IpProtocol: 'tcp', + ToPort: 443, + }, + ], + }); + }); }); });