如何排查来自需要双向 TLS 的 API Gateway 自定义域名的 HTTP 403 禁止访问错误?

上次更新日期:2021 年 12 月 8 日

已激活双向传输层安全性(TLS)身份验证的 Amazon API Gateway 自定义域名返回 HTTP 403 禁止访问错误。为什么会发生这种情况?如何排查此问题?

简短描述

注意:API Gateway 可能会因各种原因返回 403 禁止访问错误。本文仅讨论与双向 TLS 相关的 403 禁止访问错误。有关排查其他类型的 403 禁止访问错误的信息,请参阅如何排查来自 API Gateway 的 HTTP 403 禁止访问错误?

使用需要双向 TLS 的自定义域名调用 API Gateway API,客户端必须在 API 请求中出示可信证书。当客户端尝试调用 API 时,API Gateway 会在信任库中查找客户端证书的发布者。

如果发生以下任何一种情况,API Gateway 就会无法连接 TLS 并返回 403 状态代码:

  • API Gateway 在您的信任库中找不到客户端证书的发布者。
  • 客户端证书使用的是不安全的签名算法。
  • 客户端证书是自签名证书。

如果您的 API 已激活 Amazon CloudWatch 日志记录,则执行日志中将显示一条错误消息,指明引起错误的原因。

重要提示:如果 API 请求在日志记录激活后未生成任何 CloudWatch Logs,则 403 禁止访问错误与双向 TLS 无关。

对于 REST API

如果您为 REST API 设置了 Amazon CloudWatch 日志记录,那么您的执行日志中还会显示下面的其中一条错误消息:

  • Access denied.Reason: Could not find issuer for certificate
  • Access denied.Reason: Client cert using an insecure Signature Algorithm
  • Access denied.Reason: self signed certificate

对于 HTTP API

HTTP API 不支持执行日志记录。要排查需要双向 TLS 并调用 HTTP API 的自定义域名返回的 403 禁止访问错误,您必须执行以下操作:

1.    为自定义域名新建一个 API 映射,仅调用用于测试的 REST API。
注意:如果您没有可用于测试的 REST API,请使用示例 PetStore REST API。然后,将示例 API 部署到新阶段,并为其创建使用自定义域名的新 API 映射。

2.    使用您为 REST API 创建的新 API 映射,按照本文的解决方法部分中的说明进行操作。

3.    识别并解决错误后,将自定义域名的 API 映射重新路由回 HTTP API。

解决方法

确认引起错误的原因

1.    如果您尚未为您的 REST API 启用 CloudWatch 日志记录,请启用。务必配置执行和访问日志记录

注意:为此使用案例配置访问日志记录时,最佳实践是使用以下 $context 变量。这些变量有两个用途:

  • 当需要双向 TLS 的自定义域名返回 403 禁止访问错误时,它们会告知 API Gateway 生成 CloudWatch Logs。
  • 当您查看 CloudWatch Logs 时,它们可以帮助您更轻松地识别曾试图调用您的 API 的调用者。

建议为 CloudWatch 访问日志记录使用 $context 变量,允许 API Gateway 生成执行和访问日志

{ "accountId":"$context.accountId", "apiId":"$context.apiId", "domainName":"$context.domainName", "domainPrefix":"$context.domainPrefix", "error.message":"$context.error.message", "error.responseType":"$context.error.responseType", "extendedRequestId":"$context.extendedRequestId", "httpMethod":"$context.httpMethod", "identity.sourceIp":"$context.identity.sourceIp", "identity.clientCert.clientCertPem":"$context.identity.clientCert.clientCertPem", "identity.clientCert.subjectDN":"$context.identity.clientCert.subjectDN", "identity.clientCert.issuerDN":"$context.identity.clientCert.issuerDN", "identity.clientCert.serialNumber":"$context.identity.clientCert.serialNumber", "identity.clientCert.validity.notBefore":"$context.identity.clientCert.validity.notBefore", "identity.clientCert.validity.notAfter":"$context.identity.clientCert.validity.notAfter", "identity.userAgent":"$context.identity.userAgent", "path":"$context.path", "protocol":"$context.protocol", "requestId":"$context.requestId", "requestTime":"$context.requestTime", "requestTimeEpoch":"$context.requestTimeEpoch", "resourceId":"$context.resourceId", "resourcePath":"$context.resourcePath", "stage":"$context.stage", "responseLatency":"$context.responseLatency", "responseLength":"$context.responseLength", "status":"$context.status" }

