亚马逊AWS官方博客

使用 ApiGateway 作为 S3 的反向代理

背景

客户目前在其架构中使用 Nginx 作为反向代理,但希望将其迁移至 AWS 托管服务。他们的主要目标是利用 AWS 的功能来实现更高效的资源管理和更可靠的服务,其中一项需求是确保可以使用自定义域名来访问存储在 AWS S3 中的资源,而不直接暴露 S3 桶的地址给终端用户,这样做可以提高安全性并使管理更加方便;此外,客户还希望在遇到 S3 资源不存在、无法访问或权限问题时,不直接返回标准的 4XX 错误代码,而是返回自定义的状态码,以便在用户界面上提供更加友好和可控的体验。

方案

解决方案

  • 使用 AWS 托管服务 API Gateway 给 S3 配置代理,用来转发资源请求
  • 使用 API Gateway 配置自定义响应参数

架构图:

涉及 AWS 服务:

  • AWS API Gateway
  • IAM
  • S3

方案特点:

优势:

  • 扩展性:AWS API Gateway 可以自动扩展以处理大量的请求流量,无需您担心基础设施扩容。
  • 性能:它可以提供低延迟和高性能,确保快速响应客户端请求。
  • 安全性:AWS API Gateway 支持身份验证和授权机制,可用于保护您的后端服务。您可以轻松集成 AWS Cognito、AWS IAM 或自定义身份验证方法。
  • 监控和分析:它提供了丰富的监控和分析功能,以便您可以实时监视请求、响应时间和错误。
  • 缓存:您可以配置缓存策略,以减轻后端服务的负载并提高响应时间。
  • 部署和管理:AWS API Gateway 提供了方便的管理工具,允许您轻松配置、部署和更新 API。

劣势:

  • 成本:使用 AWS API Gateway 可能会带来一些费用,尤其是在处理大量请求时。您需要根据使用情况来评估成本。
  • 复杂性:配置和管理 API Gateway 可能会有一定的复杂性,特别是对于复杂的路由和策略设置。
  • 依赖性:将 API Gateway 用作反向代理可能使您的应用程序依赖于 AWS 服务,这可能在将来的迁移或架构变更时引入一些依赖性。
  • 限制:AWS API Gateway 有一些限制,包括请求大小、并发连接数等。您需要了解这些限制并确保它们适合您的需求。

限制:

具体实现步骤

配置步骤:

Section 1 – IAM 配置

新建 IAM Role

添加信任策略,可以直接复制以下权限语句,请关注红色字体部分

{
       "Version": "2012-10-17",
       "Statement": [
{
                                "Sid": "",
                                "Effect": "Allow",
                                "Principal": {
                                             "Service": "apigateway.amazonaws.com"
                                           },
                               "Action": "sts:AssumeRole"
                  }
]
}

不添加托管权限(之后会创建内联策略)

命名,检查内容,并且创建

选择刚才创建的 Role

在权限 Tab 中,点选添加权限,选择创建内联策略(内联策略仅针对当前的选择的 Role,一般建议通用权限可以创建客户托管权限)

指定权限,选择 JSON

授予访问 S3 的权限

  • 范例一,仅赋予获取 S3 对象的权限
    {
           "Version": "2012-10-17",
           "Statement": [
    {
                                    "Effect": "Allow",
                                    "Action": [
    "s3:GetObject" ],
                                                "Resource": "*"
                      }
    ]
    }
    

或者

  • 范例二,仅赋予获取以及列举 S3 对象或者桶等的权限(本文使用范例二权限)
    {
          "Version": "2012-10-17",
          "Statement": [
                      {
                                  "Effect": "Allow",
                                  "Action": [ "s3:Get*", "s3:List*" ],
                                  "Resource": "*"
                      }
          ]
    }
    

创建此条策略,多数情况下请在 IAM>策略选项下新建托管策略,托管策略更适合多数情况,比如通用的策略等,本文使用角色下的内联策略作为范例

请记录此角色的 ARN,后续步骤中会使用到此 ARN

Section 2 – API Gateway 创建

打开 AWS API Gateway 控制台

选择 REST API 创建

填写 API 名称,在 API 端点终端类型中选择区域

点击创建,可以看到已经创建完成的 API

在 Root 资源下,即显示“/”的情况下,选择创建方法

在方法类型中选择 GET,集成类型中选择亚马逊云科技服务,在区域中选择您所在的区域(北京区域为 cn-north-1,宁夏区域为 cn-northwest-1),亚马逊云科技服务请选择 S3,HTTP 方法选择 GET

在操作类型中选择“使用路径覆盖”,并且填写目标桶的名称,以及之前创建的角色的 ARN

关于路径覆盖

  • 如果填写“/“(仅填写反斜杠,无需引号),则表示 S3 服务根目录
  • 如果填写具体桶名称,则指向 S3 桶的根目录,即图示中的配置为将 API 中的 GET request https//your-api-host/stage 指向到您的 S3 桶的 https://your-s3-host/index.html 的路径

本文中直接使用“/“指向 S3 根目录

Section 3 – S3 桶设置与 API Gateway 详细配置

