使用AWS re:Post即您表示您同意 AWS re:Post 使用条款

如何解决来自需要双向 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 日志,则 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 日志记录
  2. 配置执行和访问日志
    注意: 当您为这个用例配置访问日志时,最佳实践是使用以下 $context 变量
    { "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" }
    当需要双向 TLS 的自定义域名返回 403 错误时,这些变量指示 API Gateway 生成 CloudWatch 日志。它们还使您可以更轻松地识别尝试调用您的 API 操作的调用者。
  3. 在 CloudWatch 中查看 REST API 的执行日志,以确定出现错误的原因。如果日志中记录了与双向 TLS 相关的 403 禁止访问错误,则您会收到一条类似于以下内容的错误消息:
    Extended Request Id: {extendedRequestId} Access denied. Reason: {reason}
    ForbiddenException Forbidden: {requestId}

Resolve "Access denied.Reason: Could not find issuer for certificate" errors

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

API 请求中客户端证书 (client.pem) 的颁发者必须包含在自定义域名的信任库中。颁发者还必须作为证书捆绑包 (bundle.pem) 的一部分包含在 Amazon Simple Storage Service(Amazon S3)中。
要验证客户端证书的颁发者是否包含在所需的信任库中,请运行以下 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. 在左侧导航窗格中,选择自定义域名。然后,选择需要双向 TLS 的自定义域名。

  3. 详细信息部分中,检查以下错误消息: 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 Authorizer。您可以在 Lambda 函数中使用您的自定义验证算法。为此,请接受客户端证书作为 API 请求的输入

解决“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'

命令响应会返回您的信任库的签名算法。

有关详细信息,请参阅配置信任库

Resolve "Access denied.Reason: self signed certificate”错误

确认 API 请求中的自签名客户端证书未被更改或损坏。客户认证签名请求 (my_client.csr)、客户端证书私钥 (my_client.key) 和客户端证书公钥 (my_client.pem) 必须匹配。

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

$ openssl rsa -noout -modulus -in my_client.csr
$ openssl x509 -noout -modulus -in my_client.key
$ openssl x509 -noout -modulus -in my_client.pem

**注意:**要生成更短的哈希值以便于比较,请在输出模数上使用管道。参见以下 openssl sha1 示例:

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

有效的输出示例如下所示:

2143831a73a8bb28467860df18550c696c03fbcb2143831a73a8bb28467860df18550c696c03fbcb
2143831a73a8bb28467860df18550c696c03fbcb

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

$ diff client.crt bundle.crt

有关详细信息,请参阅配置信任库

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