503 服务不可用 - SSL 握手失败

您正在查看的是 Apigee Edge 文档。
转到 Apigee X 文档
信息

问题

客户端应用收到 HTTP 状态代码 503 Service Unavailable 及错误代码 messaging.adaptors.http.flow.SslHandshakeFailed,作为 API 调用的响应。

错误消息

客户端应用会获得以下响应代码:

HTTP/1.1 503 Service Unavailable

此外,您可能还会看到以下错误消息:

{
   "fault":{
      "faultstring":"SSL Handshake failed sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target",
      "detail":{
         "errorcode":"messaging.adaptors.http.flow.SslHandshakeFailed"
      }
   }
}

可能的原因

由于多种原因,Apigee Edge 的消息处理器和后端服务器之间的 SSL 握手过程失败了,您可能会收到状态代码 503 Service Unavailable 和错误代码 messaging.adaptors.http.flow.SslHandshakeFailedfaultstring 中的错误消息通常指示导致此错误的高级别原因。

根据在 faultstring 中观察到的错误消息,您需要采用适当的方法排查问题。本指南介绍了如何在 faultstring 中发现错误消息 SSL Handshake failed sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 时排查此错误。

在 Apigee Edge 的消息处理器和后端服务器之间的 SSL 握手过程中会出现此错误:

  • 如果 Apigee Edge 消息处理器的 truststore
    • 包含与后端服务器的完整证书链不匹配的证书链,或
    • 不包含后端服务器的完整证书链
  • 如果后端服务器提供的证书链:
    • 包含与目标端点中指定的主机名不匹配的 完全限定域名 (FQDN)
    • 包含的证书链不正确或不完整

导致此问题的可能原因如下:

原因 说明 适用的问题排查说明
消息处理器的信任库中的证书或证书链不正确/不完整 存储在 Apigee Edge 消息处理器的信任库中的证书和/或其链与后端服务器的证书链不一致,或不包含后端服务器的完整证书链。 Edge Private 和公有云用户
后端服务器证书中的 FQDN 与目标端点中的主机名不匹配 后端服务器提供的证书包含与目标端点中指定的主机名不匹配的 FQDN。 Edge Private 和公有云用户
后端服务器提供的证书或证书链不正确/不完整 后端服务器提供的证书链不正确或不完整。 Edge Private 和公有云用户

常见诊断步骤

使用以下工具/技巧之一来诊断此错误:

API 监控

过程 1:使用 API 监控

要使用 API Monitoring 诊断错误,请执行以下操作:

  1. 以拥有 适当角色的用户身份 登录 Apigee Edge 界面
  2. 切换到您要调查问题的组织。

  3. 前往 Analyze > API Monitoring > Investigate 页面。
  4. 选择您发现错误的具体时间范围。
  5. 根据时间绘制故障代码

  6. 选择具有错误代码 messaging.adaptors.http.flow.SslHandshakeFailed 的单元格,如下所示:

    查看大图

  7. 错误代码 messaging.adaptors.http.flow.SslHandshakeFailed 的相关信息如下所示:

    查看大图

  8. 点击查看日志 ,然后展开失败请求所在的行。

    查看大图

  9. 日志窗口中,请注意以下详细信息:
    • 请求消息 ID
    • 状态代码503
    • 错误来源target
    • 错误代码messaging.adaptors.http.flow.SslHandshakeFailed

跟踪记录

过程 2:使用跟踪工具