创建公开 Amazon S3 服务功能的 API 资源

  • 创建 Folder 资源表示 S3 桶
  • 创建 Item 资源表示 S3 桶中对象

公开 API 方法以列出调用方的 Amazon S3 存储桶

  • 从 Resources(资源)面板右上角的 Actions(操作)下拉菜单中,在根节点 (/) 上选择 Create method(创建方法)。在 HTTP 动词的下拉列表中选择 GET,然后选择对勾图标以开始创建方法
  • 在方法类型中选择 GET,集成类型中选择亚马逊云科技服务
  • 在亚马逊与科技区域中填写您的 S3 桶所在区域,服务则选择 S3,HTTP 方法选择 GET,操作类型选择 使用路径覆盖,并且填写“/” 用以表示 S3 服务根目录,复制之前创建的 IAM 角色的 ARN(来自 IAM 控制台),并将其粘贴到执行角色中

使用 IAM 对此 API 进行访问控制

  • 在此 GET 方法中,选择方法请求,并点选编辑
  • 在授权中,选择 Amazon IAM

添加 GET 方法对响应类型

  • 在方法响应中创建响应
  • 添加 400 响应
  • 重复以上步骤,添加 500 响应

对 GET 方法增加响应标头

  • 在方法响应中,选择响应 200,进行编辑
  • 添加标头,将 Timestamp, Content-Length,Content-Type 分别添加进标头(注意带小写)

在 GET 方法对集成响应中,增加标头映射

  • 编辑响应
  • 增加标头映射
  • 在 GET 方法对集成响应中,为 500 响应,400 响应分别创建响应,并且添加正则表达式
  • 在 GET 方法的测试选项中测试根资源下的 GET 请求

公开 API 方法以访问 Amazon S3 存储桶

  • 在 Folder 资源上创建 GET 方法
  • 在方法类型中选择 GET,集成类型中选择亚马逊云科技服务
  • 在亚马逊与科技区域中填写您的 S3 桶所在区域,服务则选择 S3,HTTP 方法选择 GET,操作类型选择使用路径覆盖,并且填写“{bucket}” 用以表示指定的 S3 桶,复制之前创建的 IAM 角色的 ARN(来自 IAM 控制台),并将其粘贴到执行角色中
  • 创建完成
  • 在此 GET 方法的方法请求中,进行 URL 查询字符串的编辑,添加 folder 字符串
  • 在此 GET 方法的方法请求中,进行 HTTP 请求标头的编辑
  • 在 HTTP 请求标头中,添加标头,Content-Type
  • 在此 GET 方法的集成请求中,进行 URL 路径参数编辑
  • 在 URL 路径参数中添加路径参数,添加名称 bucket,映射自填写 method.request.path.folder
  • 在 HTTP 标头中添加标头,添加 Content-Type 标头

Section 4 – S3 桶设置与 API Gateway 详细配置

选择需要使用到的目标 S3 桶,并且选择权限 Tab

在存储桶策略中编辑并且写入以下权限,请将权限 JSON 中的红色文字替换为:

  • 目标桶的名字
  • API Gateway 中 GET 方法的 ARN
{
            "Version": "2012-10-17",
            "Statement": [
{
                                     "Sid": "APIProxyBucketPolicy",
                                      "Effect": "Allow",
                                     "Principal": {
                                                  "Service": "apigateway.amazonaws.com"
                                                  },
                                     "Action": "s3:GetObject",
                                     "Resource": "arn:aws:s3:::poc-zhy-chris-reverseproxy-bucket-1/*",
                                     "Condition": {
                                                  "ArnLike": {
                                                              "aws:SourceArn": "arn:aws-cn:execute-api:cn-northwest-1:580424818010:p8an3aiy2i/*/GET/"
                                                  }
                                     }
                        }
]
}

映射模版参考文档:

https://docs.thinkwithwp.com/apigateway/latest/developerguide/apigateway-override-request-response-parameters.html

https://docs.thinkwithwp.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#context-variable-reference

总结

本文介绍了如何使用 AWS API Gateway 作为 S3 的反向代理,主要目的是允许使用自定义域名访问 S3 中的资源,而不直接暴露 S3 桶地址,从而提高安全性和管理便利性。另外,它还可以在遇到 S3 资源不存在等情况时返回自定义状态码,提升用户体验。

该方案利用了 AWS 托管服务的优势,如自动扩展、高性能、安全性好等,但也需要注意成本、复杂性和 AWS 服务依赖等潜在问题。文档还提供了相关配置细节和参考资料,对于需要类似需求的用户很有参考价值。

本篇作者

李琳

亚马逊云科技解决方案架构师,负责面向跨国企业客户的云计算方案架构咨询和设计,客户涵盖医疗、零售、制造等行业。熟悉云原生网络技术及混合云网络架构。

叶骏

亚马逊云科技资深解决方案架构师。拥有超过 18 年的零售行业、制造行业以及数字营销领域的技术产品研发和解决方案架构经验。目前专注于将 AWS 云平台技术应用于实际解决方案,为客户实现技术创新和成功的技术落地。