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

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

我啟用相互 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.    在 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-ing 為加密雜湊函數。例如:openssl sha1

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

有效命令輸出範例

2143831a73a8bb28467860df18550c696c03fbcb
2143831a73a8bb28467860df18550c696c03fbcb
2143831a73a8bb28467860df18550c696c03fbcb

若要確認資料完整性,請執行以下 diff 命令,確認沒有修改任何內容等級資料:

$ diff client.crt bundle.crt

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


此文章是否有幫助?


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