亚马逊AWS官方博客

提升 API Gateway 安全性的三种常见手段

一、概述

Amazon API Gateway(以下简称 API Gateway)是亚马逊云科技的托管的 API 网关服务。许多企业需要将自身应用的数据接口暴露给第三方合作伙伴,在使用场景上包括互联网访问、专线访问、VPC 内网访问等多种场景。当接口在互联网提供对外访问时候,有较大的安全风险面。为了提升安全性,建议对 API Gateway 实施多种安全防护,包括但不限于如下几种方式:

  • 使用 Amazon WAF 限制访问 API Gateway 的来源 IP 地址
  • 使用 Amazon IAM 身份认证和 Signature V4 签名验证身份
  • 使用 Mutual TLS(mTLS)双向证书认证

本文分别介绍这三种方式的配置。

二、使用 Amazon WAF 保护 API Gateway

1、背景

使用 API Gateway 面向多个合作伙伴提供服务时候,需要将接口暴露在互联网上。为提升接口安全性,可为 API Gateway 设置来源 IP 地址限制的办法,提升安全。API Gateway 支持设置 Resource Policy,通过资源策略中填写 IP Condition 来限制可以访问的 IP 访问,包括白名单允许,或者显式拒绝。

使用 API Gateway 自带的策略控制 IP 地址有一些局限,因为资源策略是随着 API Gateway 的部署 Stages 下发生效的,因此有时候仅需要 IP 地址的策略变更,但是为了让其生效,需要对整个接口开发的版本和 Stages 阶段创建新的版本,并进行流量切换。如此过程对整个应用开发和运行体系的影响较大。那么有什么办法实施 Out-of-band(带外管理)方式的 IP 策略管控呢?这里就可以用到 Amazon WAF。

Amazon WAF(以下简称 WAF)是 AWS 的托管 Web Application Firewall 应用防火墙。WAF 支持设置 OSI 网络模型七层的规则,包括对 HTTP/HTTPS 请求的 URI/Header 等信息进行检查。通过 WAF 实施 IP 地址检查规则,并将 WAF 绑定到 API Gateway 上,简单方便,不影响当前 API Gateway 的开发、部署。WAF 优先于所有 API Gateway 策略,在网络层生效。因此 WAF 配置的规则,优先于 API Gateway 的 Resource Policy 中配置的 IP Condition 规则。

本例配置中,会将来自特定客户端的 IP 加入白名单,并拒绝除特定客户端之外的所有 IP 请求。

2、验证 API Gateway 访问从互联网访问正常

首先进入 API Gateway 界面,从向导创建一个默认的 petstore 的演示用 API 接口。这个接口默认不带身份验证,默认类型为 regional 也就是当前 AWS 区域级别可以访问,有外网入口。创建完毕后,执行部署,生成一个新的 Stage

进入 Stages 界面,可以看到接口信息如下截图。

在这个界面中,可以看到新创建的 API 接口,以及支持调用的方法。如图中支持 GET 和 POST。接下来将接口地址复制下来,用 curl 命令校验接口地址能否正常访问,如下图所示:

3、在 WAF 中创建 IP sets 地址集

Stages 界面,点击右侧的 WAF 菜单位置的 Create Web ACL 链接。如下截图。

进入 WAF 界面后,点击页面左侧菜单的 IP sets。请注意 WAF 的控制台是全局的,右上角显示 Region 的界面会显示为 Global。在 AWS 中国区,这个 Global 的意思是北京 region 和宁夏 region 统一管理。在海外区,这个 Global 的意思是全球所有 region。这里不用担心,后续创建 ACL 时候会再次选择正确的 region。此时先不要着急点击创建按钮,而是先要创建 IP 地址集(IP sets)。如下截图。

在 IP 地址集页面上,选择正确的区域。WAF 管理控制台虽然是全局的,但是设置规则是 regional 级别的,因此把 IP 地址集要设定到正确的区域。本例中为宁夏区域。如下截图。

