API 网关 w/mTLS 和授权方 - 不一致 $context.identity.sourceIp
API Gateway w/mTLS and Authorizer - inconsistent $context.identity.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 暴露的网关 APIs:
- 两个客户端 IP 都需要列入白名单
- 两个客户端都需要有有效的credentials/token
- 客户端 B 需要 mTLS(使用 API 网关 B)
使用的 AWS API 网关类型是 HTTP API (v2) - 主要是因为 cost-effective REST APIs.
创建的自定义 Lambda 授权方由两个 API 网关共享,并根据以下内容授权客户端:
- IP - CIDR 块验证
- Credentials/Token - 身份验证
两个 API 网关(A 和 B)的安全配置是:
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"
但 Lambda 授权事件内容不同且不一致:
- 对于客户端 A - 来自 API 网关 A:
{
"version": "1.0",
"type": "REQUEST",
"identitySource": "<Token_ClientA>, <IP_ClientA>",
"headers": {
"x-forwarded-for": "<IP_ClientA>",
...
},
"requestContext": {
"identity": {
"sourceIp": " <IP_ClientA>",
...
},
...
},
...
}
问题 1:
为什么 $.identitySource
和 $.requestContext.identity.sourceIp
中的 $context.identity.sourceIp
部分前面有一个额外的空格 (' ')?
- 对于客户端 B - 来自 API 网关 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",
...
},
...
},
...
}
问题二:
为什么 $.identitySource
和 $.requestContext.identity.sourceIp
中都不存在客户端 IP ($context.identity.sourceIp
)?
问题 3:
10.1.9.160:35840
是什么(不是常量),它从何而来?
Lambda 授权事件内容的唯一一致性似乎是 X-Forwarded-For
header 的存在,其中包含直接 TCP API 网关连接的源 IP 地址。
但即使 X-Forwarded-For
header 用法也不是很一致,因为如果我们将两个客户端放在同一个启用 X-Forwarded-*
设置的反向代理后面,我们将有不同的内容header 在 Lambda 授权事件内容中:
- 对于客户端 A - 来自 API 网关 A:
{
...
"headers": {
"x-forwarded-for": "<IP_ClientA>, <IP_ReverseProxy>",
...
},
...
}
- 对于客户端 B - 来自 API 网关 B:
{
...
"headers": {
"x-forwarded-for": "<IP_ReverseProxy>",
...
},
...
}
问题四:
为什么 X-Forwarded-For
header 没有正确地通过 API 网关 B?
与 AWS Support 进行一些互动后:
问题 1 的答案:(简单 API 网关)
We can confirm that there is an existing discrepancy within HTTP API where $.requestContext.identity.sourceIp is with an additional whitespace, and it is with all IPs. We are aware of this issue and we are working on fix it.
已解决 - 修复已应用,问题不再重现。
问题 2、3 和 4 的答案:(API 带 mTLS 的网关)
The backend team has identified multiple discrepancies with the IP addresses, and they are working on fixing the issue. The issue is being work-on timelessly by the API Gateway service team, and they have implemented the pipeline to deploy the fix. However, there's no exact ETA of when the issue might be fixed.
还没解决
结论:
- 无法使用
$.identitySource
或 $.requestContext.identity.sourceIp
验证客户端 IP ($context.identity.sourceIp
)
- 如果真实客户端 IP 在反向代理后面,则无法验证它
- 只能验证
X-Forwarded-For
header 中存在的 nearest/last/only IP
对于具有以下 AWS 架构的解决方案:
Client A --> API Gateway A --> Server A
|
|--> Lambda Authorizer (custom and shared)
|
Client B --> API Gateway B --> Server B
|
S3 Bucket
(trustore)
其中,为了消耗 API 暴露的网关 APIs:
- 两个客户端 IP 都需要列入白名单
- 两个客户端都需要有有效的credentials/token
- 客户端 B 需要 mTLS(使用 API 网关 B)
使用的 AWS API 网关类型是 HTTP API (v2) - 主要是因为 cost-effective REST APIs.
创建的自定义 Lambda 授权方由两个 API 网关共享,并根据以下内容授权客户端:
- IP - CIDR 块验证
- Credentials/Token - 身份验证
两个 API 网关(A 和 B)的安全配置是:
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"
但 Lambda 授权事件内容不同且不一致:
- 对于客户端 A - 来自 API 网关 A:
{
"version": "1.0",
"type": "REQUEST",
"identitySource": "<Token_ClientA>, <IP_ClientA>",
"headers": {
"x-forwarded-for": "<IP_ClientA>",
...
},
"requestContext": {
"identity": {
"sourceIp": " <IP_ClientA>",
...
},
...
},
...
}
问题 1:
为什么 $.identitySource
和 $.requestContext.identity.sourceIp
中的 $context.identity.sourceIp
部分前面有一个额外的空格 (' ')?
- 对于客户端 B - 来自 API 网关 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",
...
},
...
},
...
}
问题二:
为什么 $.identitySource
和 $.requestContext.identity.sourceIp
中都不存在客户端 IP ($context.identity.sourceIp
)?
问题 3:
10.1.9.160:35840
是什么(不是常量),它从何而来?
Lambda 授权事件内容的唯一一致性似乎是 X-Forwarded-For
header 的存在,其中包含直接 TCP API 网关连接的源 IP 地址。
但即使 X-Forwarded-For
header 用法也不是很一致,因为如果我们将两个客户端放在同一个启用 X-Forwarded-*
设置的反向代理后面,我们将有不同的内容header 在 Lambda 授权事件内容中:
- 对于客户端 A - 来自 API 网关 A:
{
...
"headers": {
"x-forwarded-for": "<IP_ClientA>, <IP_ReverseProxy>",
...
},
...
}
- 对于客户端 B - 来自 API 网关 B:
{
...
"headers": {
"x-forwarded-for": "<IP_ReverseProxy>",
...
},
...
}
问题四:
为什么 X-Forwarded-For
header 没有正确地通过 API 网关 B?
与 AWS Support 进行一些互动后:
问题 1 的答案:(简单 API 网关)
We can confirm that there is an existing discrepancy within HTTP API where $.requestContext.identity.sourceIp is with an additional whitespace, and it is with all IPs. We are aware of this issue and we are working on fix it.
已解决 - 修复已应用,问题不再重现。
问题 2、3 和 4 的答案:(API 带 mTLS 的网关)
The backend team has identified multiple discrepancies with the IP addresses, and they are working on fixing the issue. The issue is being work-on timelessly by the API Gateway service team, and they have implemented the pipeline to deploy the fix. However, there's no exact ETA of when the issue might be fixed.
还没解决
结论:
- 无法使用
$.identitySource
或$.requestContext.identity.sourceIp
验证客户端 IP ( - 如果真实客户端 IP 在反向代理后面,则无法验证它
- 只能验证
X-Forwarded-For
header 中存在的 nearest/last/only IP
$context.identity.sourceIp
)