Ошибки установления 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

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

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

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

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

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

    alt_text

  4. Как вы видите на скриншоте выше, error.cause«Получено фатальное предупреждение: 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. Внутренний сервер отправляет сообщение «Server Hello» вместе со своим сертификатом, а затем запрашивает у клиента отправить свой сертификат в сообщении № 7.
  4. Процессор сообщений завершает проверку сертификата и подтверждает сообщение ServerHello внутреннего сервера в сообщении № 8.
  5. Процессор сообщений отправляет свой сертификат на внутренний сервер в сообщении №9.
  6. Внутренний сервер подтверждает получение сертификата обработчика сообщений в сообщении № 11.
  7. Однако он немедленно отправляет процессору сообщений фатальное предупреждение: плохой сертификат (сообщение № 12). Это указывает на то, что сертификат, отправленный обработчиком сообщений, был недействительным и, следовательно, проверка сертификата на внутреннем сервере не удалась. В результате SSL-квитирование не удалось и соединение будет закрыто.


    alt_text

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


    alt_text

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

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

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

Диагностика

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

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

  1. Определите хранилище ключей, используемое в целевой конечной точке или целевом сервере для конкретного прокси-сервера API, выполнив следующие действия:
    1. Получите справочное имя хранилища ключей из элемента Keystore в разделе 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 выше, с помощью 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. В примере, описанном в этой книге, в серверную часть был добавлен сертификат с эмитентом "issuer" : "CN=MyCompany Test SHA2 CA G2, DC=testcore, DC=test, DC=dir, DC=mycompany, DC=com" хранилище доверенных сертификатов сервера, чтобы решить проблему.

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

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

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

  1. Если вы являетесь пользователем Public Cloud, предоставьте следующую информацию:
    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. Вывод команды «Получить сертификат для API хранилища ключей» .
  3. Подробная информация о том, какие разделы этого руководства вы пробовали, а также любые другие сведения, которые помогут нам ускорить решение этой проблемы.