输入 IP 地址集的信息,包括名称、描述,确认 region 的正确。如果有多个地址段,在文本框内每行输一个。然后点击 Create IP set 按钮。如下截图。

显示绿色信息创建完成。如下截图。

4、创建 Web ACL 设置规则

在左侧菜单,点击 Web ACLs 按钮,在页面右侧切换到正确的 region,本例为宁夏区域。然后点击页面右侧的 Create web ACL 按钮继续。如下截图。

在配置 WAF 规则向导第一步,输入名称,在 Region 位置选择正确的区域(本例为宁夏),然后点击下方的 Add Amazon Web Services resources,将 WAF 和 API Gateway 绑定。如下截图。

在绑定云资源的对话框里边,选择 Amazon API Gateway,然后从资源清单中,选择本例创建的 API Gateway 的 Stages 的名称。如果有多个 API Gateway,或者一个 API Gateway 的接口有多个 Stages 部署,那么这里也要选择多个不同的 Stages 的名称,以实现保护。如果只选一个,那么意味着其他的 Stages 部署不会被保护。选择好了之后,点击 Add 按钮。如下截图。


绑定好了后,在资源清单中,能看到刚才选择的 Stages 的名字了。现在点击 Next 下一步。如下截图。

在向导第二步,Add rules and rule groups 界面,点击 Add rules,有两个选项,第一个选项是 AWS 托管规则,第二个是自定义规则。这里选择第二项 Add my own rules and rule groups。如下截图。

在自定义规则的界面上,将上方的 Rule type 选择为 IP set 类型,即 IP 规则。在 Rule 名称位置,输入一个平淡但是友好的名称作为规则名称。在 IP set 位置,从下拉框中,选择本文前一个步骤自定义 IP 地址集时候设定的名称。在下方针对入站访问的来源,WAF 支持可能是经过 NAT 等通道的场景,一般选择第一个选项针对网络层体现的最终 IP。如果有特定的 HTTP Header 标记真实客户端 IP,那么也可以选择第二个选项 IP address in header,并手工制定特定的 Header 名称。一般不需要调整这个选项,选择第一个 Source IP address 即可。如下截图。

将页面向下滚动,将本条规则行为选为 Allow 即允许通过。因为本例的配置是对特定 IP 白名单,拒绝其他所有 IP,所以这里选择对本条 IP Allow 放行。然后点击右下角的 Add rule。如下截图。


在添加完毕自定义规则后,页面返回了向导第二步,在页面上方已经看到刚才的规则被添加进来,且 Action 行为的位置显示为 Allow。接下来,要将所有非这个来源 IP 的流量设置为拒绝。在下方 Default web ACL action for requests that don't match any rules 位置,表示默认规则的处理,这里将 Default action 选择为 Block 拒绝访问。然后点击页面右下角的 Next 下一步按钮。

在向导第三步,设置多条规则的优先级。如果有多个防护规则,一般建议将网络层 IP 拒绝的规则放在最上方第一条,以便有限屏蔽无关流量,减少总体扫描量。如果只有一条的话,可直接点击 Next 下一步。如下截图。

在向导第四步,上方的下方的 Amazon CloudWatch metrics 选项保持默认打开即可。在下方的 Request sampling options 采样设置,选择 Enable sampled requests,这样在 WAF 规则 Rule 下方即可看到部分访问的采样,同时包括允许和拒绝的信息。最后点击 Next 按钮下一步继续。如下截图。

向导最后一步 Review,无需调整任何设置,直接将页面卷动到最下方,点击 Create web ACL 按钮。如下截图。

显示绿色的则表示创建 WAF ACL 完成。如下截图。

5、验证 WAF 工作

首先从本地网络(也就是被授权 Allow 放行)的位置发起访问,可看到访问正常。

接下来更换到其他的网络环境,对刚才被保护的 URL 发起访问。可看到返回报错信息。