如需使用跟踪工具诊断错误,请执行以下操作:

  1. 启用跟踪会话,然后:
    • 等待发生 503 Service Unavailable 错误(错误代码为 messaging.adaptors.http.flow.SslHandshakeFailed),或者
    • 如果您可以重现问题,请进行 API 调用以重现问题 503 Service Unavailable
  2. 确保已启用 Show all FlowInfos

  3. 选择其中一个失败的请求并检查跟踪记录。
  4. 浏览跟踪记录的不同阶段,并找到失败的位置。
  5. 您通常在目标请求流程开始阶段后会发现该错误,如下所示:

    查看大图

  6. 注意跟踪记录中的以下值:
    • 错误SSL Handshake failed sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    • error.cause:PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    • error.class:com.apigee.errors.http.server.ServiceUnavailableException
    • 错误 SSL Handshake failed sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 的值表示 SSL 握手失败,因为 Apigee Edge 的消息处理器无法验证后端服务器的证书。
  7. 进入跟踪记录中的 AX(已记录 Google Analytics(分析)数据)阶段,然后点击该阶段。
  8. 向下滚动到 Phase Details Error Headers 部分,并确定 X-Apigee-fault-codeX-Apigee-fault-sourceX-Apigee-Message-ID 的值,如下所示:

    查看大图

  9. 请注意 X-Apigee-fault-codeX-Apigee-fault-sourceX-Apigee-Message-ID 的值:
  10. 错误标头
    X-Apigee-fault-code messaging.adaptors.http.flow.SslHandshakeFailed
    X-Apigee-fault-source target
    X-Apigee-Message-ID MESSAGE_ID

NGINX

过程 3:使用 NGINX 访问日志

如需使用 NGINX 访问日志诊断错误,请执行以下操作:

  1. 如果您是 Private Cloud 用户,则可以使用 NGINX 访问日志来确定有关 HTTP 503 Service Unavailable 的关键信息。
  2. 检查 NGINX 访问日志:

    /opt/apigee/var/log/edge-router/nginx/ORG~ENV.PORT#_access_log

  3. 搜索以查看在特定持续时间内是否存在任何错误代码为 messaging.adaptors.http.flow.SslHandshakeFailed503 错误(如果问题是过去发生的),或者是否有任何请求仍然失败并显示 503
  4. 如果您确实发现任何 503 错误,且 X-Apigee-fault-code messaging.adaptors.http.flow.SslHandshakeFailed 的值匹配,则确定 X-Apigee-fault-source 的值。

    NGINX 访问日志中的 503 错误示例

    查看大图

    NGINX 访问日志中的上述示例条目具有 X-Apigee-fault-code X-Apigee-fault-code 的以下值:

    标头
    X-Apigee-fault-code messaging.adaptors.http.flow.SslHandshakeFailed
    X-Apigee-fault-source target

消息处理器日志

过程 4:使用消息处理器日志

  1. 按照常见诊断步骤中的说明,使用 API Monitoring、Trace 工具或 NGINX 访问日志确定其中一个失败请求的消息 ID。
  2. 在消息处理器日志 (/opt/apigee/var/log/edge-message-processor/logs/system.log) 中搜索特定的请求消息 ID。您可能会看到以下错误:

    org:myorg env:test api:MyProxy rev:1
    messageid:myorg-28247-3541813-1
    NIOThread@1 ERROR HTTP.CLIENT - HTTPClient$Context.handshakeFailed() :
    SSLClientChannel[Connected: Remote:X.X.X.X:443
    Local:192.168.194.140:55102]@64596 useCount=1
    bytesRead=0 bytesWritten=0 age=233ms  lastIO=233ms
    isOpen=true handshake failed, message: General SSLEngine problem
    

    上述错误表示消息处理器和后端服务器之间的 SSL 握手失败。

    之后会有包含详细堆栈轨迹的异常,如下所示:

    org:myorg env:test api:MyProxy rev:1
    messageid:myorg-28247-3541813-1
    NIOThread@1 ERROR ADAPTORS.HTTP.FLOW - RequestWriteListener.onException() :
    RequestWriteListener.onException(HTTPRequest@1522922c)
    javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    	at sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1478)
    	at sun.security.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:535)
    	... <snipped>
    Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    	at sun.security.ssl.Alerts.getSSLException(Alerts.java:203)
    	at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1728)
    	... <snipped>
    Caused by: sun.security.validator.ValidatorException: PKIX path building failed:
    sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid
    certification path to requested target
    	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
    	at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
    	... <snipped>
      

    请注意,握手失败的原因如下:

    Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

    这表示 SSL 握手失败,因为 Apigee Edge 的消息处理器无法验证后端服务器的证书。

