如何對來自需相互 TLS 的 API Gateway 自訂網域名稱的 HTTP 403 禁止錯誤,進行疑難排解?

上次更新日期:2022 年 12 月 21 日

我啟用相互 Transport Layer Security (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.    為您的自訂網域名稱新建會叫用 REST API 的 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.    在詳細資訊區段中,查看是否有以下錯誤訊息: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。接受用戶端憑證當作 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

如需詳細資訊,請參閱設定您的信任庫


此文章是否有幫助?


您是否需要帳單或技術支援?