[root@ip-172-31-16-68 ~]# curl https://038iiposid.execute-api.cn-northwest-1.amazonaws.com.cn/prod-v1/pets
{"message":"Forbidden"}
[root@ip-172-31-16-68 ~]#

现在回到 WAF 服务界面,来到 Web ACLs 菜单,点击刚才新创建的 ACL,点击 Overview 标签页。然后向下卷动页面。如下截图。

在页面下方的 Sampled requests 位置可以看到最近的访问记录取样,可查看其中列出的允许的规则和拒绝的规则都与预期一致。

至此配置完成。

如前文所述,使用 WAF 进行 IP 地址限制,不需要修改 API Gateway 的 Policy,无需重新发布 Stage,因此作为一项带外管理功能,配置变更更加方便。

三、使用 IAM 身份认证和 Signature V4 签名验证身份

1、背景

新创建的 Amazon API Gateway (以下简称 API Gateway)的 Regional 级别的接口是可以通过互联网进行公开调用的,任何人都无需身份验证即可匿名访问。在 API 为应用特定客户端调用的场景下,必须要实施身份验证。主要的身份验证手段有:IAM 身份验证、Lambda 转发器验证(Backend 可使用数据库)、OAuth/JWT 认证。此外,在 API Gateway 上还可使用 mTLS,配置双向证书,也可以显著提升安全性。

下文介绍如何开启 IAM 身份验证。

2、确认当前 API Gateway ID、接口、调用方法等信息

本文假设一个 Regional 类型的 API Gateway 接口已经创建完毕,默认是处于开放访问、无需身份认证的状态。

为构建 IAM Policy 用户授权,需要确认当前接口的信息。从 Stages 位置等多个地方都可以看到 API Gateway 的 ID,也可以看到接口名称、调用方法等信息。如下截图。

3、配置可访问 API Gateway IAM Policy、用户、AKSK

首先为要访问 API Gateway 的用户,创建一个最小权限的 IAM Policy。在开发、测试和生产环境中,不建议使用 AdministratorAccess 等具有 AWS 账号管理员权限的身份进行测试。因此接下来,为要访问访问 API Gateway 的用户(对应程序)创建专用的最小权限的 IAM Policy 策略。

进入 IAM Policy 界面,点击创建左侧 Policy,点击右侧创建 Policy。如下截图。

点击第二个标签页 JSON,直接输入 IAM 策略,文本内容如下:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "execute-api:Invoke"           
      ],
      "Resource": [
        "arn:aws-cn:execute-api:cn-northwest-1:420029960748:dmtqi47mvg/prod-iamauth/GET/pets"
      ]
    }
  ]
}

请替换上一个步骤中确认的区域、AWS 账户(12 位数字)、API Gateway 网关名称、接口名称、调用方法等信息为正确的值。

为了灵活对开发、测试、生产环境授权,IAM 策略中的 prod-iamauth 是代表 Stages 阶段,GET 是允许的方法,petResource。这几个字段可进行排列组合,实现授权的权限最小化管控。本例中,稍后打开了 IAM 授权后,还会重新部署另一个 Stages,因此 Stages 阶段的名称将会从目前的 prod-noauth 变化为 prod-iamauth。所以这里写 IAM 策略时候,直接按照新创建的名字去授权,旧的阶段不再授权。然后在要访问 API Gateway 的应用层进行流量切换,修改访问入口即可。

另外请注意,如果是在中国区,那么 Resource 中 ARN 的设置应为 aws-cn,反之在 Global 区域则为 aws。本文档按照 AWS 中国区编写,因此使用 aws-cn。如下截图。

配置好 IAM 策略后,点击 Next: Tags 按钮下一步,在标签页面可跳过,然后来到名称界面,输入本策略名称,例如 APIGW-prod-get-pets。请记住这个名称,稍后会使用这个策略。

最后点击右下角的 Create policy 按钮完成创建。

