Сбои рукопожатия SSL — неверный сертификат клиента

Вы просматриваете документацию по Apigee Edge .
См. документацию по Apigee X.

Симптом

Клиентское приложение получает код состояния HTTP 503 с сообщением «Служба недоступна» в качестве ответа на запрос API. В трассировке пользовательского интерфейса вы увидите, что error.cause имеет Received fatal alert: bad_certificate в целевом потоке запросов для неудачного запроса API.

Если у вас есть доступ к журналам обработчика сообщений, вы увидите сообщение об ошибке « Received fatal alert: bad_certificate для неудачного запроса API». Эта ошибка наблюдается во время процесса рукопожатия SSL между обработчиком сообщений и внутренним сервером в двухсторонней настройке TLS .

Сообщение об ошибке

Клиентское приложение получает следующий код ответа:

HTTP/1.1 503 Service Unavailable

Кроме того, вы можете наблюдать следующее сообщение об ошибке:

{
 "fault": {
    "faultstring":"The Service is temporarily unavailable",
    "detail":{
        "errorcode":"messaging.adaptors.http.flow.ServiceUnavailable"
    }
 }
}

Пользователи частного облака увидят следующую ошибку для конкретного запроса API в журналах обработчика сообщений /opt/apigee/var/log/edge-message-processor/system.log :

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

Возможные причины

Возможные причины этой проблемы следующие:

Причина Описание Инструкции по устранению неполадок, применимые для
Нет сертификата клиента Хранилище ключей, используемое в целевой конечной точке целевого сервера, не имеет сертификата клиента. Пользователи пограничных частных и общедоступных облаков
Несоответствие центра сертификации Центр сертификации конечного сертификата (первый сертификат в цепочке сертификатов) в хранилище ключей обработчика сообщений не соответствует ни одному из центров сертификации, принятых внутренним сервером. Пользователи пограничных частных и общедоступных облаков

Общие этапы диагностики

  1. Включите трассировку в пользовательском интерфейсе Edge, выполните вызов API и воспроизведите проблему.
  2. В результатах трассировки пользовательского интерфейса перейдите к каждой фазе и определите, где произошла ошибка. Ошибка могла произойти в целевом потоке запросов.
  3. Изучите поток, который показывает ошибку, вы должны увидеть ошибку, как показано в примере трассировки ниже:

    alt_text

  4. Как вы видите на снимке экрана выше, причиной ошибки является «Получено фатальное предупреждение: bad_certificate» .
  5. Если вы являетесь пользователем Private Cloud , следуйте приведенным ниже инструкциям:
    1. Вы можете получить идентификатор сообщения для неудачного запроса API, определив значение заголовка ошибки « X-Apigee.Message-ID » на этапе, указанном AX в трассировке.
    2. Найдите этот идентификатор сообщения в журнале обработчика сообщений /opt/apigee/var/log/edge-message-processor/system.log и определите, можете ли вы найти дополнительную информацию об ошибке:
      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 , но нет никакой дополнительной информации, указывающей на причину этой проблемы.

  6. Для дальнейшего изучения этой проблемы вам потребуется перехватить пакеты TCP/IP с помощью инструмента tcpdump .
    1. Если вы являетесь пользователем частного облака , вы можете перехватывать пакеты TCP/IP на внутреннем сервере или обработчике сообщений. Предпочтительно перехватывать их на внутреннем сервере, поскольку пакеты расшифровываются на внутреннем сервере.
    2. Если вы являетесь пользователем общедоступного облака , захватывайте пакеты TCP/IP на внутреннем сервере.
    3. После того, как вы решили, где вы хотите перехватывать пакеты TCP/IP, используйте приведенную ниже команду tcpdump для захвата пакетов TCP/IP.
    4. tcpdump -i any -s 0 host <IP address> -w <File name>

      Если вы принимаете пакеты TCP/IP в процессоре сообщений, используйте общедоступный IP-адрес внутреннего сервера в команде tcpdump .

      Если для внутреннего сервера/обработчика сообщений используется несколько IP-адресов, вам необходимо использовать другую команду tcpdump. Обратитесь к tcpdump для получения дополнительной информации об этом инструменте и других вариантах этой команды.

  7. Проанализируйте пакеты TCP/IP с помощью инструмента Wireshark или аналогичного инструмента, с которым вы знакомы.

