Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,9 @@
],
"SupportedIpAddressTypes": [
"ipv4"
],
"SupportedRegions": [
"us-east-2"
]
}
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class TestStack extends cdk.Stack {
vpcEndpointServiceLoadBalancers: [loadBalancer],
acceptanceRequired: true,
contributorInsights: true,
supportedIpAddressTypes: [ec2.IpAddressType.IPV4], // change to ipv4 and re-run
supportedIpAddressTypes: [ec2.IpAddressType.IPV4],
allowedRegions: ['us-east-2'],
});
}
}
Expand Down
12 changes: 12 additions & 0 deletions packages/aws-cdk-lib/aws-ec2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,18 @@ new ec2.VpcEndpointService(this, 'EndpointService', {
});
```

You can restrict access to your endpoint service to specific AWS regions:

```ts
declare const networkLoadBalancer: elbv2.NetworkLoadBalancer;

new ec2.VpcEndpointService(this, 'EndpointService', {
vpcEndpointServiceLoadBalancers: [networkLoadBalancer],
// Allow service consumers from these regions only
allowedRegions: ['us-east-1', 'eu-west-1'],
});
```

Endpoint services support private DNS, which makes it easier for clients to connect to your service by automatically setting up DNS in their VPC.
You can enable private DNS on an endpoint service like so:

Expand Down
13 changes: 13 additions & 0 deletions packages/aws-cdk-lib/aws-ec2/lib/vpc-endpoint-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ export class VpcEndpointService extends Resource implements IVpcEndpointService
*/
private readonly supportedIpAddressTypes?: IpAddressType[];

/**
* The Regions from which service consumers can access the service.
*/
private readonly allowedRegions?: string[];

/**
* The id of the VPC Endpoint Service, like vpce-svc-xxxxxxxxxxxxxxxx.
* @attribute
Expand Down Expand Up @@ -132,6 +137,7 @@ export class VpcEndpointService extends Resource implements IVpcEndpointService
this.acceptanceRequired = props.acceptanceRequired ?? true;
this.contributorInsightsEnabled = props.contributorInsights;
this.supportedIpAddressTypes = props.supportedIpAddressTypes;
this.allowedRegions = props.allowedRegions;

if (props.allowedPrincipals && props.whitelistedPrincipals) {
throw new Error('`whitelistedPrincipals` is deprecated; please use `allowedPrincipals` instead');
Expand All @@ -144,6 +150,7 @@ export class VpcEndpointService extends Resource implements IVpcEndpointService
acceptanceRequired: this.acceptanceRequired,
contributorInsightsEnabled: this.contributorInsightsEnabled,
supportedIpAddressTypes: this.supportedIpAddressTypes?.map(type => type.toString()),
supportedRegions: this.allowedRegions,
});

this.vpcEndpointServiceId = this.endpointService.ref;
Expand Down Expand Up @@ -220,4 +227,10 @@ export interface VpcEndpointServiceProps {
* @default - No specific IP address types configured
*/
readonly supportedIpAddressTypes?: IpAddressType[];

/**
* The Regions from which service consumers can access the service.
* @default - No Region restrictions
*/
readonly allowedRegions?: string[];
}
96 changes: 96 additions & 0 deletions packages/aws-cdk-lib/aws-ec2/test/vpc-endpoint-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,5 +229,101 @@ describe('vpc endpoint service', () => {
SupportedIpAddressTypes: ['ipv4', 'ipv6'],
});
});

test('without specifying allowed regions', () => {
// GIVEN
const stack = new Stack();

// WHEN
const lb = new DummyEndpointLoadBalacer('arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/Test/9bn6qkf4e9jrw77a');
new VpcEndpointService(stack, 'EndpointService', {
vpcEndpointServiceLoadBalancers: [lb],
acceptanceRequired: false,
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpointService', {
NetworkLoadBalancerArns: ['arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/Test/9bn6qkf4e9jrw77a'],
AcceptanceRequired: false,
});

// Verify SupportedRegions is not present when not specified
const template = Template.fromStack(stack);
const resources = template.findResources('AWS::EC2::VPCEndpointService');
const resourceKey = Object.keys(resources)[0];
expect(resources[resourceKey].Properties.SupportedRegions).toBeUndefined();
});

test('with a single allowed region', () => {
// GIVEN
const stack = new Stack();

// WHEN
const lb = new DummyEndpointLoadBalacer('arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/Test/9bn6qkf4e9jrw77a');
new VpcEndpointService(stack, 'EndpointService', {
vpcEndpointServiceLoadBalancers: [lb],
acceptanceRequired: false,
allowedRegions: ['us-east-1'],
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpointService', {
NetworkLoadBalancerArns: ['arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/Test/9bn6qkf4e9jrw77a'],
AcceptanceRequired: false,
SupportedRegions: ['us-east-1'],
});
});

test('with multiple allowed regions', () => {
// GIVEN
const stack = new Stack();

// WHEN
const lb = new DummyEndpointLoadBalacer('arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/Test/9bn6qkf4e9jrw77a');
new VpcEndpointService(stack, 'EndpointService', {
vpcEndpointServiceLoadBalancers: [lb],
acceptanceRequired: false,
allowedRegions: ['us-east-1', 'us-west-1', 'eu-west-1'],
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpointService', {
NetworkLoadBalancerArns: ['arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/Test/9bn6qkf4e9jrw77a'],
AcceptanceRequired: false,
SupportedRegions: ['us-east-1', 'us-west-1', 'eu-west-1'],
});
});

test('with combined options including allowed regions', () => {
// GIVEN
const stack = new Stack();

// WHEN
const lb = new DummyEndpointLoadBalacer('arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/Test/9bn6qkf4e9jrw77a');
new VpcEndpointService(stack, 'EndpointService', {
vpcEndpointServiceLoadBalancers: [lb],
acceptanceRequired: true,
allowedRegions: ['us-east-1', 'us-west-2'],
supportedIpAddressTypes: [IpAddressType.IPV4],
contributorInsights: true,
allowedPrincipals: [new ArnPrincipal('arn:aws:iam::123456789012:root')],
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpointService', {
NetworkLoadBalancerArns: ['arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/Test/9bn6qkf4e9jrw77a'],
AcceptanceRequired: true,
SupportedRegions: ['us-east-1', 'us-west-2'],
SupportedIpAddressTypes: ['ipv4'],
ContributorInsightsEnabled: true,
});

Template.fromStack(stack).hasResourceProperties('AWS::EC2::VPCEndpointServicePermissions', {
ServiceId: {
Ref: 'EndpointServiceED36BE1F',
},
AllowedPrincipals: ['arn:aws:iam::123456789012:root'],
});
});
});
});