如何在AWS CDK中通过标签名查找NAT网关并获取其公网IP
获取VPC关联NAT网关公网IP并添加到API Gateway白名单
核心思路
由于CDK的Vpc.fromLookup()不会自动返回关联的NAT网关信息,且NAT Gateway构造没有fromLookup()方法,我们需要通过自定义资源(CustomResource)结合EC2 API来查询指定VPC下的NAT网关公网IP,再将其集成到API Gateway的资源策略中。
实现步骤(TypeScript示例)
- 导入目标VPC
import * as cdk from 'aws-cdk-lib'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; import * as apigateway from 'aws-cdk-lib/aws-apigateway'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as iam from 'aws-cdk-lib/aws-iam'; import { CustomResource, Provider } from 'aws-cdk-lib/custom-resources'; const app = new cdk.App(); const stack = new cdk.Stack(app, 'NatIpToApiGatewayStack'); // 导入已存在的VPC(可通过VPC ID或标签匹配) const vpc = ec2.Vpc.fromLookup(stack, 'ExistingVpc', { vpcId: 'vpc-xxxxxx', // 替换为你的VPC ID });
- 创建Lambda函数查询NAT网关IP
编写一个Lambda函数,调用EC2的describeNatGateways接口过滤指定VPC下的NAT网关,提取公网IP:
const getNatIpLambda = new lambda.Function(stack, 'GetNatIpLambda', { runtime: lambda.Runtime.NODEJS_18_X, handler: 'index.handler', code: lambda.Code.fromInline(` const AWS = require('aws-sdk'); const ec2 = new AWS.EC2(); exports.handler = async (event) => { if (event.RequestType === 'Create' || event.RequestType === 'Update') { try { const result = await ec2.describeNatGateways({ Filters: [{ Name: 'vpc-id', Values: [event.ResourceProperties.VpcId] }] }).promise(); // 提取所有NAT网关的公网IP const natIps = result.NatGateways.flatMap(nat => nat.NatGatewayAddresses.map(addr => addr.PublicIp) ); return { PhysicalResourceId: Date.now().toString(), Data: { NatPublicIps: natIps.join(',') } }; } catch (err) { throw new Error(\`获取NAT网关IP失败: \${err.message}\`); } } return { PhysicalResourceId: event.PhysicalResourceId }; }; `), }); // 赋予Lambda查询NAT网关的权限 getNatIpLambda.addToRolePolicy(new iam.PolicyStatement({ actions: ['ec2:DescribeNatGateways'], resources: ['*'], }));
- 通过自定义资源获取IP列表
用Provider封装Lambda,再创建CustomResource来触发IP查询:
const natIpProvider = new Provider(stack, 'NatIpProvider', { onEventHandler: getNatIpLambda, }); const natIpResource = new CustomResource(stack, 'NatIpResource', { serviceToken: natIpProvider.serviceToken, properties: { VpcId: vpc.vpcId }, }); // 解析出NAT网关公网IP数组 const natPublicIps = natIpResource.getAtt('NatPublicIps').toString().split(',');
- 将IP添加到API Gateway资源策略
创建或更新API Gateway的资源策略,限制仅允许这些NAT网关IP访问:
// 创建或导入你的API Gateway const api = new apigateway.RestApi(stack, 'MyProtectedApi', { description: '仅允许指定NAT网关IP访问的API', }); // 构建资源策略 const apiPolicy = new iam.PolicyDocument({ statements: [ new iam.PolicyStatement({ effect: iam.Effect.ALLOW, principals: [new iam.AnyPrincipal()], actions: ['execute-api:Invoke'], resources: [api.arnForExecuteApi('*')], conditions: { IpAddress: { 'aws:SourceIp': natPublicIps }, }, }), ], }); // 为API Gateway附加策略 api.addToResourcePolicy(apiPolicy);
注意事项
- 如果VPC下有多个NAT网关,上述代码会自动收集所有公网IP并加入白名单;
- 若NAT网关发生变更(如新增/替换),需触发CDK部署更新CustomResource,以刷新IP列表;
- 确保Lambda角色拥有
ec2:DescribeNatGateways权限,否则无法查询NAT网关信息。
内容的提问来源于stack exchange,提问作者Nikita Voronin
相关产品推荐
相关产品推荐