Вот анализ примера данных пакетов TCP/IP с помощью инструмента Wireshark:

alt_text

  1. Сообщение № 4 в приведенном выше tcpdump показывает, что обработчик сообщений (источник) отправил сообщение «Client Hello» на внутренний сервер (назначение).
  2. Сообщение № 5 показывает, что внутренний сервер подтверждает сообщение Client Hello от обработчика сообщений.
  3. Бэкенд-сервер отправляет сообщение «Привет серверу» вместе со своим сертификатом, а затем запрашивает у клиента отправить свой сертификат в сообщении № 7.
  4. Процессор сообщений завершает проверку сертификата и подтверждает сообщение ServerHello внутреннего сервера в сообщении № 8.
  5. Процессор сообщений отправляет свой сертификат на внутренний сервер в сообщении № 9.
  6. Бэкенд-сервер подтверждает получение сертификата обработчика сообщений в сообщении №11.
  7. Однако он немедленно отправляет фатальное предупреждение: неверный сертификат обработчику сообщений (сообщение № 12). Это указывает на то, что сертификат, отправленный обработчиком сообщений, был неверным, и, следовательно, проверка сертификата на внутреннем сервере завершилась неудачно. В результате рукопожатие SSL не удалось, и соединение будет закрыто.


    alt_text

  8. Давайте теперь посмотрим на сообщение № 9, чтобы проверить содержимое сертификата, отправленного обработчиком сообщений:


    alt_text

  9. Как вы можете заметить, внутренний сервер не получил никакого сертификата от клиента ( длина сертификата: 0) . Следовательно, внутренний сервер отправляет Fatal Alert: Bad Certificate.
  10. Обычно это происходит, когда клиент, то есть обработчик сообщений (процесс на основе Java):
    1. Не имеет сертификата клиента в своем хранилище ключей или;
    2. Не удается отправить сертификат клиента. Это может произойти, если он не может найти сертификат, выданный одним из допустимых центров сертификации внутреннего сервера. Это означает, что если центр сертификации конечного сертификата клиента (т. е. первый сертификат в цепочке) не соответствует ни одному из допустимых центров сертификации внутреннего сервера, то обработчик сообщений не отправит сертификат.

Давайте рассмотрим каждую из этих причин отдельно следующим образом.

Причина: нет сертификата клиента

Диагноз

Если в хранилище ключей нет сертификата, указанного в разделе «Информация SSL» целевой конечной точки или целевого сервера, используемого в целевой конечной точке, это является причиной этой ошибки.

Выполните следующие шаги, чтобы определить, является ли это причиной:

  1. Определите хранилище ключей, используемое в целевой конечной точке или целевом сервере для конкретного прокси-сервера API, выполнив следующие действия:
    1. Получите ссылочное имя хранилища ключей из элемента хранилища ключей в разделе SSLInfo в целевой конечной точке или на целевом сервере.

      Давайте посмотрим на пример раздела SSLInfo в конфигурации целевой конечной точки:

      <SSLInfo>
        <Enabled>true</Enabled>
        <ClientAuthEnabled>true</ClientAuthEnabled>
        <KeyStore>ref://myKeystoreRef</KeyStore>
        <KeyAlias>myKey</KeyAlias>
        <TrustStore>ref://myTrustStoreRef</TrustStore>
      </SSLInfo>
    2. В приведенном выше примере имя ссылки на хранилище ключей — « myKeystoreRef».
    3. Перейдите в пользовательский интерфейс Edge и выберите Прокси-серверы API -> Конфигурации среды.

      Выберите вкладку «Ссылки» и найдите имя ссылки на хранилище ключей. Запишите имя в столбце «Ссылка» для конкретной ссылки на хранилище ключей. Это будет имя вашего хранилища ключей.


      alt_text

    4. В приведенном выше примере вы можете заметить, что myKeystoreRef имеет ссылку на «myKeystore». Следовательно, имя хранилища ключей — myKeystore.
  2. Проверьте, содержит ли это хранилище ключей сертификат, используя пользовательский интерфейс Edge или список сертификатов для API хранилища ключей .
  3. Если хранилище ключей содержит сертификаты, перейдите к разделу «Причина: несоответствие центра сертификации» .
  4. Если хранилище ключей не содержит никакого сертификата, то это причина, по которой клиентский сертификат не отправляется обработчиком сообщений.