原因:消息处理器的信任库中的证书或证书链不正确/不完整

诊断

  1. 按照常见诊断步骤中所述,使用 API 监控、Trace 工具或 NGINX 访问日志确定观察到的错误的故障代码故障来源
  2. 如果 Fault Codemessaging.adaptors.http.flow.SslHandshakeFailed,则使用以下方法之一确定错误消息:
  3. 如果错误消息为 sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target",则表示 SSL 握手失败,因为 Apigee Edge 的消息处理器无法验证后端服务器的证书。

您可以分两个阶段来调试此问题:

  1. 第 1 阶段:确定后端服务器的证书链
  2. 第 2 阶段:比较存储在消息处理器的信任库中的证书链

第 1 阶段

第 1 阶段:确定后端服务器的证书链

您可以使用以下方法之一确定后端服务器的证书链:

openssl

对后端服务器的主机名执行 openssl 命令,如下所示:

openssl s_client -connect BACKEND_SERVER_HOST_NAME:PORT#

请注意上述命令输出的证书链:

openssl 命令输出中的后端服务器证书链示例

Certificate chain
 0 s:/CN=mocktarget.apigee.net
   i:/C=US/O=Google Trust Services LLC/CN=GTS CA 1D4
 1 s:/C=US/O=Google Trust Services LLC/CN=GTS CA 1D4
   i:/C=US/O=Google Trust Services LLC/CN=GTS Root R1
 2 s:/C=US/O=Google Trust Services LLC/CN=GTS Root R1
   i:/C=US/O=Google Trust Services LLC/CN=GTS Root R1

tcpdump

  1. 如果您是公有云用户,请捕获后端服务器上的 TCP/IP 数据包。
  2. 如果您是 Private Cloud 用户,则可以捕获后端服务器或消息处理器上的 TCP/IP 数据包。最好在后端服务器上捕获这些数据包,因为数据包在后端服务器上解密。
  3. 使用以下 tcpdump 命令捕获 TCP/IP 数据包:

    tcpdump -i any -s 0 host IP_ADDRESS -w FILE_NAME
    
  4. 使用 Wireshark 工具或类似工具分析 TCP/IP 数据包。

    Tcpdump 分析示例

    查看大图

    • 数据包 #43:消息处理器(来源)向后端服务器(目的地)发送了一条 Client Hello 消息。
    • 数据包 44:后端服务器确认收到来自消息处理器的 Client Hello 消息。
    • 数据包 #45:后端服务器发送 Server Hello 消息及其证书。
    • 数据包 #46:消息处理器确认收到 Server Hello 消息和证书。
    • 数据包 47:消息处理器发送一条 FIN, ACK 消息,后跟数据包 #48 中的 RST, ACK

      这表示消息处理器对后端服务器证书进行验证失败。这是因为消息处理器没有与后端服务器的证书匹配的任何证书,或者无法信任后端服务器的证书与其(消息处理器)信任库中的可用证书。

    • 您可以返回并查看数据包 45,并确定后端服务器发送的证书链

      查看大图

    • 在此示例中,您可以看到服务器先发送一个叶证书 (common name (CN) = mocktarget.apigee.net),接着发送一个中间证书 (CN= GTS CA 1D4),再发送根证书 (CN = GTX Root R1)。

    如果您已确定服务器的证书验证失败,请转到第 2 阶段:比较后端服务器的证书和消息处理器的信任库中存储的证书

第 2 阶段

