AWS HTTP API网关mTLS与共享授权器$context.sourceIp不一致问题咨询
架构说明
某方案采用如下AWS架构:
Client A --> API Gateway A --> Server A | |--> Lambda Authorizer (custom and shared) | Client B --> API Gateway B --> Server B | S3 Bucket (trustore)
API调用要求
- 两个客户端IP都需要加白
- 两个客户端都需要持有有效凭证/令牌
- Client B要求mTLS认证,使用API Gateway B接入
使用的AWS API Gateway类型为HTTP API (v2),核心诉求是搭建高性价比的REST API。
自定义Lambda Authorizer逻辑
共享授权器从两个维度做校验:
- IP - CIDR网段校验
- 凭证/令牌 - 身份认证
两个API网关的安全配置如下:
securitySchemes: oauth: in: header name: IpAuthorizer type: apiKey x-amazon-apigateway-authtype: oauth2 x-amazon-apigateway-authorizer: type: request authorizerPayloadFormatVersion: 1.0 identitySource: "$request.header.Authorization,$context.identity.sourceIp" authorizerUri: !Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaAuthorizerArn}/invocations"
异常现象
Client A请求异常
Client A通过API Gateway A发起请求时,授权器收到的事件如下:
{ "version": "1.0", "type": "REQUEST", "identitySource": "<Token_ClientA>, <IP_ClientA>", "headers": { "x-forwarded-for": "<IP_ClientA>", ... }, "requestContext": { "identity": { "sourceIp": " <IP_ClientA>", ... }, ... }, ... }
问题1: 请问$context.identity.sourceIp在$.identitySource中的取值、以及$.requestContext.identity.sourceIp字段的取值前缀为何会多出一个空格?
Client B请求异常
Client B通过API Gateway B发起请求时,授权器收到的事件如下:
{ "version": "1.0", "type": "REQUEST", "identitySource": "<Token_ClientB>,10.1.9.160:35840", "headers": { "x-forwarded-for": "<IP_ClientB>", ... }, "requestContext": { "identity": { "sourceIp": "10.1.9.160:35840", ... }, ... }, ... }
问题2: 请问客户端真实IP为何没有出现在$.identitySource和$.requestContext.identity.sourceIp字段中?
问题3: 请问事件中出现的非固定值10.1.9.160:35840是什么,来源是哪里?
X-Forwarded-For透传异常
当两个客户端都位于同一个开启了X-Forwarded-*配置的反向代理之后时,两个网关透传的该字段值存在差异:
- Client A通过API Gateway A发起请求时的字段取值:
{ ... "headers": { "x-forwarded-for": "<IP_ClientA>, <IP_ReverseProxy>", ... }, ... }
- Client B通过API Gateway B发起请求时的字段取值:
{ ... "headers": { "x-forwarded-for": "<IP_ReverseProxy>", ... }, ... }
问题4: 请问X-Forwarded-For头为何没有被API Gateway B正确透传?
问题1解答
你在identitySource配置中定义了两个取值源用逗号加空格分隔,AWS HTTP API v1格式的Lambda授权器在拼接多源取值时,会严格按照配置的分隔符原样输出,所以两个值之间会多出空格。另外部分AWS区域的旧版HTTP API实现存在小缺陷,单独取$context.identity.sourceIp值时也会默认补一个前缀空格,你可以在Lambda代码中对该字段做trim()处理即可解决。
问题2解答
因为API Gateway B开启了mTLS认证,开启该功能后HTTP API的$context.identity.sourceIp字段默认只会返回TLS终止节点的直连IP,不会透传客户端真实IP,所以这两个字段中看不到Client B的真实地址。
问题3解答
10.1.9.160:35840是AWS API Gateway mTLS模块的内部负载均衡节点地址:其中IP是对应区域API Gateway服务的内部私有网段地址,端口是该节点转发请求时使用的随机源端口,每次请求端口都会变化,IP也会在可用区对应的内部网段内浮动。
问题4解答
开启mTLS的HTTP API默认会覆盖X-Forwarded-For头,仅保留TCP直连的上一跳IP(也就是你场景里的反向代理IP),不会拼接上游传来的原始客户端IP;而未开启mTLS的API Gateway A会默认保留上游的X-Forwarded-For值,再追加上一跳IP,所以会显示两段IP。你可以在API Gateway B的配置中开启X-Forwarded-For透传开关,就能拿到完整的转发IP链。
内容的提问来源于stack exchange,提问作者mo7ty

