如何通过 API 网关充当 S3 代理来处理来自 S3 的 403/404 错误?

问题描述 投票:0回答:1

我有一个 Cloudformation 模板(见底部),它允许我直接通过 API 网关获取 S3 对象。

获取存在的对象时效果很好,返回 200 和对象内容:

curl -i "https://xxx.execute-api.eu-west-1.amazonaws.com/prod/index.json"
HTTP/2 200 
content-type: application/json
...
{"hello": "world"}

但是,当对象不存在时,我预计会出现 404 Not Found 错误,它仍然返回 200 OK:

curl -i "https:xxx.execute-api.eu-west-1.amazonaws.com/prod/abcd.json"
HTTP/2 200 
content-type: application/json
content-length: 243
...
<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>AccessDenied</Code>
    <Message>Access Denied</Message>
    <RequestId>CH2PRDQ2MVN0CXXX</RequestId>
    <HostId>cCV8dG+6CXA5pVrzTwLqiRqMjpuW8F+iuISQRUrKDP5PugEA6f4wauU0Egmb3b1GyvLjQZgjXXX=</HostId>
</Error>%                                    

如何修改我的 CloudFormation 模板,以便对未知 S3 密钥的请求导致 HTTP 404 响应?

Resources:
  S3Bucket:
    Type: AWS::S3::Bucket
  ApiGatewayRestApi:
    Type: AWS::ApiGateway::RestApi
    Properties:
      Name: S3ProxyAPI
  ApiGatewayResource:
    Type: AWS::ApiGateway::Resource
    Properties:
      RestApiId:
        Ref: ApiGatewayRestApi
      ParentId:
        Fn::GetAtt:
          - ApiGatewayRestApi
          - RootResourceId
      PathPart: "{proxy+}"
  ApiGatewayMethod:
    Type: AWS::ApiGateway::Method
    Properties:
      AuthorizationType: NONE
      RestApiId:
        Ref: ApiGatewayRestApi
      ResourceId:
        Ref: ApiGatewayResource
      HttpMethod: GET
      RequestParameters:
        method.request.path.proxy: true
      MethodResponses:
        - StatusCode: 200
      Integration:
        IntegrationHttpMethod: ANY
        Type: AWS
        Uri:
          Fn::Sub: arn:aws:apigateway:${AWS::Region}:s3:path/${S3Bucket}/{proxy}
        Credentials:
          Fn::GetAtt:
            - ApiGatewayRole
            - Arn
        RequestParameters:
          integration.request.path.proxy: method.request.path.proxy
        PassthroughBehavior: WHEN_NO_MATCH
        IntegrationResponses:
          - StatusCode: 200
  ApiGatewayDeployment:
    Type: AWS::ApiGateway::Deployment
    DependsOn: ApiGatewayMethod
    Properties:
      RestApiId:
        Ref: ApiGatewayRestApi
      StageName: prod
  ApiGatewayRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: apigateway.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: ApiGatewayS3ProxyPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetObject
                Resource:
                  Fn::Sub: arn:aws:s3:::${S3Bucket}/*
Outputs:
  ApiEndpoint:
    Value:
      Fn::Sub: https://${ApiGatewayRestApi}.execute-api.${AWS::Region}.amazonaws.com/prod/{proxy}
  BucketName:
    Value:
      Ref: S3Bucket

amazon-web-services amazon-s3 aws-api-gateway
1个回答
1
投票

MethodResponses
定义您的 API 方法可能使用哪些 HTTP 状态代码。
IntegrationResponses
然后处理“后端”响应到 API 网关响应的映射

他们俩一起工作。

您需要 404 状态代码的方法响应,以允许您返回 404 状态代码,然后是具有 404 选择模式的集成响应。这样,您可以从 API 网关返回针对来自 S3 的 404 错误的 404 响应.

你总是得到 200,因为没有集成响应来“捕获”404 错误(或者实际上,在本例中为 403,但更多内容见下文),即使你这样做了,你也需要一个方法响应才能将其映射到 xxx 状态代码。

像这样修改你的

ApiGatewayMethod

ApiGatewayMethod:
  Type: AWS::ApiGateway::Method
  Properties:
    MethodResponses:
      - StatusCode: 200
      - StatusCode: 404
    ...
    Integration:
      IntegrationResponses:
        - StatusCode: 200
        - StatusCode: 404
          SelectionPattern: '404'
      ...

但是,这仍然不适用于您定义的 IAM 策略 - 根据 docs:

如果您没有 s3:ListBucket 权限,Amazon S3 将返回 HTTP 状态代码 403(“访问被拒绝”)错误。

您没有配置此 IAM 权限,因此 AWS 将始终返回 403(从

<Code>AccessDenied</Code>
可以看出)以阻止 S3 目录枚举。你永远不会得到 404 来映射它。

确保您还提供

s3:ListBucket
权限,如下所示:

Policies:
  - PolicyName: ApiGatewayS3ProxyPolicy
    PolicyDocument:
      Version: '2012-10-17'
      Statement:
        - Effect: Allow
          Action:
            - s3:GetObject
          Resource:
            Fn::Sub: arn:aws:s3:::${S3Bucket}/*
        - Effect: Allow
          Action:
            - s3:ListBucket
          Resource:
            Fn::Sub: arn:aws:s3:::${S3Bucket}

这会导致 AWS 实际上针对未找到的文件返回 404 错误,并且您的 API 网关随后将 S3 404 响应“映射”(或者在本例中,只是传递)到 404 方法响应。


完整的工作YAML文件如下:

Resources:
  S3Bucket:
    Type: AWS::S3::Bucket
  ApiGatewayRestApi:
    Type: AWS::ApiGateway::RestApi
    Properties:
      Name: S3ProxyAPI
  ApiGatewayResource:
    Type: AWS::ApiGateway::Resource
    Properties:
      RestApiId:
        Ref: ApiGatewayRestApi
      ParentId:
        Fn::GetAtt:
          - ApiGatewayRestApi
          - RootResourceId
      PathPart: "{proxy+}"
  ApiGatewayMethod:
    Type: AWS::ApiGateway::Method
    Properties:
      AuthorizationType: NONE
      RestApiId:
        Ref: ApiGatewayRestApi
      ResourceId:
        Ref: ApiGatewayResource
      HttpMethod: GET
      RequestParameters:
        method.request.path.proxy: true
      MethodResponses:
        - StatusCode: 200
        - StatusCode: 404
      Integration:
        IntegrationHttpMethod: ANY
        Type: AWS
        Uri:
          Fn::Sub: arn:aws:apigateway:${AWS::Region}:s3:path/${S3Bucket}/{proxy}
        Credentials:
          Fn::GetAtt:
            - ApiGatewayRole
            - Arn
        RequestParameters:
          integration.request.path.proxy: method.request.path.proxy
        PassthroughBehavior: WHEN_NO_MATCH
        IntegrationResponses:
          - StatusCode: 200
          - StatusCode: 404
            SelectionPattern: '404'
  ApiGatewayDeployment:
    Type: AWS::ApiGateway::Deployment
    DependsOn: ApiGatewayMethod
    Properties:
      RestApiId:
        Ref: ApiGatewayRestApi
      StageName: prod
  ApiGatewayRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: apigateway.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: ApiGatewayS3ProxyPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetObject
                Resource:
                  Fn::Sub: arn:aws:s3:::${S3Bucket}/*
              - Effect: Allow
                Action:
                  - s3:ListBucket
                Resource:
                  Fn::Sub: arn:aws:s3:::${S3Bucket}
Outputs:
  ApiEndpoint:
    Value:
      Fn::Sub: https://${ApiGatewayRestApi}.execute-api.${AWS::Region}.amazonaws.com/prod/{proxy}
  BucketName:
    Value:
      Ref: S3Bucket

对于成功的响应,您将获得 JSON,对于失败的响应,您将获得 XML,因此您可能需要调整 CloudFormation 的其他部分,使其与您的

Content-Type
标头(如果需要)匹配。

© www.soinside.com 2019 - 2024. All rights reserved.