创建 IAM 用户、Access Key 和 Secret Key(以下简称 AKSK)是一个标准流程,请参考 IAM 相应文档。本文只需要创建一个具有 AWS API 访问权限的用户和对应的密钥即可,不需要访问 AWS 控制台。因此在创建 IAM 用户过程中,选项 Enable console access 不需要被选中。

如果您是 AWS 新用户,不熟悉 2022 年改版后的 IAM 操作界面,可参考这篇博客。

创建 AKSK 完成后将其保存好,因为 IAM 界面只在创建的第一次会显示完整的 Secret Key,以后将不会显示。后续程序中将会使用这个 AKSK 测试对 API Gateway 的认证和访问。

4、在 API Gateway 上配资资源和方法,开启 IAM 身份验证

进入 API Gateway界面,点击左侧 Resource 菜单,在右侧找到要管理的资源,例如首先配置 / 目录对应的 GET 方法。在页面右侧的 Method Request 下方可以看到,当前配置的 Auth 显示为 None,这表示当前没有打开认证。此时点击 Method Request 文字链接,进入设置界面。如下截图。

Method Execution 界面,点击 Authentication 的下拉框,从刚才没有认证的 None 选项,修改为 Amazon IAM。然后点击边上的对勾按钮表示保存设置。如下截图。

修改完毕后,重新回到上一步的资源界面,可以看到图中的 Auth 认证已经改变,显示为 Amazon IAM。如下截图。

5、多个资源和方法的批量配置(本节可选)

API Gateway 的资源的修改,是针对单个资源和方法的,也就是上边的截图中的对于 / 目录的 GET 方法。对于其他资源和方法,依然还是处于没有认证的公开阶段,因此他们需要被逐一配置。如下截图。

逐一配置 IAM 认证的方法就是重复以上过程,把所有资源 Resource 对应的方法 Method(即 GET/POST 等)逐一编辑认证选项,逐个添加。这里还提供另一种方法,可选用 AWSCLI 为接口批量设置。

在 AWS 控制台图形界面上,图中标记出来的 ID 就是后续要用到的资源编号。如下截图。

也通过 AWSCLI 查询本网关下所有的资源和方法:

aws apigateway get-resources --rest-api-id dmtqi47mvg

以上清单中,可以分别获取资源 IDresource-id 和支持的方法如 GETPOST 等。

有了 ID 后,即可使用 AWS CLI 批量配置使其打开 IAM 认证。为单个方法配置 IAM 认证的命令是:

aws apigateway update-method \
    --rest-api-id dmtqi47mvg \
    --resource-id vlifnq \
    --http-method OPTIONS \
    --patch-operations op="replace",path="/authorizationType",value="AWS_IAM"

配置之后显示如下信息,其中第二行显示认证已经是 IAM 类型。如下截图。

重复以上过程,对所有资源和方法都执行一遍配置。

6、将开启 IAM 认证的配资部署为新的 Stages 阶段

经过确认,所有接口部署完成。接下来要将 Resource 部署到 Stages 推向生产。在上一步的 Resource 界面,点击 Actions 按钮,从下拉框中选择 Deploy API 按钮,进行部署。如下截图。

在弹出的对话框中,输入要部署的 Stages 的名称,这里需要与前文配置 IAM Policy 的授权的 Stages 名称一致,这里使用 prod-iamauth。如下截图。

部署完成。回到 API Gateway 界面,点击左侧的 Stages 按钮,可看到页面中间显示的新部署的 prod-iamauth,点击资源和方案,可看到右侧显示的 AuthenticationAmazon IAM,表示配置成功。如下截图。

至此配置部分完成。接下来进行测试。

7、使用 AWS Signature V4 对打开 IAM 身份验证的接口发起访问

1)SigV4 简介

在 API Gateway 打开了 IAM 认证后,要求客户端发送给服务器端的请求必须使用 SigV4 签名进行身份认证。也就是说,客户端不能直接通过 CURL 发送明文的 AKSK 到 API Gateway,而是要经过 HMAC-SHA256 算法生成符合 API Gateway 要求的 SigV4 签名,然后带着签名才能发送到 AWS 云端。签名请求格式类似如下:

