in packages/@aws-cdk/toolkit-lib/lib/context-providers/vpcs.ts [40:186]
private async readVpcProps(ec2: IEC2Client, vpc: Vpc, args: VpcContextQuery): Promise<VpcContextResponse> {
const vpcId = vpc.VpcId!;
await this.io.debug(`Describing VPC ${vpcId}`);
const filters = { Filters: [{ Name: 'vpc-id', Values: [vpcId] }] };
const subnetsResponse = await ec2.describeSubnets(filters);
const listedSubnets = subnetsResponse.Subnets || [];
const routeTablesResponse = await ec2.describeRouteTables(filters);
const routeTables = new RouteTables(routeTablesResponse.RouteTables || []);
// Now comes our job to separate these subnets out into AZs and subnet groups (Public, Private, Isolated)
// We have the following attributes to go on:
// - Type tag, we tag subnets with their type. In absence of this tag, we
// determine the subnet must be Public if either:
// a) it has the property MapPublicIpOnLaunch
// b) it has a route to an Internet Gateway
// If both of the above is false but the subnet has a route to a NAT Gateway
// and the destination CIDR block is "0.0.0.0/0", we assume it to be a Private subnet.
// Anything else is considered Isolated.
// - Name tag, we tag subnets with their subnet group name. In absence of this tag,
// we use the type as the name.
const azs = Array.from(new Set<string>(listedSubnets.map((s) => s.AvailabilityZone!)));
azs.sort();
const subnets: Subnet[] = listedSubnets.map((subnet) => {
let type = getTag('aws-cdk:subnet-type', subnet.Tags);
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)) {
// eslint-disable-next-line max-len
throw new ContextProviderError(
`Subnet ${subnet.SubnetArn} has invalid subnet type ${type} (must be ${SubnetType.Public}, ${SubnetType.Private} or ${SubnetType.Isolated})`,
);
}
if (args.subnetGroupNameTag && !getTag(args.subnetGroupNameTag, subnet.Tags)) {
throw new ContextProviderError(
`Invalid subnetGroupNameTag: Subnet ${subnet.SubnetArn} does not have an associated tag with Key='${args.subnetGroupNameTag}'`,
);
}
const name = getTag(args.subnetGroupNameTag || 'aws-cdk:subnet-name', subnet.Tags) || type;
const routeTableId = routeTables.routeTableIdForSubnetId(subnet.SubnetId);
if (!routeTableId) {
throw new ContextProviderError(
`Subnet ${subnet.SubnetArn} does not have an associated route table (and there is no "main" table)`,
);
}
return {
az: subnet.AvailabilityZone!,
cidr: subnet.CidrBlock!,
type,
name,
subnetId: subnet.SubnetId!,
routeTableId,
};
});
let grouped: SubnetGroups;
let assymetricSubnetGroups: VpcSubnetGroup[] | undefined;
if (args.returnAsymmetricSubnets) {
grouped = { azs: [], groups: [] };
assymetricSubnetGroups = groupAsymmetricSubnets(subnets);
} else {
grouped = groupSubnets(subnets);
assymetricSubnetGroups = undefined;
}
// Find attached+available VPN gateway for this VPC
const vpnGatewayResponse =
(args.returnVpnGateways ?? true)
? await ec2.describeVpnGateways({
Filters: [
{
Name: 'attachment.vpc-id',
Values: [vpcId],
},
{
Name: 'attachment.state',
Values: ['attached'],
},
{
Name: 'state',
Values: ['available'],
},
],
})
: undefined;
const vpnGatewayId =
vpnGatewayResponse?.VpnGateways?.length === 1 ? vpnGatewayResponse.VpnGateways[0].VpnGatewayId : undefined;
return {
vpcId,
vpcCidrBlock: vpc.CidrBlock!,
ownerAccountId: vpc.OwnerId,
availabilityZones: grouped.azs,
isolatedSubnetIds: collapse(
flatMap(findGroups(SubnetType.Isolated, grouped), (group) => group.subnets.map((s) => s.subnetId)),
),
isolatedSubnetNames: collapse(
flatMap(findGroups(SubnetType.Isolated, grouped), (group) => (group.name ? [group.name] : [])),
),
isolatedSubnetRouteTableIds: collapse(
flatMap(findGroups(SubnetType.Isolated, grouped), (group) => group.subnets.map((s) => s.routeTableId)),
),
privateSubnetIds: collapse(
flatMap(findGroups(SubnetType.Private, grouped), (group) => group.subnets.map((s) => s.subnetId)),
),
privateSubnetNames: collapse(
flatMap(findGroups(SubnetType.Private, grouped), (group) => (group.name ? [group.name] : [])),
),
privateSubnetRouteTableIds: collapse(
flatMap(findGroups(SubnetType.Private, grouped), (group) => group.subnets.map((s) => s.routeTableId)),
),
publicSubnetIds: collapse(
flatMap(findGroups(SubnetType.Public, grouped), (group) => group.subnets.map((s) => s.subnetId)),
),
publicSubnetNames: collapse(
flatMap(findGroups(SubnetType.Public, grouped), (group) => (group.name ? [group.name] : [])),
),
publicSubnetRouteTableIds: collapse(
flatMap(findGroups(SubnetType.Public, grouped), (group) => group.subnets.map((s) => s.routeTableId)),
),
vpnGatewayId,
subnetGroups: assymetricSubnetGroups,
};
}