第 2 阶段:比较后端服务器的证书与存储在消息处理器的信任库中的证书

  1. 确定后端服务器的证书链
  2. 按照以下步骤确定存储在消息处理器的信任库中的证书:
    1. TargetEndpointSSLInfo 部分的 TrustStore 元素获取信任库引用名称。

      我们来看一下 TargetEndpoint 配置中的 SSLInfo 部分示例:

      <TargetEndpoint name="default">
      ...
         <HTTPTargetConnection>
            <Properties />
            <SSLInfo>
               <Enabled>true</Enabled>
               <ClientAuthEnabled>true</ClientAuthEnabled>
               <KeyStore>ref://myKeystoreRef</KeyStore>
               <KeyAlias>myKey</KeyAlias>
               <TrustStore>
                  ref://myCompanyTrustStoreRef
               </TrustStore>
            </SSLInfo>
         </HTTPTargetConnection>
         ...
      </TargetEndpoint>
      
    2. 在上述示例中,TrustStore 引用名称为 myCompanyTruststoreRef
    3. 在 Edge 界面中,依次选择环境 > 引用。记下参考列中特定信任库引用的名称。这将是您的信任库名称。

      查看大图

    4. 在上面的示例中,信任库名称为:

      myCompanyTruststoreRefmyCompanyTruststore

  3. 使用以下 API 获取存储在信任库中的证书(在上一步中确定):

    1. 获取密钥库或信任库的所有证书。此 API 会列出特定信任库中的所有证书。

      公有云用户

      curl -v -X GET https//api.enterprise.apigee.com/v1/organizations/ORGANIZATION_NAME/environments/ENVIRONMENT_NAME/keystores/KEYSTORE_NAME/certs -H "Authorization: Bearer $TOKEN"
      

      Private Cloud 用户

      curl -v -X GET http://MANAGEMENT_HOST:PORT_#/v1/organizations/ORGANIZATION_NAME/environments/ENVIRONMENT_NAME/keystores/KEYSTORE_NAME/certs -H "Authorization: Bearer $TOKEN"
      

      地点

      • ORGANIZATION_NAME 是组织的名称
      • ENVIRONMENT_NAME 是环境的名称
      • KEYSTORE_NAME 是密钥库的名称
      • 将 $TOKEN 设置为 OAuth 2.0 访问令牌,如获取 OAuth 2.0 访问令牌中所述。
      • 使用 curl 中介绍了此示例中使用的 curl 选项。

      示例输出:

      示例信任库 myCompanyTruststore 中的证书为:

      [
        "serverCert"
      ]
      

    2. 从密钥库或 Truststore 中获取特定证书的证书详情。 此 API 会返回特定信任库中特定证书的相关信息。

      公有云用户

      curl -v -X GET https//api.enterprise.apigee.com/v1/organizations/ORGANIZATION_NAME/environments/ENVIRONMENT_NAME/keystores/KEYSTORE_NAME/certs/CERT_NAME -H "Authorization: Bearer $TOKEN"
      

      Private Cloud 用户

      curl -v -X GET http://MANAGEMENT_HOST:PORT_#>/v1/organizations/ORGANIZATION_NAME/environments/ENVIRONMENT_NAME/keystores/KEYSTORE_NAME/certs/CERT_NAME -H "Authorization: Bearer $TOKEN"
      

      地点

      • ORGANIZATION_NAME 是组织的名称
      • ENVIRONMENT_NAME 是环境的名称
      • KEYSTORE_NAME 是密钥库的名称
      • CERT_NAME 是证书的名称
      • 将 $TOKEN 设置为 OAuth 2.0 访问令牌,如获取 OAuth 2.0 访问令牌中所述。
      • 使用 curl 中介绍了此示例中使用的 curl 选项。

      输出示例

      serverCert 的详细信息按如下方式显示主题和颁发者:

      叶/实体证书

      "subject": "CN=mocktarget.apigee.net",
      "issuer": "CN=GTS CA 1D4, O=Google Trust Services LLC, C=US",
      

      中间证书

      "subject" : "CN=GTS CA 1D4, O=Google Trust Services LLC, C=US",
      "issuer" : "CN=GTS Root R1, O=Google Trust Services LLC, C=US",
      
  4. 验证在第 1 步中获取的实际服务器证书与在第 3 步中获取的信任库中存储的证书是否一致。如果二者不符,那就是导致问题的原因。

    通过上例,我们一次看一个证书:

    1. 叶证书

      从后端服务器

      s:/CN=mocktarget.apigee.net
      i:/C=US/O=Google Trust Services LLC/CN=GTS CA 1D4
      

      通过消息处理器(客户端)信任库

      "subject": "CN=mocktarget.apigee.net",
      "issuer": "CN=GTS CA 1D4, O=Google Trust Services LLC, C=US",
      

      存储在信任库中的叶证书与后端服务器的叶证书匹配。

    2. 中间证书

      从后端服务器

      s:/C=US/O=Google Trust Services LLC/CN=GTS CA 1D4
      i:/C=US/O=Google Trust Services LLC/CN=GTS Root R1
      

      通过消息处理器(客户端)信任库

      "subject" : "CN=GTS CA 1D4, O=Google Trust Services LLC, C=US",
      "issuer" : "CN=GTS Root R1, O=Google Trust Services LLC, C=US",
      

      存储在信任库中的中间证书与后端服务器的中间证书匹配。

    3. 根证书

      从后端服务器

      s:/C=US/O=Google Trust Services LLC/CN=GTS Root R1
      i:/C=US/O=Google Trust Services LLC/CN=GTS Root R1
      

      消息处理器的信任库中完全缺失根证书。

    4. 由于信任库中缺少根证书,因此消息处理器会抛出以下异常:

      sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
      

      并向客户端应用返回带有错误代码 messaging.adaptors.http.flow.SslHandshakeFailed503 Service Unavailable