2.    查看 CloudWatch 中 REST API 的执行日志,确定导致 403 禁止访问错误的原因。如果记录了与双向 TLS 相关的 403 禁止访问错误,则会显示类似以下示例的错误消息。

需要双向 TLS 的自定义域名返回 403 禁止访问错误时显示的 CloudWatch Logs 错误消息示例

Extended Request Id: {extendedRequestId} 
Access denied. Reason: {reason} 
ForbiddenException Forbidden: {requestId}

解决“Access denied.Reason: Could not find issuer for certificate”错误

验证自定义域名的信任库中是否包含 API 请求中客户端证书的发布者

自定义域名的信任库中必须包含 API 请求中客户端证书(client.pem)的发布者。发布者还必须属于 Amazon Simple Storage Service(Amazon S3)中的证书捆绑包(bundle.pem)。

要验证所需的信任库中是否包含客户端证书的发布者,请运行以下 OpenSSL 命令:

$ openssl verify -CAfile bundle.pem client.pem

– 或者 –

如果证书捆绑包包含中级证书颁发机构,则运行以下 OpenSSL 命令:

$ openssl verify -CAfile rootCA.pem -untrusted intCA.pem client.pem

如果所需信任库中包含 API 请求中客户端证书的发布者,则该命令将返回 OK 响应。

如果所需信任库中不包含客户端证书的发布者,则该命令将返回以下错误:“error X at Y depth lookup: unable to get local issuer certificate”

验证自定义域名的信任库中的所有客户端证书是否均有效

如果自定义域名的信任库中某个客户端证书无效,则某些客户端可能无法访问您的 API。

要验证信任库中的所有客户端证书是否均有效,请执行以下操作:

1.    打开 API Gateway 控制台

2.    在左侧导航窗格中,选择 Custom domain names(自定义域名)。然后,选择需要双向 TLS 的自定义域名。

3.    在 Details(详细信息)部分,查看是否存在以下错误消息:There is an invalid certificate in your truststore bundle

4.    如果您看到该错误消息,则必须对信任库中的证书进行解码,确定哪个证书导致了该警告。
注意:以下 OpenSSL 命令将显示证书的内容,包括其主题:

$ openssl x509 -in certificate.crt -text -noout

5.    更新或删除导致警告的证书。然后,将新的信任库上传到 Amazon S3

有关更多信息,请参阅证书警告问题排查

注意:API Gateway 接受根证书颁发机构或任何其他中级颁发机构直接签署的客户端证书,前提是已保留他们的证书链。要仅验证由上一个中级证书颁发机构签署的客户端证书,请使用基于请求参数的 AWS Lambda 授权方。您可以接受客户端证书作为 API 请求的输入,在 Lambda 函数级别使用您的自定义验证算法。

解决“Access denied.Reason: Client cert using an insecure Signature Algorithm”错误

验证您的信任库文本文件是否使用受支持的哈希算法

API Gateway 在信任库中支持以下哈希算法:

  • SHA-256 或更强
  • RSA-2048 或更强
  • ECDSA-256 或更强

要验证信任库文本文件是否使用受支持的哈希算法,请运行以下 OpenSSL 命令:

$ openssl x509 -in client.crt -text -noout | grep 'Signature Algorithm'

该命令响应将返回信任库的签名算法。

有关更多信息,请参阅配置您的信任库

解决“Access denied.Reason: self signed certificate”错误

验证 API 请求中的自签名客户端证书是否未被更改或损坏

以下内容必须完全匹配:

  • 用于签署 S3 中信任库内自签名证书(bundle.crtbundle.pem)的私有密钥(private.key)的模数。
  • API 请求中传递的客户端证书(client.crt)的模数。

要比较两个模数,请运行以下 OpenSSL 命令:

$ openssl rsa -noout -modulus -in private.key
$ openssl x509 -noout -modulus -in bundle.crt
$ openssl x509 -noout -modulus -in client.crt

注意:要生成较短的哈希值以便于比较,您可以使用 PIPE 函数将输出模数输入加密哈希函数。例如:openssl sha1

$ openssl [operation] -noout -modulus -in [data] | openssl sha1

有效命令输出示例

2143831a73a8bb28467860df18550c696c03fbcb
2143831a73a8bb28467860df18550c696c03fbcb
2143831a73a8bb28467860df18550c696c03fbcb

要确认数据完整性,请运行以下 diff 命令,确认内容级别没有任何数据修改:

$ diff client.crt bundle.crt

有关更多信息,请参阅配置您的信任库


这篇文章对您有帮助吗?


您是否需要账单或技术支持?