UNPKG

artillery

Version:

Cloud-scale load testing. https://www.artillery.io

150 lines (124 loc) 3.82 kB
const assert = require('node:assert').strict; const { EC2Client, DescribeRouteTablesCommand, DescribeVpcsCommand, DescribeSubnetsCommand } = require('@aws-sdk/client-ec2'); class VPCSubnetFinder { constructor(opts) { this.ec2 = new EC2Client(opts); } async getRouteTables(vpcId) { const rts = await this.ec2.send( new DescribeRouteTablesCommand({ Filters: [ { Name: 'vpc-id', Values: [vpcId] } ] }) ); return rts.RouteTables; } async findDefaultVpc() { const vpcRes = await this.ec2.send( new DescribeVpcsCommand({ Filters: [ { Name: 'isDefault', Values: ['true'] } ] }) ); assert.ok(vpcRes.Vpcs.length <= 1); if (vpcRes.Vpcs.length !== 1) { return null; } else { return vpcRes.Vpcs[0].VpcId; } } async getSubnets(vpcId) { const subRes = await this.ec2.send( new DescribeSubnetsCommand({ Filters: [ { Name: 'vpc-id', Values: [vpcId] } ] }) ); return subRes.Subnets; } isSubnetPublic(routeTables, subnetId) { // // Inspect associations of each route table (of a specific VPC). A route // table record has an Associations field, which is a list of association // objects. There are two types of those: // // 1. An implicit association, which is indicated by field Main set to // true and no explicit subnet id. // 2. An explicit association, which is indicated by field Main set to // false, and a SubnetId field containing a subnet id. // // Route table for the subnet - can there only be one? let subnetTable = routeTables.filter((rt) => { const explicitAssoc = rt.Associations.filter((assoc) => { return assoc.SubnetId && assoc.SubnetId === subnetId; }); assert.ok(explicitAssoc.length <= 1); return explicitAssoc.length === 1; }); if (subnetTable.length === 0) { // There is no explicit association for this subnet so it will be implicitly // associated with the VPC's main routing table. subnetTable = routeTables.filter((rt) => { const implicitAssoc = rt.Associations.filter((assoc) => { return assoc.Main === true; }); assert.ok(implicitAssoc.length <= 1); return implicitAssoc.length === 1; }); } if (subnetTable.length !== 1) { throw new Error( `Could not locate routing table for subnet: subnet id: ${subnetId}` ); } const igwRoutes = subnetTable[0].Routes.filter((route) => { // NOTE: there may be no IGW attached to route return route.GatewayId?.startsWith('igw-'); }); return igwRoutes.length > 0; } // TODO: Distinguish between there being no default VPC, // or being given an invalid VPC ID, and no public subnets // existing in a VPC that definitely exists. async findPublicSubnets(vpcId) { if (!vpcId) { vpcId = await this.findDefaultVpc(); } const rts = await this.getRouteTables(vpcId); const subnets = await this.getSubnets(vpcId); const publicSubnets = subnets.filter((subnet) => { return this.isSubnetPublic(rts, subnet.SubnetId); }); return publicSubnets; } } async function main() { const f = new VPCSubnetFinder({ region: process.env.REGION }); try { const publicSubnets = await f.findPublicSubnets(process.env.VPC_ID); console.log(publicSubnets.map((s) => s.SubnetId).join('\n')); } catch (err) { console.log(err); } } if (require.main === module) { main(); } module.exports = { VPCSubnetFinder };