Authorization: AWS4-HMAC-SHA256
Credential=AKIAIOSFODNN7EXAMPLE/20220830/cn-northwest-1/execute-api/aws4_request,
SignedHeaders=host;x-amz-date,
Signature=calculated-signature

SigV4 签名才用的 HMAC-SHA256 算法具有足够的强度,因此经过加密的信息不会被破解。关于 SigV4 的介绍,可参考本文末尾的文档。为了满足 SigV4 签名的前提条件,本文后续将使用内置 SigV4 的客户端进行测试,并使用 Python 构建代码进行测试。

2)使用 REST 客户端软件请求

对 API Gateway 的请求可以通过 REST 客户端,例如 Postman 等软件。本文使用 VSCode 并通过 THUNDER CLIENT 插件实现。

在 THUNDER CLIENT 插件的界面上,选择方法是 GET,输入 API Gateway 调用的资源地址,选择认证标签页 Auth,然后在下方输入 Access Key 和 Secret Key。然后点击 Send 按钮提交认证。此时右侧可以收到正确的请求返回信息。如下截图。

如果 IAM 和 AKSK 的认证信息不正确,则会收到错误信息。如下截图。

由此确认了带有 IAM 身份验证的 API Gateway 请求正常。

3)使用 Python 代码请求

Python 程序调用 AWS 服务,包括但不限于 API Gateway,需要额外安装 requests 库和 aws_requests_auth。命令如下:

pip install requests aws_requests_auth -y

构建如下 Python 程序:

import requests
from aws_requests_auth.aws_auth import AWSRequestsAuth

# let's talk to our AWS Elasticsearch cluster
auth = AWSRequestsAuth(aws_access_key='access_key',
                       aws_secret_access_key='secret_key',
                       aws_host='dmtqi47mvg.execute-api.cn-northwest-1.amazonaws.com.cn',
                       aws_region='cn-northwest-1',
                       aws_service='execute-api')

response = requests.get('https://dmtqi47mvg.execute-api.cn-northwest-1.amazonaws.com.cn/prod-iamauth/pets',
                        auth=auth)
print(response.text)

以上代码不依赖于 AWS Boto3 SDK,只需要构建正确的 HTTP 请求即可满足 IAM 身份认证要求的 SigV4 签名。将配置信息带入后,运行程序,可看到正常返回结果。

如果 IAM 和 AKSK 的认证信息不正确,则会收到错误信息。如下截图。

由此确认了带有 IAM 身份验证的 API Gateway 请求正常。

至此所有配置过程完成。

四、使用 Mutual TLSmTLS)双向证书认证

1、背景

通常使用的 HTTPS 接口采用的是服务器端 Transport Layer Security(以下简称TLS)认证。TLS 认证默认是由服务器提供证书,服务器端证书经过全球数家证书颁发机构和顶级 CA 签署认证的证书,来标识服务器自己的真实、正确的身份。在亚马逊云科技的云平台上,这一服务器端证书通常由 Amazon Certificate Manager(ACM)生成并管理,配置到 Amazon CloudFront、Amazon ELB、Amazon API Gateway(以下简称 API Gateway)等服务上。

为了进一步增强安全性,TLS 协议建立连接时候,服务器可以要求客户端也提供自己 X.509 格式的证书用于验明身份。由于服务器和客户端双方都需要提供证书,这种认证方式被称为 mutual Transport Layer Security(以下简称 mTLS),也称为双向 TLS。

双向 TLS 证书验证在金融、物联网、IoT 等公开网络环境中发生在线交易、在线交互等场景下获得普遍应用。在企业内部应用系统中也经常作为强制验证客户端身份真实性的一种手段。使用 mTLS 后,即便拥有正确的用户名和密码,也会因为没有通过证书验证而不能建立网络连接,此时用户名和密码将不会在网络层被发送。应用 mTLS 额外提升了接口安全能力。

