SSLHandshakeException при попытке доступа к экземпляру ES из Docker - PullRequest
0 голосов
/ 10 июня 2019

Я пытаюсь получить доступ к экземпляру 6.x ES с помощью клиента REST высокого уровня 6.7.2. Доступ к этому экземпляру ES предоставляется мне через имя хоста (https://****.azureedge.net), имя пользователя и пароль.

Мое приложение Spring Boot без проблем получает данные из той же ES, когда оно запускается из моей среды разработки (IDE), но выдает исключение SSLHandshakeException, как только я пытаюсь запустить его из контейнера Docker (с моей машины разработки или кластера K8s в облаке). ).

Контейнер сделан с базовым образом: FROM debian:stretch-slim & OpenJDK 11.0.2 с необходимыми модулями Spring Boot.

Я добился некоторого прогресса в отладке с -Djavax.net.debug=all. Оказывается, что во время работы в образе докера происходит всего несколько первых шагов обычного SSL-квитирования:

Produced ClientHello handshake message
WRITE: TLS13 handshake, length = 2352
Raw write
Raw read (0000: 15 03 03 00 02 02 28    ......(   )
READ: TLSv1.2 alert, length = 2
Received alert message (
  "Alert": {
    "level"      : "fatal",
    "description": "handshake_failure"
  }
)

, за которым следует SSLHandshakeException:

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at org.elasticsearch.client.RestClient$SyncResponseListener.get(RestClient.java:938)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:227)
at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1764)
at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:1749)
at org.elasticsearch.client.RestHighLevelClient.performRequestAndParseEntity(RestHighLevelClient.java:1708)
at org.elasticsearch.client.SecurityClient.getSslCertificates(SecurityClient.java:508) 
....
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at java.base/sun.security.ssl.Alert.createSSLException(Unknown Source)
at java.base/sun.security.ssl.Alert.createSSLException(Unknown Source)
at java.base/sun.security.ssl.TransportContext.fatal(Unknown Source)
at java.base/sun.security.ssl.Alert$AlertConsumer.consume(Unknown Source)
at java.base/sun.security.ssl.TransportContext.dispatch(Unknown Source)
at java.base/sun.security.ssl.SSLTransport.decode(Unknown Source)
at java.base/sun.security.ssl.SSLEngineImpl.decode(Unknown Source)
at java.base/sun.security.ssl.SSLEngineImpl.readRecord(Unknown Source)
at java.base/sun.security.ssl.SSLEngineImpl.unwrap(Unknown Source)
at java.base/sun.security.ssl.SSLEngineImpl.unwrap(Unknown Source)
at java.base/javax.net.ssl.SSLEngine.unwrap(Unknown Source)
at org.apache.http.nio.reactor.ssl.SSLIOSession.doUnwrap(SSLIOSession.java:271)
at org.apache.http.nio.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:316)
at org.apache.http.nio.reactor.ssl.SSLIOSession.isAppInputReady(SSLIOSession.java:509)
at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:120)
at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276)
at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:591)

При запуске из моего локального окружения рукопожатие выглядит непрерывно:

Produced ClientHello handshake message
WRITE: TLS13 handshake, length = 460
Raw write
Raw read
READ: TLSv1.2 handshake, length = 155
Consuming ServerHello
ServerHello
Negotiated protocol version: TLSv1.3
Session initialized:  Session(1560119025211|TLS_AES_256_GCM_SHA384)
WRITE: TLS13 change_cipher_spec, length = 1
Raw write
Raw read
READ: TLSv1.2 change_cipher_spec, length = 1
Consuming ChangeCipherSpec message
Raw read
READ: TLSv1.2 application_data, length = 27
...
Raw read
READ: TLSv1.2 application_data, length = 8469
Consuming server Certificate handshake message
... // here is the list of 3 certificates with "SHA256withRSA", "SHA256withRSA", "SHA1withRSA" signature algorithms
Found trusted certificate ⇢ SHA1withRSA
...

Работая локально, я заметил CN=Microsoft IT TLS CA 2, OU=Microsoft IT, O=Microsoft Corporation, L=Redmond, ST=Washington, C=US, а также CN=Baltimore CyberTrust Root, OU=CyberTrust, O=Baltimore, C=IE как эмитентов, возможно, это важно, но я предполагаю, что это ожидается с учетом адреса хоста ES (Azure).

В заключение я хотел подчеркнуть, что мне не нужно было делать ничего особенного, чтобы сделать эту работу в моей macOS Java 11.0.2 среде разработки.

Я уже пытался следовать, но это ничего не изменило:

  • Изменение базового образа Docker со «тонкого» на несжатый вариант
  • Использование OpenJDK 11.0.1 или 11.0.2
  • Добавлен сертификат от хоста в TrustStore, который JVM использует во время выполнения. (Я проверил в контейнере Docker, что действительно есть еще один сертификат, но учитывая, когда сбой рукопожатия происходит, я думаю, что это не имеет значения)
  • попытался принудительно применить приложение с помощью: "-Dcom.sun.net.ssl.enableECC = false", "-Djdk.tls.client.protocols = TLSv1.3", "-Dhttps.protocols = TLSv1.3", не помогло

Интересно: завиток из образа Docker с BasicAuth «общается» с тем же URL-адресом без проблем (рукопожатие завершено) и небольшой запрос возвращает результаты. Я предполагаю, что curl и JVM используют разные источники доверенных CA внутри Docker, разные алгоритмы для квитирования связи и т. Д.

Заранее спасибо за любую помощь

1 Ответ

0 голосов
/ 13 июня 2019

TLDR: принудительное применение TLSv1.2 для клиента в приложении завершило рукопожатие из докера

После множества попыток попытки / неудачи я сделал этоРабота.Следующие вещи не имели никакого значения:

  • , используя не "тонкий" базовый образ Debian вместо "slim"
  • , используя OpenJDK 11.0.2 вместо 11.0.1
  • добавление сертификата хоста в JVM TrustedStore при создании образа докера, чтобы он был доступен при запуске контейнера.
  • принудительное применение com.sun.net.ssl.enableECC=false
  • принудительное применение TLSv1.3 для https.protocols и / или jdk.tls.client.protocols
  • применение TLSv1.2 для https.protocols

Что исправило рукопожатие с хостом, приводило в исполнение TLSv1.2 для клиента с помощью -Djdk.tls.client.protocols=TLSv1.2 в Dockerfile, поэтому приложение работает с этим флагом внутри контейнера.Это позволило SSL рукопожатие завершить, так как оно должно работать в любом случае.По какой-то причине фактические переговоры о версии протокола не работали без применения более низкой версии протокола для клиента.Журналы из локальной среды vs docker не показывают никакой разницы, но это помогло в docker.

Что помогло мне выяснить это:

  • установка javax.net.debug=ssl:handshake или даже более подробно javax.net.debug=all, чтобы я мог видеть детали попыток рукопожатия
  • , подтверждающихчто «хотя бы кто-то» может установить исходящую связь из докера, используя curl для отправки того же запроса, что и приложение, которое сработало, потому что curl каким-то образом выяснил, как выполнить рукопожатие с хостом.
  • pure luck

Спасибо всем за поддержку и идеи

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...