分辨率

  1. 请确保您的后端服务器证书链正确且完整。
  2. 如果您是公有云用户,请按照 更新云的 TLS 证书中的说明将证书更新为 Apigee Edge 的消息处理器信任库。
  3. 如果您是私有云用户,请按照 更新私有云的 TLS 证书中的说明将该证书更新为 Apigee Edge 的消息处理器信任库。

原因:后端服务器证书中的 FQDN 与目标端点中的主机名不匹配

如果后端服务器提供的证书链包含 FQDN,且该证书链与目标端点中指定的主机名不匹配,则 Apigee Edge 的消息流程将返回错误 SSL Handshake failed sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

诊断

  1. 检查您观察到此错误的 API 代理中的特定目标端点,并记下后端服务器的主机名:

    TargetEndpoint 示例

    <TargetEndpoint name="default">
       …
       <HTTPTargetConnection>
          <Properties />
          <SSLInfo>
             <Enabled>true</Enabled>
             <TrustStore>ref://myTrustStoreRef</TrustStore>
          </SSLInfo>
          <URL>https://backend.company.com/resource</URL>
       </HTTPTargetConnection>
    </TargetEndpoint>
    

    在上述示例中,后端服务器的主机名为 backend.company.com

  2. 使用 openssl 命令确定后端服务器证书中的 FQDN,如下所示:

    openssl s_client -connect BACKEND_SERVER_HOST_NAME>:PORT_#>
    

    例如:

    openssl s_client -connect backend.company.com:443
    

    检查 Certificate chain 部分,并记下叶证书主题中被指定为 CN 一部分的 FQDN。

    Certificate chain
     0 s:/CN=backend.apigee.net
       i:/C=US/O=Google Trust Services LLC/CN=GTS CA 1D4
     1 s:/C=US/O=Google Trust Services LLC/CN=GTS CA 1D4
       i:/C=US/O=Google Trust Services LLC/CN=GTS Root R1
     2 s:/C=US/O=Google Trust Services LLC/CN=GTS Root R1
       i:/C=US/O=Google Trust Services LLC/CN=GTS Root R1
    

    在上述示例中,后端服务器的 FQDN 为 backend.apigee.net

  3. 如果从第 1 步获得的后端服务器的主机名与从第 2 步获得的 FQDN 不匹配,这就是导致错误的原因。
  4. 在上述示例中,目标端点中的主机名为 backend.company.com。但是,后端服务器证书中的 FQDN 名称为 backend.apigee.net。由于它们不匹配,因此您收到此错误消息。

