diff --git a/packages/aws-cdk/lib/context-providers/vpcs.ts b/packages/aws-cdk/lib/context-providers/vpcs.ts index 5a4f36443d8a2..ce2441fc29ee7 100644 --- a/packages/aws-cdk/lib/context-providers/vpcs.ts +++ b/packages/aws-cdk/lib/context-providers/vpcs.ts @@ -74,6 +74,7 @@ export class VpcNetworkContextProviderPlugin implements ContextProviderPlugin { if (type === undefined && subnet.MapPublicIpOnLaunch) { type = SubnetType.Public; } if (type === undefined && routeTables.hasRouteToIgw(subnet.SubnetId)) { type = SubnetType.Public; } if (type === undefined && routeTables.hasRouteToNatGateway(subnet.SubnetId)) { type = SubnetType.Private; } + if (type === undefined && routeTables.hasRouteToTransitGateway(subnet.SubnetId)) { type = SubnetType.Private; } if (type === undefined) { type = SubnetType.Isolated; } if (!isValidSubnetType(type)) { @@ -176,6 +177,15 @@ class RouteTables { return !!table && !!table.Routes && table.Routes.some(route => !!route.NatGatewayId && route.DestinationCidrBlock === '0.0.0.0/0'); } + /** + * Whether the given subnet has a route to a Transit Gateway + */ + public hasRouteToTransitGateway(subnetId: string | undefined): boolean { + const table = this.tableForSubnet(subnetId) || this.mainRouteTable; + + return !!table && !!table.Routes && table.Routes.some(route => !!route.TransitGatewayId && route.DestinationCidrBlock === '0.0.0.0/0'); + } + /** * Whether the given subnet has a route to an IGW */ diff --git a/packages/aws-cdk/test/context-providers/vpcs.test.ts b/packages/aws-cdk/test/context-providers/vpcs.test.ts index fff9c90e68e31..d9472126baaa1 100644 --- a/packages/aws-cdk/test/context-providers/vpcs.test.ts +++ b/packages/aws-cdk/test/context-providers/vpcs.test.ts @@ -411,7 +411,7 @@ test('Recognize public subnet by route table', async () => { }); }); -test('Recognize private subnet by route table', async () => { +test('Recognize private subnet by route table with NAT Gateway', async () => { // GIVEN const filter = { foo: 'bar' }; const provider = new VpcNetworkContextProviderPlugin(mockSDK); @@ -475,6 +475,70 @@ test('Recognize private subnet by route table', async () => { }); }); +test('Recognize private subnet by route table with Transit Gateway', async () => { + // GIVEN + const filter = { foo: 'bar' }; + const provider = new VpcNetworkContextProviderPlugin(mockSDK); + + mockVpcLookup({ + subnets: [ + { SubnetId: 'sub-123456', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: false }, + ], + routeTables: [ + { + Associations: [{ SubnetId: 'sub-123456' }], + RouteTableId: 'rtb-123456', + Routes: [ + { + DestinationCidrBlock: '10.0.2.0/26', + Origin: 'CreateRoute', + State: 'active', + VpcPeeringConnectionId: 'pcx-xxxxxx', + }, + { + DestinationCidrBlock: '10.0.1.0/24', + GatewayId: 'local', + Origin: 'CreateRouteTable', + State: 'active', + }, + { + DestinationCidrBlock: '0.0.0.0/0', + TransitGatewayId: 'tgw-xxxxxx', + Origin: 'CreateRoute', + State: 'active', + }, + ], + }, + ], + }); + + // WHEN + const result = await provider.getValue({ + account: '1234', + region: 'us-east-1', + filter, + }); + + // THEN + expect(result).toEqual({ + vpcId: 'vpc-1234567', + vpcCidrBlock: '1.1.1.1/16', + ownerAccountId: '123456789012', + availabilityZones: ['bermuda-triangle-1337'], + isolatedSubnetIds: undefined, + isolatedSubnetNames: undefined, + isolatedSubnetRouteTableIds: undefined, + privateSubnetIds: ['sub-123456'], + privateSubnetNames: ['Private'], + privateSubnetRouteTableIds: ['rtb-123456'], + publicSubnetIds: undefined, + publicSubnetNames: undefined, + publicSubnetRouteTableIds: undefined, + vpnGatewayId: undefined, + subnetGroups: undefined, + }); +}); + test('Recognize isolated subnet by route table', async () => { // GIVEN const filter = { foo: 'bar' };