您目前查看的是 Apigee Edge 說明文件。
前往 Apigee X 說明文件。 info
問題
用戶端應用程式會收到 HTTP 狀態碼 503,以及「Service Unavailable」(服務無法使用) 訊息,做為 API 要求的回應。在 UI 追蹤記錄中,您會發現失敗的 API 要求在「目標要求流程」中,error.cause 為 Received fatal alert: bad_certificate。
如果您有權存取訊息處理器記錄,就會發現失敗的 API 要求會顯示 Received fatal alert: bad_certificate 錯誤訊息。在雙向 TLS 設定中,訊息處理器與後端伺服器之間的 SSL 交握程序會發生這項錯誤。
錯誤訊息
用戶端應用程式會取得下列回應代碼:
HTTP/1.1 503 Service Unavailable
此外,您可能會看到下列錯誤訊息:
{
"fault": {
"faultstring":"The Service is temporarily unavailable",
"detail":{
"errorcode":"messaging.adaptors.http.flow.ServiceUnavailable"
}
}
}Private Cloud 使用者會在訊息處理器記錄 /opt/apigee/var/log/edge-message-processor/system.log 中,看到特定 API 要求的下列錯誤:
2017-10-23 05:28:57,813 org:org-name env:env-name api:apiproxy-name
rev:revision-number messageid:message_id NIOThread@0 ERROR HTTP.CLIENT - HTTPClient$Context.handshakeFailed() :
SSLClientChannel[C:IP address:port # Remote host:IP address:port #]@65461
useCount=1 bytesRead=0 bytesWritten=0 age=529ms lastIO=529ms handshake failed,
message: Received fatal alert: bad_certificate
可能原因
這個問題的可能原因如下:
| 原因 | 說明 | 適用於以下裝置的疑難排解說明 |
| 沒有用戶端憑證 | 目標伺服器目標端點中使用的金鑰儲存區沒有任何用戶端憑證。 | Edge 私有雲和公有雲使用者 |
| 憑證授權單位不符 | 訊息處理器的金鑰儲存區中,葉節點憑證 (憑證鏈中的第一個憑證) 的憑證授權單位,與後端伺服器接受的任何憑證授權單位都不相符。 | Edge 私有雲和公有雲使用者 |
常見診斷步驟
- 在 Edge UI 中啟用追蹤功能、發出 API 呼叫,然後重現問題。
- 在 UI 追蹤結果中,逐一瀏覽每個階段,找出發生錯誤的位置。錯誤會發生在目標要求流程中。
- 檢查顯示錯誤的 Flow,您應該會看到如下方範例追蹤記錄所示的錯誤:

- 如上方的螢幕截圖所示,error.cause 為 「Received fatal alert: bad_certificate」。
- 如果您是私有雲使用者,請按照下列指示操作:
- 如要取得失敗 API 要求的訊息 ID,請在追蹤記錄中,找出 AX 指示的階段,並判斷錯誤標頭「
X-Apigee.Message-ID」的值。 - 在訊息處理器記錄
/opt/apigee/var/log/edge-message-processor/system.log中搜尋這個訊息 ID,判斷是否能找到錯誤的相關資訊:2017-10-23 05:28:57,813 org:org-name env:env-name api:apiproxy-name rev:revision-number messageid:message_id NIOThread@0 ERROR HTTP.CLIENT - HTTPClient$Context.handshakeFailed() : SSLClientChannel[C:IP address:port # Remote host:IP address:port #]@65461 useCount=1 bytesRead=0 bytesWritten=0 age=529ms lastIO=529ms handshake failed, message: Received fatal alert: bad_certificate 2017-10-23 05:28:57,813 org:org-name env:env-name api:apiproxy-name rev:revision-number messageid:message_id NIOThread@0 ERROR HTTP.CLIENT - HTTPClient$Context.handshakeFailed() : SSLInfo: KeyStore:java.security.KeyStore@52de60d9 KeyAlias:KeyAlias TrustStore:java.security.KeyStore@6ec45759 2017-10-23 05:28:57,814 org:org-name env:env-name api:apiproxy-name rev:revision-number messageid:message_id NIOThread@0 ERROR ADAPTORS.HTTP.FLOW - RequestWriteListener.onException() : RequestWriteListener.onException(HTTPRequest@6071a73d) javax.net.ssl.SSLException: Received fatal alert: bad_certificate at sun.security.ssl.Alerts.getSSLException(Alerts.java:208) ~[na:1.8.0_101] at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1666) ~[na:1.8.0_101] at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1634) ~[na:1.8.0_101] at sun.security.ssl.SSLEngineImpl.recvAlert(SSLEngineImpl.java:1800) ~[na:1.8.0_101] at com.apigee.nio.NIOSelector$SelectedIterator.findNext(NIOSelector.java:496) [nio-1.0.0.jar:na] at com.apigee.nio.util.NonNullIterator.computeNext(NonNullIterator.java:21) [nio-1.0.0.jar:na] at com.apigee.nio.util.AbstractIterator.hasNext(AbstractIterator.java:47) [nio-1.0.0.jar:na] at com.apigee.nio.NIOSelector$2.findNext(NIOSelector.java:312) [nio-1.0.0.jar:na] at com.apigee.nio.NIOSelector$2.findNext(NIOSelector.java:302) [nio-1.0.0.jar:na] at com.apigee.nio.util.NonNullIterator.computeNext(NonNullIterator.java:21) [nio-1.0.0.jar:na] at com.apigee.nio.util.AbstractIterator.hasNext(AbstractIterator.java:47) [nio-1.0.0.jar:na] at com.apigee.nio.handlers.NIOThread.run(NIOThread.java:59) [nio-1.0.0.jar:na]
訊息處理器記錄檔有錯誤的堆疊追蹤記錄
Received fatal alert: bad_certificate,但沒有任何其他資訊指出問題原因。
- 如要取得失敗 API 要求的訊息 ID,請在追蹤記錄中,找出 AX 指示的階段,並判斷錯誤標頭「
- 如要進一步調查這個問題,請使用 tcpdump 工具擷取 TCP/IP 封包。
- 如果您是私有雲使用者,則可以在後端伺服器或訊息處理器上擷取 TCP/IP 封包。最好在後端伺服器上擷取封包,因為封包會在後端伺服器上解密。
- 如果您是公有雲使用者,請擷取後端伺服器上的 TCP/IP 封包。
- 決定要擷取 TCP/IP 封包的位置後,請使用下列 tcpdump 指令擷取 TCP/IP 封包。
tcpdump -i any -s 0 host <IP address> -w <File name>
如果您要在訊息處理器上擷取 TCP/IP 封包,請在
tcpdump指令中使用後端伺服器的公開 IP 位址。如果後端伺服器/訊息處理器有多個 IP 位址,則必須使用不同的 tcpdump 指令。如要進一步瞭解這項工具和這個指令的其他變體,請參閱 tcpdump。
- 使用 Wireshark 工具或您熟悉的類似工具,分析 TCP/IP 封包。
以下是使用 Wireshark 工具分析的 TCP/IP 封包資料範例:

- 上述 tcpdump 中的訊息 #4 顯示,訊息處理器 (來源) 將「Client Hello」訊息傳送至後端伺服器 (目的地)。
- 訊息 #5 顯示後端伺服器確認來自訊息處理器的 Client Hello 訊息。
- 後端伺服器會傳送「Server Hello」訊息和憑證,然後要求用戶端在訊息 #7 中傳送憑證。
- 訊息處理器會完成憑證驗證,並在訊息 #8 中確認後端伺服器的 ServerHello 訊息。
- 訊息處理器會在訊息 #9 中將憑證傳送至後端伺服器。
- 後端伺服器會在訊息 #11 中確認收到訊息處理器的憑證。
不過,它會立即將「Fatal Alert: Bad Certificate」傳送至訊息處理器 (Message #12)。這表示訊息處理器傳送的憑證有問題,因此後端伺服器無法通過憑證驗證。因此,SSL 握手程序失敗,連線將會關閉。

現在來查看訊息 #9,檢查訊息處理器傳送的憑證內容:

- 如您所見,後端伺服器並未從用戶端取得任何憑證 (憑證長度:0)。因此後端伺服器會傳送嚴重警示:憑證無效。
- 通常發生這種情況時,用戶端 (即訊息處理器,以 Java 為基礎的程序) 會:
- 金鑰儲存庫中沒有任何用戶端憑證;或
- 無法傳送用戶端憑證。如果找不到由後端伺服器可接受的憑證授權單位核發的憑證,就可能發生這種情況。也就是說,如果用戶端葉子憑證的憑證授權單位 (即鏈結中的第一個憑證) 與任何後端伺服器可接受的憑證授權單位不符,訊息處理器就不會傳送憑證。
以下將分別說明這些原因。
原因:沒有用戶端憑證
診斷
如果目標端點的 SSL 資訊部分或目標端點中使用的目標伺服器,沒有在 Keystore 中指定憑證,就會導致這個錯誤。
請按照下列步驟判斷是否為這個原因:
- 請按照下列步驟,找出特定 API Proxy 的目標端點或目標伺服器所使用的金鑰儲存區:
- 從目標端點或目標伺服器中的「SSLInfo」部分,取得「Keystore」元素的 KeyStore 參照名稱。
以下是目標端點設定中的 SSLInfo 範例:
<SSLInfo> <Enabled>true</Enabled> <ClientAuthEnabled>true</ClientAuthEnabled> <KeyStore>ref://myKeystoreRef</KeyStore> <KeyAlias>myKey</KeyAlias> <TrustStore>ref://myTrustStoreRef</TrustStore> </SSLInfo>
- 在上述範例中,Keystore 參照名稱為「myKeystoreRef"。
- 前往 Edge UI,然後選取「API Proxies」->「Environment Configurations」。
選取「參考資料」分頁標籤,然後搜尋 KeyStore 參考名稱。 記下特定金鑰儲存區參照「參照」欄中的名稱。 這會是您的金鑰儲存庫名稱。

- 在上述範例中,您會發現 myKeystoreRef 參照了「myKeystore」。因此金鑰儲存庫名稱為 myKeystore。
- 從目標端點或目標伺服器中的「SSLInfo」部分,取得「Keystore」元素的 KeyStore 參照名稱。
- 使用 Edge UI 或 List certs for keystore API,檢查這個 Keystore 是否包含憑證。
- 如果金鑰儲存庫確實包含憑證,請前往「原因:憑證授權單位不符」。
- 如果 Keystore 不含任何憑證,這就是訊息處理器未傳送用戶端憑證的原因。
解析度
- 請確認已將正確且完整的用戶端憑證鏈結上傳至訊息處理器的特定 KeyStore。
原因:憑證授權單位不符
一般來說,當伺服器要求用戶端傳送憑證時,會指出接受的簽發者或憑證授權單位組合。如果訊息處理器 Keystore 中,葉子憑證 (即憑證鏈結中的第一個憑證) 的簽發者/憑證授權單位,與後端伺服器接受的憑證授權單位不符,訊息處理器 (即以 Java 為基礎的程序) 就不會將憑證傳送至後端伺服器。
請按照下列步驟確認是否為這種情況:
- 列出 Keystore API 的憑證。
- 使用「Get cert for keystore API」,取得您在上述步驟 1 中取得的每個憑證詳細資料。
- 記下儲存在金鑰儲存區中的分葉憑證簽發者 (即憑證鏈結中的第一個憑證)。
葉節點憑證範例
{ "certInfo" : [ { "basicConstraints" : "CA:FALSE", "expiryDate" : 1578889324000, "isValid" : "Yes", "issuer" : "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com", "publicKey" : "RSA Public Key, 2048 bits", "serialNumber" : "65:00:00:00:d2:3e:12:d8:56:fa:e2:a9:69:00:06:00:00:00:d2", "sigAlgName" : "SHA256withRSA", "subject" : "CN=nonprod-api.mycompany.com, OU=ITS, O=MyCompany, L=MELBOURNE, ST=VIC, C=AU", "subjectAlternativeNames" : [ ], "validFrom" : 1484281324000, "version" : 3 } ], "certName" : "nonprod-api.mycompany.com.key.pem-cert" }在上述範例中,簽發者/憑證授權單位為
"CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com" - 使用下列其中一種技術,判斷後端伺服器接受的簽發者或憑證授權單位清單:
技巧 1:使用下列 openssl 指令:
openssl s_client -host <backend server host name> -port <Backend port#> -cert <Client Certificate> -key <Client Private Key>
請參閱這項指令輸出內容中,標題為「Acceptable Client Certificate CA names」(可接受的用戶端憑證 CA 名稱) 的部分,如下所示:
Acceptable client certificate CA names /C=AU/ST=VIC/L=MELBOURNE/O=MyCompany/OU=ITS/CN=nonprod-api.mycompany.com /C=AU/ST=VIC/L=MELBOURNE/O=MyCompany/OU=ITS/CN=nonprod-api.mycompany.com
方法 2:檢查 TCP/IP 封包中的
Certificate Request封包,後端伺服器會要求用戶端傳送憑證:在上述 TCP/IP 封包範例中,
Certificate Request封包是訊息 #7。請參閱「Distinguished Names」(識別名稱) 一節,其中包含後端伺服器的可接受憑證授權單位。
確認步驟 3 中取得的憑證授權單位,是否與步驟 4 中取得的後端伺服器接受的簽發者或憑證授權單位清單相符。如果兩者不符,訊息處理器就不會將用戶端憑證傳送至後端伺服器。
在上述範例中,您會發現訊息處理器的 Keystore 中,用戶端葉子憑證的簽發者與後端伺服器的可接受憑證授權單位不符。因此,訊息處理器不會將用戶端憑證傳送至後端伺服器。這會導致 SSL 交握失敗,後端伺服器會傳送「
Fatal alert: bad_certificate」訊息。
解析度
- 請確認發行者/憑證授權單位與用戶端葉子憑證 (鏈結中的第一個憑證) 的發行者/憑證授權單位相符的憑證,已儲存在後端伺服器的信任儲存區中。
- 在本 Playbook 所述的範例中,我們將發行者為
"issuer" : "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com"的憑證新增至後端伺服器的 Truststore,解決了這個問題。
如果問題仍未解決,請參閱「必須收集的診斷資訊」。
必須收集診斷資訊
如果按照上述指示操作後問題仍未解決,請收集下列診斷資訊。請聯絡 Apigee Edge 支援團隊並提供下列資訊:
- 如果您是公有雲使用者,請提供下列資訊:
- 機構名稱
- 環境名稱
- API Proxy 名稱
- 完成 curl 指令,重現錯誤
- 顯示錯誤的追蹤記錄檔
- 在後端伺服器上擷取的 TCP/IP 封包
- 如果您是 Private Cloud 使用者,請提供下列資訊:
- 出現的完整錯誤訊息
- API Proxy 套裝組合
- 顯示錯誤的追蹤記錄檔
- 訊息處理器記錄
/opt/apigee/var/log/edge-message-processor/logs/system.log - 在後端伺服器或訊息處理器上擷取的 TCP/IP 封包。
- Get cert for keystore API 的輸出內容。
- 您已嘗試使用本 Playbook 中的哪些章節,以及任何其他有助於我們加快解決問題的洞察資訊。