分辨率

您可以使用以下方法之一解决此问题:

正确的 FQDN

使用正确的 FQDN、有效且完整的证书链更新后端服务器的密钥库

  1. 如果您没有具有正确 FQDN 的后端服务器证书,请从相应的 CA(证书授权机构)获取正确的证书。
  2. 验证您拥有有效且完整的后端服务器证书链

  3. 当您在叶证书或实体证书中找到与目标端点中指定的主机名相同的有效且完整的证书链(其中包含后端服务器的正确 FQDN)后,请使用完整的证书链更新后端的密钥库

正确的后端服务器

使用正确的后端服务器的主机名更新目标端点

  1. 如果在目标端点中错误地指定了主机名,请更新目标端点,使其具有与后端服务器证书中的 FQDN 匹配的正确主机名。
  2. 保存对 API 代理的更改。

    在上述示例中,如果未正确指定后端服务器主机名,您可以使用后端服务器证书中的 FQDN(即 backend.apigee.net)进行修复,如下所示:

    <TargetEndpoint name="default">
       …
       <HTTPTargetConnection>
          <Properties />
          <SSLInfo>
             <Enabled>true</Enabled>
             <TrustStore>ref://myTrustStoreRef</TrustStore>
          </SSLInfo>
          <URL>https://backend.apigee.net/resource</URL>
       </HTTPTargetConnection>
    </TargetEndpoint>
    

原因:后端服务器提供的证书或证书链不正确/不完整

诊断

  1. 对后端服务器的主机名执行 openssl 命令,以获取后端服务器的证书链,如下所示:
    openssl s_client -connect BACKEND_SERVER_HOST_NAME:PORT_#
    

    请注意上述命令输出中的 Certificate chain

    openssl 命令输出中的后端服务器证书链示例

    Certificate chain
     0 s:/CN=mocktarget.apigee.net
       i:/C=US/O=Google Trust Services LLC/CN=GTS CA 1D4
     1 s:/C=US/O=Google Trust Services LLC/CN=GTS CA 1D4
       i:/C=US/O=Google Trust Services LLC/CN=GTS Root R1
       
  2. 按照验证证书链中的说明,验证您的证书链是否正确、完整。
  3. 如果您没有后端服务器的有效且完整的证书链,这就是导致此问题的原因。

    上面显示的示例后端服务器的证书链中缺少根证书。因此,您会遇到此错误。

分辨率

使用有效且完整的证书链更新后端服务器的密钥库:

  1. 验证您的后端服务器的证书链是否有效且完整

  2. 后端服务器的密钥库中更新有效且完整的证书链。

如果问题仍然存在,请参阅 必须收集诊断信息

必须收集的诊断信息

如果按照上述说明操作后,问题仍然存在,请收集以下诊断信息并联系 Apigee Edge 支持团队

  • 如果您是公有云用户,请提供以下信息:
    • 组织名称
    • 环境名称
    • API 代理名称
    • 完成 curl 命令以重现错误
    • 显示错误的跟踪文件
    • openssl 命令的输出:

      openssl s_client -connect BACKEND_SERVER_HOST_NAME:PORT_#

    • 在后端服务器上捕获的 TCP/IP 数据包
  • 如果您是 Private Cloud 用户,请提供以下信息:
    • 观察到完整的错误消息
    • API 代理软件包
    • 显示错误的跟踪文件
    • 消息处理器日志 /opt/apigee/var/log/edge-message-processor/logs/system.log
    • openssl 命令的输出:
      openssl s_client -connect BACKEND_SERVER_HOST_NAME:PORT_#
    • 在后端服务器或消息处理器上捕获的 TCP/IP 数据包。
    • 获取密钥库或信任库的所有证书 API 的输出,以及使用 从密钥库或 Truststore 获取证书详情 API 获取的每个证书的详细信息。

参考