在 API Gateway 上开启 mTLS 认证没有额外费用。双向 TLS 证书验证与使用用户名、密码和 token 的认证手段并不矛盾和冲突,mTLS 工作于更基础的网络层。通过证书校验,网络通道建立后,就会进行应用层的身份认证。对于 API Gateway,建议在 API Gateway 使用包括但是不限于 IAM 身份验证、Lambda 认证转发器和 JSON Web Tokens(JWTs)等认证手段进行身份认证。

在 API Gateway 上开启 mTLS 认证主要步骤是:

  • 准备:发布一个正常接受访问的 API Gateway Stages(阶段),并准备好 ACM 证书,自定义域名
  • 生成证书:生成 mTLS 使用的证书
  • 创建 Endpoint:使用自定义域名功能,通过绑定别名和来自 Amazon Certificate Manager(ACM)的证书,生成一个仅支持的 mTLS 的新的 Endpoint
  • 绑定:然后通过 API Mapping 方式将原 API Gateway 与新的 mTLS 认证的 Endpoint 进行关联
  • 加固:关闭原有 API Gateway 的 Endpoint 的公开访问

本文介绍如何为 API Gateway 开启 mTLS 认证。开始配置前,请确认 API Gateway 本身工作正常。然后开始配置。

2、生成并上传证书

双向证书认证要求证书为 X.509 证书。证书可以自行签署,或者通过 Amazon Private Certificate Authority(以下简称 Private CA)生成。

截止本文编写时(2023 年 1 月),亚马逊云科技中国区尚未发布 Private CA 功能,因此本文使用 Openssl 自行签署。

1)生成 CA

生成证书需要 Linux 环境和 openssl 组件,先生成自有 CA,然后自己为自己颁发证书。全过程需要生成以下文件:

  • RootCA.key (root CA private key)
  • RootCA.pem (root CA public key)
  • my_client.csr (client certificate signing request)
  • my_client.key (client certificate private key)
  • my_client.pem (client certificate public key)

首先生成 CA 私有证书文件。

openssl genrsa -out RootCA.key 4096

由此将在当前目录下获得 RootCA.key 文件。接下来生成 CA Public Key。执行如下命令:

openssl req -new -x509 -days 3650 -key RootCA.key -out RootCA.pem

执行以上命令后,提示输入证书所需要的 Country NameStatecityCompanysectionnameEmail 等信息。如下返回信息。

[root@ip-172-31-32-113 ~]# openssl req -new -x509 -days 3650 -key RootCA.key -out RootCA.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BEIJING
Locality Name (eg, city) [Default City]:BEIJING
Organization Name (eg, company) [Default Company Ltd]:BITIPCMAN
Organizational Unit Name (eg, section) []:DEV
Common Name (eg, your name or your server's hostname) []:lxy
Email Address []:aobao32@163.com
[root@ip-172-31-32-113 ~]#

完毕后,在当前目录下生成 RootCA.pem 文件。

2)生成客户端证书

首先生成客户端私钥。执行如下命令:

openssl genrsa -out my_client.key 2048

由此获得 my_client.key 文件。为此证书生成 Certificate Signing Request (CSR)。执行如下命令:

openssl req -new -key my_client.key -out my_client.csr

在发出证书签署申请时候,也要逐步输入 Country NameStatecityCompanysectionnameEmail 等信息。当提示 A challenge password 时候,请注意这是可选步骤,直接按回车保持为空不需要输入。如下返回信息。

[root@ip-172-31-32-113 ~]# openssl req -new -key my_client.key -out my_client.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BEIJING
Locality Name (eg, city) [Default City]:BEIJING
Organization Name (eg, company) [Default Company Ltd]:BITIPCMAN
Organizational Unit Name (eg, section) []:DEV
Common Name (eg, your name or your server's hostname) []:dev01
Email Address []:dev01@bitipcman.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
[root@ip-172-31-32-113 ~]#

至此在当前目录下获得 my_client.csr 文件。

3)签署证书

