非默认VPC内Lambda调用API Gateway端点返回403错误问题求助
问题定位与解决方案
核心排查方向
结合你给出的环境特征(使用NAT Instance而非托管NAT Gateway、默认VPC Lambda调用正常、Lambda可访问其他公网端点、接口无认证/ApiKey校验、日志无相关错误记录),403问题按以下优先级排查修复:
- 第一优先级:API Gateway资源策略不生效
你提到已经配置VPC放通规则,但走NAT Instance公网出口的流量,API Gateway侧根本无法识别请求来源的VPC ID——只有通过VPC Endpoint(PrivateLink)访问API Gateway时,请求才会携带VPC源身份标识,公网流量的可识别源标识只有NAT实例绑定的公网IP。
如果你在资源策略里仅配置了aws:SourceVpc或者aws:VpceId条件,对公网转发的请求完全不生效,必须在资源策略里加一条放通NAT实例公网EIP的规则,或者配置VPC Endpoint让Lambda走内网访问API Gateway。
注意:修改API Gateway资源策略后必须重新部署对应API阶段,否则配置不会生效,这是最高发的配置遗漏点。 - 第二优先级:VPC私有DNS解析冲突
如果当前账号同区域存在API Gateway类型的VPC Endpoint且开启了私有DNS解析,非默认VPC内的Lambda解析execute-api.REGION.amazonaws.com域名时,可能会被解析到VPC Endpoint的私有IP:- 如果当前非默认VPC到该Endpoint没有可达路由、Endpoint安全组未放通Lambda网段的入站请求、Endpoint策略未允许调用目标API,请求会直接被Endpoint拦截返回403,且该请求不会进入API Gateway的服务端日志,这也是你在CloudWatch/API Gateway日志里查不到错误记录的核心原因。
验证方式:在非默认VPC的Lambda里加解析测试代码,打印API域名对应的解析IP,如果返回的是RFC1918私有网段地址,就说明命中了私有DNS解析,要么调整VPC路由/Endpoint安全组/策略放通,要么给VPC Endpoint关闭私有DNS,或者给Lambda配置自定义DNS走公网解析。
- 如果当前非默认VPC到该Endpoint没有可达路由、Endpoint安全组未放通Lambda网段的入站请求、Endpoint策略未允许调用目标API,请求会直接被Endpoint拦截返回403,且该请求不会进入API Gateway的服务端日志,这也是你在CloudWatch/API Gateway日志里查不到错误记录的核心原因。
- 第三优先级:NAT Instance转发配置异常
自建NAT Instance和托管NAT Gateway的转发逻辑有差异,部分NAT实例默认配置的TCP报头修改规则、IP碎片转发策略会触发API Gateway边缘节点的WAF拦截:- 先确认NAT实例已关闭源/目标地址检查(虽然你说能访问其他公网端点,但部分旧版AMI配置仅放通了特定端口的转发规则)
- 临时给非默认VPC的Lambda绑定弹性公网IP,关闭公网出口走NAT的路由,直接发起调用,如果调用正常,就说明问题出在NAT实例的转发规则上,重点检查NAT实例上的iptables规则、TCP MSS钳制配置,确认没有修改HTTP请求头里的Host、X-Forwarded-For字段。
- 第四优先级:冗余请求头触发拦截
你的代码里固定传了x-api-key请求头,但你提到接口未配置ApiKey校验,部分API Gateway阶段配置下,未开启ApiKey校验的接口收到无效的x-api-key头时会直接返回403,先把代码里的x-api-key头删掉测试,排除请求头导致的拦截。
快速验证步骤
- 先在Lambda里加测试代码,确认当前请求的出口IP、API域名解析结果,快速定位问题点:
const dns = require('dns').promises; const axios = require('axios'); exports.handler = async () => { // 查询Lambda出口公网IP const eipRes = await axios.get('https://api.ipify.org'); console.log('Lambda出口公网IP:', eipRes.data); // 查询API域名解析结果 const apiDomain = 'XXXX.execute-api.REGION.amazonaws.com'; const records = await dns.resolve4(apiDomain); console.log('API域名解析IP:', records); // 移除x-api-key头发起测试请求 try { const res = await axios.get(`https://${apiDomain}/ABC/hello-world/healthcheck`); console.log('调用成功,状态码:', res.status); } catch(err) { console.log('调用错误,状态码:', err.response?.status, '返回内容:', err.response?.data); } }
- 如果解析出来的是私有IP,按VPC Endpoint私有DNS冲突的方案修复
- 如果解析出来的是公网IP,把打印出来的Lambda出口公网IP加到API Gateway资源策略的允许列表里,重新部署API阶段后再测试
- 如果加了IP放通规则还是403,临时给Lambda绑EIP绕过NAT Instance测试,定位是否为NAT转发配置问题
内容的提问来源于stack exchange,提问作者Rasim SEN
相关产品推荐
相关产品推荐

