背景
 
       客户目前在其架构中使用 Nginx 作为反向代理,但希望将其迁移至 AWS 托管服务。他们的主要目标是利用 AWS 的功能来实现更高效的资源管理和更可靠的服务,其中一项需求是确保可以使用自定义域名来访问存储在 AWS S3 中的资源,而不直接暴露 S3 桶的地址给终端用户,这样做可以提高安全性并使管理更加方便;此外,客户还希望在遇到 S3 资源不存在、无法访问或权限问题时,不直接返回标准的 4XX 错误代码,而是返回自定义的状态码,以便在用户界面上提供更加友好和可控的体验。
 
       方案
 
       解决方案
 
        
        - 使用 AWS 托管服务 API Gateway 给 S3 配置代理,用来转发资源请求
- 使用 API Gateway 配置自定义响应参数
架构图:
 
        
       涉及 AWS 服务:
 
        
       方案特点:
 
       优势:
 
        
        - 扩展性: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 资源
 
        
        
        
        
       公开 API 方法以列出调用方的 Amazon S3 存储桶
 
        
        - 从 Resources(资源)面板右上角的 Actions(操作)下拉菜单中,在根节点 (/) 上选择 Create method(创建方法)。在 HTTP 动词的下拉列表中选择 GET,然后选择对勾图标以开始创建方法
 
        - 在方法类型中选择 GET,集成类型中选择亚马逊云科技服务
 
        - 在亚马逊与科技区域中填写您的 S3 桶所在区域,服务则选择 S3,HTTP 方法选择 GET,操作类型选择 使用路径覆盖,并且填写“/” 用以表示 S3 服务根目录,复制之前创建的 IAM 角色的 ARN(来自 IAM 控制台),并将其粘贴到执行角色中
使用 IAM 对此 API 进行访问控制
 
        
        
        
        
       添加 GET 方法对响应类型
 
        
        
        
        
        
       对 GET 方法增加响应标头
 
        
        
        
        - 添加标头,将 Timestamp, Content-Length,Content-Type 分别添加进标头(注意带小写)
在 GET 方法对集成响应中,增加标头映射
 
        
        
        
        
        
        
        - 在 GET 方法对集成响应中,为 500 响应,400 响应分别创建响应,并且添加正则表达式
 
        - 在 GET 方法的测试选项中测试根资源下的 GET 请求
公开 API 方法以访问 Amazon S3 存储桶
 
        
        
        
        - 在方法类型中选择 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.aws.amazon.com/apigateway/latest/developerguide/apigateway-override-request-response-parameters.html
 
       https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#context-variable-reference
 
       总结
 
       本文介绍了如何使用 AWS API Gateway 作为 S3 的反向代理,主要目的是允许使用自定义域名访问 S3 中的资源,而不直接暴露 S3 桶地址,从而提高安全性和管理便利性。另外,它还可以在遇到 S3 资源不存在等情况时返回自定义状态码,提升用户体验。
 
       该方案利用了 AWS 托管服务的优势,如自动扩展、高性能、安全性好等,但也需要注意成本、复杂性和 AWS 服务依赖等潜在问题。文档还提供了相关配置细节和参考资料,对于需要类似需求的用户很有参考价值。
 
       本篇作者