现在针对上一步的客户端证书签名请求,签署客户端证书,生成客户端公钥。执行如下命令:

openssl x509 -req -in my_client.csr -CA RootCA.pem -CAkey RootCA.key -set_serial 01 -out my_client.pem -days 3650 -sha256

这样即可针对刚才的客户端证书生成签名。返回结果如下:

root@ip-172-31-32-113 ~]# openssl x509 -req -in my_client.csr -CA RootCA.pem -CAkey RootCA.key -set_serial 01 -out my_client.pem -days 3650 -sha256
Signature ok
subject=/C=CN/ST=BEIJING/L=BEIJING/O=BITIPCMAN/OU=DEV/CN=dev01/emailAddress=dev01@bitipcman.com
Getting CA Private Key
[root@ip-172-31-32-113 ~]#

由此在当前目录下获得 my_client.pem 文件。后续在调用 API Gateway 的客户端程序中,就需要使用 client.pem 这个文件。

4)上传 CA S3 存储桶用于 API Gateway 加载

API Gateway 在开启 mTLS 时候需要检查证书的 CA 的公有证书,因此这里需要将上一个步骤生成的 RootCA.pem 上传到某个 S3 存储桶中,然后在 API Gateway 上加载这个证书文件。

为此,创建一个 S3 存储桶,选择与 API Gateway 相同的 region,存储桶取名为 apigateway-mtls-mycert-zhy。将上一步生成的 RootCA.pem 复制为一个新文件,名叫 truststore.pem,然后将其上传到 S3 存储桶内。

以下过程也可以通过 AWSCLI 执行,命令如下。

cp RootCA.pem truststore.pem
aws s3 cp truststore.pem s3://apigateway-mtls-mycert-zhy/

3、为 API Gateway 设置设置自定义域名和 mTLS

为配置 mTLS,需要开启 custom domain name 也就是自定义域名功能。

进入 API Gateway 的界面,点击左侧菜单 custom domain name,点击右侧的创建按钮。

在创建自定义域名的界面上,输入自定义域名,TLS 协议选择为 1.2 版本(推荐),在 Mutual TLS authentication 开关设置为启用,在 Truststore URI 位置输入上一步的 S3 存储桶名称和文件路径 s3://apigateway-mtls-mycert-zhy/truststore.pem。然后向下卷动页面。如下截图。

Certificate type 位置上,选择 Public ACM certificate,然后从下拉框中选择事先在本 Region 配置好的 ACM 证书。最后点击右角的 Create domain name 创建自定义域名。

现在可以看到新生成了一个新的 API Gateway Endpoint,和原来没有使用 mTLS 的 Endpoint 是独立的两个端点。由此即可配置自己的域名,设置一个新的 CNAME,将别名指向过来。

如果您的域名是在 Amazon Route53 解析的,请在 Route53 上设置 Alias 记录。如果您的域名是在其他域名服务商解析的,那么请在域名服务商提供的域名解析控制面板上设置 CNAME 记录。设置 Alias 和 CNAME 过程本文不再描述,请参考相关文档完成。

4、设置自定义域名的 Mapping

在创建自定义域名完成后,还要设置 API Mapping。进入自定义域名界面,点击右下的第二个标签页 API mappings 标签页,点击右边的按钮 Configure API mappings 按钮。如下截图。

在创建新的 Endpoint 的位置上,从下拉框选择中选择要绑定的 API Gateway 的名字,从 Stages 下拉框中选择之前配置好的 prod,在映射为新的 API 地方输入相同的名字 prod,然后点击右下角的创建按钮。这里可以看到界面上提示原有的 API Gateway 的公开对外访问还没有关闭,这个信息可以暂时忽略,本文后续步骤会关闭不带 mTLS 的访问。如下截图。