Разрешение

  1. Убедитесь, что правильная и полная цепочка сертификатов клиента загружена в определенное хранилище ключей в обработчике сообщений.

Причина: несоответствие центра сертификации

Обычно, когда Сервер запрашивает у Клиента отправку своего Сертификата, он указывает набор принятых Эмитентов или Центров сертификации. Если эмитент/центр сертификации конечного сертификата (т. е. первый сертификат в цепочке сертификатов) в хранилище ключей процессора сообщений не соответствует ни одному из центров сертификации, принятых внутренним сервером, тогда процессор сообщений (который представляет собой процесс на основе Java) ) не будет отправлять сертификат на внутренний сервер.

Используйте следующие шаги, чтобы убедиться, что это так:

  1. Список сертификатов для API хранилища ключей .
  2. Получите сведения о каждом сертификате, полученном на шаге 1 выше, с помощью Get cert for keystore API .
  3. Запишите эмитента конечного сертификата (т. е. первого сертификата в цепочке сертификатов), хранящегося в хранилище ключей.

    Образец листового сертификата

    {
      "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"

  4. Определите допустимый список эмитентов или центров сертификации внутреннего сервера, используя один из следующих методов:

    Метод № 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
    /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: проверьте пакет Certificate Request в пакетах TCP / IP, где внутренний сервер запрашивает у клиента отправить свой сертификат:

    В примерах пакетов TCP/IP, показанных выше, пакет Certificate Request — это сообщение №7. Обратитесь к разделу «Отличительные имена», который содержит допустимые центры сертификации внутреннего сервера.

    alt_text

  5. Убедитесь, что центр сертификации, полученный на шаге № 3, совпадает со списком принятых эмитентов или центров сертификации внутреннего сервера, полученным на шаге № 4. Если есть несоответствие, обработчик сообщений не отправит сертификат клиента на внутренний сервер.

    В приведенном выше примере вы можете заметить, что эмитент листового сертификата клиента в хранилище ключей обработчика сообщений не соответствует ни одному из принятых центров сертификации внутреннего сервера. Следовательно, обработчик сообщений не отправляет сертификат клиента на внутренний сервер. Это приводит к сбою рукопожатия SSL, и внутренний сервер отправляет сообщение « Fatal alert: bad_certificate ».

Разрешение

  1. Убедитесь, что сертификат с эмитентом/центром сертификации, который соответствует эмитенту/центру сертификации конечного сертификата клиента (первый сертификат в цепочке), хранится в хранилище доверенных сертификатов внутреннего сервера.
  2. В примере, описанном в этом Playbook, сертификат с "issuer" : "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com" добавлен к серверной части. Truststore сервера, чтобы решить проблему.

Если проблема не устранена, перейдите к разделу «Обязательно собрать диагностическую информацию» .

Необходимо собрать диагностическую информацию

Если проблема не устранена даже после выполнения приведенных выше инструкций, соберите следующую диагностическую информацию. Свяжитесь и поделитесь ими со службой поддержки Apigee Edge :

  1. Если вы являетесь пользователем общедоступного облака, предоставьте следующую информацию:
    1. Название организации
    2. Имя среды
    3. Имя прокси-сервера API
    4. Завершите команду curl, чтобы воспроизвести ошибку
    5. Файл трассировки, показывающий ошибку
    6. Пакеты TCP/IP, перехваченные на внутреннем сервере
  2. Если вы являетесь пользователем частного облака, предоставьте следующую информацию:
    1. Полное сообщение об ошибке наблюдается
    2. Пакет API-прокси
    3. Файл трассировки, показывающий ошибку
    4. Журналы процессора сообщений /opt/apigee/var/log/edge-message-processor/logs/system.log
    5. Пакеты TCP/IP, захваченные на внутреннем сервере или процессоре сообщений.
    6. Вывод Get cert для API хранилища ключей .
  3. Подробная информация о том, какие разделы в этом Playbook вы пробовали, и любая другая информация, которая поможет нам ускорить решение этой проблемы.