API Gateway 在不应该关心我的授权时 header

API Gateway cares about my Authorization header when it shouldn't

我在 API 网关(使用 Lambda 代理集成)中创建了一个私有 REST API,需要从 VPC 访问它。我在 VPC 中为 API 网关设置了一个 VPC 端点。正如预期的那样,API 可从 VPC 内访问。

VPC 端点(实际上是整个 VPC 环境)是通过 CloudFormation 创建的。

API需要消耗一个Authorizationheader,这不是我能改变的。 header 的内容是我们公司特有的,不是标准的。问题是当我向请求添加 Authorization header 时,API 网关拒绝它并出现以下错误(来自 CloudWatch 中的 API 网关日志):

IncompleteSignatureException
Authorization header requires 'Credential' parameter.
Authorization header requires 'Signature' parameter.
Authorization header requires 'SignedHeaders' parameter.
Authorization header requires existence of either a 'X-Amz-Date' or a 'Date' header.
Authorization=[the header content here]

如果我删除 Authorization header,请求将被接受并且我会从我的 lambda 中得到预期的响应。我调用的方法将 Auth 设置为 NONE.

奇怪的是,如果我删除 VPC 端点并通过控制台手动创建它,它会正常工作 - Authorization header 被传递到我的 lambda,而不是 API 网关正在检查并拒绝它。

我已经拆除端点并多次手动重新创建它并使用 CloudFormation,结果是一致的。但我将它们相互比较,它们看起来 完全相同:相同的设置、相同的子网、相同的安全组、相同的策略。由于我看不出它们之间有什么区别,所以我有点不知道为什么它不适用于 CloudFormation 版本。

我能找到的唯一区别是每个版本的 aws headers(删除了 Authorization header,否则它不会那么远作为使用 CF 端点记录 headers)。对于 CF 端点,header 包括 x-amzn-vpce-config=0x-amzn-vpce-policy-url=MQ==。使用手动端点,我得到 x-amzn-vpce-config=1,并且不包括 policy-url header。

我还尝试将 API 更改为同时设置和删除 VPC 端点(它可以在“设置”部分的 API 上设置),并重新部署它,但在任一如果它没有效果 - 请求继续 work/get 像以前一样被拒绝。

有人有什么想法吗?我也在 AWS forum 上发布了这个,但以防万一这里的任何人之前遇到过这个...

如果有任何兴趣,端点是这样创建的([] = 已编辑):

ApiGatewayVPCEndpoint:
  Type: AWS::EC2::VPCEndpoint
  Properties:
    PrivateDnsEnabled: true
    PolicyDocument:
      Statement:
        - Action: '*'
          Effect: Allow
          Resource: '*'
          Principal: '*'
    ServiceName: !Sub com.amazonaws.${AWS::Region}.execute-api
    SecurityGroupIds:
      - !Ref [my sec group]
    SubnetIds:
      - !Ref [subnet a]
      - !Ref [subnet b]
      - !Ref [subnet c]
    VpcEndpointType: Interface
    VpcId: !Ref [my vpc]

我设法让它工作了,这是最荒谬的事情。

这是 CF 中的端点策略(包括 属性 名称以在上下文中显示):

PolicyDocument:
  Statement:
    - Action: '*'
      Effect: Allow
      Resource: '*'
      Principal: '*'

这是该策略在控制台中的显示方式:

{
    "Statement": [
        {
            "Action": "*",
            "Effect": "Allow",
            "Resource": "*",
            "Principal": "*"
        }
    ]
}

政策在 describe-vpc-endpoints 中是这样显示的:

"PolicyDocument": "{\"Statement\":[{\"Action\":\"*\",\"Resource\":\"*\",\"Effect\":\"Allow\",\"Principal\":\"*\"}]}"

现在让我们看看手动创建的端点的策略。

控制台:

{
    "Statement": [
        {
            "Action": "*",
            "Effect": "Allow",
            "Resource": "*",
            "Principal": "*"
        }
    ]
}

describe-vpc-endpoints:

"PolicyDocument": "{\n  \"Statement\": [\n    {\n      \"Action\": \"*\", \n      \"Effect\": \"Allow\", \n      \"Principal\": \"*\", \n      \"Resource\": \"*\"\n    }\n  ]\n}"

控制台显示它们完全相同,并且 describe-vpc-endpoints 中返回的 JSON 本身除了一些“美化”的换行符和空格外是相同的,这肯定没有任何效果吗?错误的!正是这些换行符使政策真正起作用!

无论如何,解决方案是将策略提供为 JSON,例如:

ApiGatewayVPCEndpoint:
  Type: AWS::EC2::VPCEndpoint
  Properties:
    PrivateDnsEnabled: true
    PolicyDocument: '
    {
      "Statement": [
        {
          "Action": "*",
          "Effect": "Allow",
          "Resource": "*",
          "Principal": "*"
        }
      ]
    }'
    ServiceName: !Sub com.amazonaws.${AWS::Region}.execute-api
    SecurityGroupIds:
      - !Ref [my sec group]
    SubnetIds:
      - !Ref [subnet a]
      - !Ref [subnet b]
      - !Ref [subnet c]
    VpcEndpointType: Interface
    VpcId: !Ref [my vpc]

你甚至可以把所有的 JSON 放在一行中,它会在某个时候得到 AWS 放在那里的换行符。只是 YAML 在没有换行符的情况下转换为 JSON 并导致此问题。

使用这样的 CF 资源,API 网关接受我的 Authorization header 并将其毫无问题地传递给 Lambda。