创建 Mapping 完成。提示原有的 API Gateway 的公开对外访问还没有关闭,这个信息可以暂时忽略,本文后续步骤会关闭不带 mTLS 的访问。如下截图。

接下来发起访问测试。

5、测试访问

使用 CURL 的参数--key--cert 带着证书访问新创建的自定义域名。命令如下:

curl --key my_client.key --cert my_client.pem 
https://mtlsdemo.bitipcman.com/prod/pets/

测试可看到访问正常。当去掉证书之后,再次使用 CURL 访问,可以看到提示 SSL 错误无法建立连接。如下截图。

由此表示配置正常。

6、关闭原有的不带 CNAME 不带 mTLS Endpoint

前文已经讲解,新创建的带有 mTLS 的自定义域名是一个全新的 Endpoint,还需要把原先的 Endpoint 设置为禁止公开访问。

方法是进入原先的 API Gateway 的界面,进入左侧的 Settings 设置界面,再右侧找到 Default endpoint 的选项,将默认为 Enable 的开关修改为 Disable。如下截图。

注意此选项变更后,必须要重新部署新 Stages 才可以生效。界面上也有如下提示:

This is an API level setting and affects all stages of your API. After you enable or disable the default endpoint, deploy your API to any one stage for the update to take effect.

如果不发起新的部署,原有的 API Gateway Endpoint 依然是无需 mTLS 即可访问的。发起新的部署可以在 API Gateway 图形界面控制台完成,也可以通过 AWSCLI 发起,命令如下:

aws apigateway update-rest-api \
    --rest-api-id abcdef123 \
    --patch-operations op=replace,path=/disableExecuteApiEndpoint,value='True'
    
aws apigateway create-deployment \
    --rest-api-id abcdef123 \
    --stage-name prod

在发布新的 Stage 后,再次通过 curl 访问原有 API Gateway,则提示没有权限。

{"message":"Forbidden"}

由此表明,旧的 API Gateway 已经被关闭。目前所有访问只能通过开启了 mTLS 的自定义域名来访问。至此所有配置完成。

五、参考文档

选择网关类型 Restful 类型和 HTTP 类型:https://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/http-api-vs-rest.html

为 API Gateway 使用 IAM 身份验证:https://aws.amazon.com/cn/premiumsupport/knowledge-center/iam-authentication-api-gateway/?nc1=h_ls

访问 API Gateway 的 IAM 策略最佳实践和配置样例:https://docs.aws.amazon.com/zhcn/apigateway/latest/developerguide/securityiamid-based-policy-examples.html#securityiam_service-with-iam-policy-best-practices

通过 AWSCLI 为 API Gateway 资源和方法配置 IAM 认证:https://docs.aws.amazon.com/cli/latest/reference/apigateway/update-method.html

AWS SigV4 简介,以及常见编程语言生成 SigV4 签名的 Sample Code:https://docs.aws.amazon.com/zh_cn/general/latest/gr/create-signed-request.html

Python SigV4 签名代码样例(From Github):https://github.com/DavidMuller/aws-requests-auth

Introducing mutual TLS authentication for Amazon API Gateway:https://aws.amazon.com/cn/blogs/compute/introducing-mutual-tls-authentication-for-amazon-api-gateway/

为 REST API 配置双向 TLS 身份验证:https://docs.amazonaws.cn/apigateway/latest/developerguide/rest-api-mutual-tls.html

禁用 REST API 的默认终端节点:https://docs.amazonaws.cn/apigateway/latest/developerguide/rest-api-disable-default-endpoint.html

本篇作者

刘辛酉

亚马逊云科技解决方案架构师,曾服务于 Parallels、Siemens,在 Atos 担任管理服务部首席架构师。拥有十余年数据中心、互联网技术经验,长期为制造、汽车等行业头部客户提供 IT 咨询和服务。加入亚马逊云科技后负责零售、快消、食品和制造等行业。擅长硬件、网络等领域设计。

苏洁

亚马逊云科技解决方案架构师,负责互联网行业云端架构咨询和设计。