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

3 分钟阅读
0

已激活双向传输层安全性(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”(Y 深度查找时出现错误 X:无法获取本地颁发者证书)

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

如果自定义域名的信任库中某个客户端证书无效,则某些客户端可能无法访问您的 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

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


AWS 官方
AWS 官方已更新 1 年前