Я пытаюсь защитить службу REST Java Spring Boot с помощью Keycloak. Частично это включает в себя связь между сервисом и Keycloak для получения известной конфигурации OpenID.
Когда все не зашифровано (через HTTP), все работает нормально. Когда я добавляю сертификат SSL в смесь (технически на сервере nginx перед обеими службами), я получаю ошибку рукопожатия SSL.
Если я попаду в службу REST или Keycloak напрямую в своем браузере, браузер не сообщит об ошибке SSL. Использование curl с остального сервера на машине Keycloak также выглядит нормально, и я попытался заставить nginx заставить ответ TLS 1.2 или 1.3.
Ошибка, когда реальная служба REST пытается подключиться к службе Keycloak, выглядит так:
2022-03-21 19:30:59.526 WARN 27 --- [nio-8080-exec-3] o.keycloak.adapters.KeycloakDeployment : Failed to load URLs from https://.../auth/realms/MyRealm/.well-known/openid-configuration
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131) ~[na:na]
...
Я просматривал множество других ответов, таких как этот один, но я не могу заставить службу распечатать какую-либо отладочную информацию, кроме фактического исключения. Я пробовал:
-Djavax.net.debug=ssl
в командную строку, которая запускает серверSystem.setProperty("javax.net.debug", "ssl");
в функцию main()
приложенияlogging.level.javax=TRACE
и logging.level.net=TRACE
в application.propertiesНичто меня никуда не ведет. Вывод по-прежнему имеет конец запуска сервера
2022-03-21 19:30:34.219 INFO 27 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2022-03-21 19:30:34.221 INFO 27 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms
затем сообщение об ошибке
2022-03-21 19:30:59.526 WARN 27 --- [nio-8080-exec-3] o.keycloak.adapters.KeycloakDeployment : Failed to load URLs from https://.../auth/realms/MyRealm/.well-known/openid-configuration
Как мне включить отладку, чтобы я мог выяснить, где происходит сбой рукопожатия?
---- РЕДАКТИРОВАТЬ ----
Удалось включить ведение журнала отладки - как следует из комментария ниже, пришлось добавить подкатегорию, например.
System.setProperty("javax.net.debug", "ssl:handshake");
Это производит массу вывода, я не уверен, что вижу большую часть этого полезным:
javax.net.ssl|INFO|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.238 UTC|AlpnExtension.java:182|No available application protocols
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.243 UTC|SSLExtensions.java:260|Ignore, context unavailable extension: application_layer_protocol_negotiation
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.243 UTC|SessionTicketExtension.java:408|Stateless resumption supported
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.244 UTC|SSLExtensions.java:260|Ignore, context unavailable extension: cookie
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.248 UTC|SSLExtensions.java:260|Ignore, context unavailable extension: renegotiation_info
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.248 UTC|PreSharedKeyExtension.java:662|No session to resume.
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.248 UTC|SSLExtensions.java:260|Ignore, context unavailable extension: pre_shared_key
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.250 UTC|ClientHello.java:652|Produced ClientHello handshake message (
"ClientHello": {
"client version" : "TLSv1.2",
"random" : "53 1B D2 D9 42 52 1C 8F E5 B0 E8 6A 88 0D A5 97 ED 22 83 1B CA C1 D4 26 1B 14 59 84 63 3C 99 5B",
"session id" : "4C 90 11 23 81 57 BD B5 AE 68 25 5F 32 E8 75 2B E2 8F A2 85 3A D7 76 4C F9 4C F7 16 5E 7C 02 B0",
"cipher suites" : "[TLS_AES_256_GCM_SHA384(0x1302), TLS_AES_128_GCM_SHA256(0x1301), TLS_CHACHA20_POLY1305_SHA256(0x1303), TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(0x009F), TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256(0xCCAA), TLS_DH
E_DSS_WITH_AES_256_GCM_SHA384(0x00A3), TLS_DHE_RSA_WITH_AES_128_GCM_SHA256(0x009E), TLS_DHE_DSS_WITH_AES_128_GCM_SHA256(0x00A2), TLS_DHE_RSA_WITH_AES_256_CBC_SHA256(0x006B), TLS_DHE_DSS_WITH_AES_256_CBC_SHA256(0x006A), TLS_DHE_RSA_W
ITH_AES_128_CBC_SHA256(0x0067), TLS_DHE_DSS_WITH_AES_128_CBC_SHA256(0x0040), TLS_DHE_RSA_WITH_AES_256_CBC_SHA(0x0039), TLS_DHE_DSS_WITH_AES_256_CBC_SHA(0x0038), TLS_DHE_RSA_WITH_AES_128_CBC_SHA(0x0033), TLS_DHE_DSS_WITH_AES_128_CBC_
SHA(0x0032), TLS_RSA_WITH_AES_256_GCM_SHA384(0x009D), TLS_RSA_WITH_AES_128_GCM_SHA256(0x009C), TLS_RSA_WITH_AES_256_CBC_SHA256(0x003D), TLS_RSA_WITH_AES_128_CBC_SHA256(0x003C), TLS_RSA_WITH_AES_256_CBC_SHA(0x0035), TLS_RSA_WITH_AES_
128_CBC_SHA(0x002F), TLS_EMPTY_RENEGOTIATION_INFO_SCSV(0x00FF)]",
"compression methods" : "00",
"extensions" : [
"server_name (0)": {
type=host_name (0), value=auth-service.mycompany.com
},
"status_request (5)": {
"certificate status type": ocsp
"OCSP status request": {
"responder_id": <empty>
"request extensions": {
<empty>
}
}
},
"supported_groups (10)": {
"versions": [ffdhe2048, ffdhe3072, ffdhe4096, ffdhe6144, ffdhe8192]
},
"ec_point_formats (11)": {
"formats": [uncompressed]
},
"signature_algorithms (13)": {
"signature schemes": [rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, dsa_sha256, rsa_sha224, dsa
_sha224, rsa_pkcs1_sha1, dsa_sha1]
},
"signature_algorithms_cert (50)": {
"signature schemes": [rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, dsa_sha256, rsa_sha224, dsa
_sha224, rsa_pkcs1_sha1, dsa_sha1]
},
"status_request_v2 (17)": {
"cert status request": {
"certificate status type": ocsp_multi
"OCSP status request": {
"responder_id": <empty>
"request extensions": {
<empty>
}
}
}
},
"extended_master_secret (23)": {
<empty>
},
"session_ticket (35)": {
<empty>
},
"supported_versions (43)": {
"versions": [TLSv1.3, TLSv1.2]
},
"psk_key_exchange_modes (45)": {
"ke_modes": [psk_dhe_ke]
},
"key_share (51)": {
"client_shares": [
{
"named group": ffdhe2048
"key_exchange": {
0000: 8A B0 45 9E 04 62 D4 52 2F 35 E7 60 03 77 ED 8D ..E..b.R/5.`.w..
...
}
},
]
}
]
}
)
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.252 UTC|Alert.java:238|Received alert message (
"Alert": {
"level" : "fatal",
"description": "handshake_failure"
}
)
javax.net.ssl|ERROR|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.253 UTC|TransportContext.java:361|Fatal (HANDSHAKE_FAILURE): Received fatal alert: handshake_failure (
"throwable" : {
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
...
)
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.253 UTC|SSLSocketImpl.java:1755|close the underlying socket
javax.net.ssl|DEBUG|1C|http-nio-8080-exec-7|2022-03-21 22:37:28.253 UTC|SSLSocketImpl.java:1774|close the SSL connection (initiative)
2022-03-21 22:37:28.255 WARN 26 --- [nio-8080-exec-7] o.keycloak.adapters.KeycloakDeployment : Failed to load URLs from https://auth-service.mycompany.com/auth/realms/MyRealm/.well-known/openid-configuration
Да, добавление ssl:handshake дало мне отладочный вывод, спасибо! Теперь... Пока не знаю, что с этим делать - я не вижу ни одного дымящегося пистолета. В журнале nginx нет ничего, кроме записей журнала доступа, но на самом деле я не вижу там запроса на .well-known/openid-configuration
, поэтому похоже, что служба REST на самом деле не звонила? Или nginx не регистрирует запрос, потому что он не прошел во время рукопожатия.
вы можете взглянуть на этот вопрос SO, я думаю, что та же ошибка и может помочь stackoverflow.com/questions/6353849/…
Я просмотрел этот пост несколько раз, но не нашел ничего, что могло бы помочь. Сертификат подписан Digicert, который определенно находится в cacerts ОС и JDK и содержит как листовые, так и промежуточные сертификаты. Так что я не думаю, что это проблема с неполной цепочкой, хотя не уверен, как еще я бы сказал. Сервер nginx настроен на разрешение TLS 1.2 и 1.3, поэтому я думаю, что JDK должен иметь возможность согласовать один из этих двух. Домен точно правильный. Это оставило бы наборы шифров - я перепробовал все, что мог здесь придумать, но не уверен, как понять, что не так.
Накрутил логирование на nginx, получилось вот что: 2022/03/22 00:50:41 [info] 74#74: *22 SSL_do_handshake() failed (SSL: error:141F7065:SSL routines:final_key_share:no suitable key share) while SSL handshaking, client: #.#.#.#, server: 0.0.0.0:443
Я думаю, что основная проблема в том, что клиент отправляет список шифров: [TLS_AES_256_GCM_SHA384(0x1302), TLS_AES_128_GCM_SHA256(0x1301),...
и сервер имеет свой список шифров: ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:...
и они не пересекаются. Все клиентские шифры начинаются с TLS
, а все серверные — с ECDHE
. Я вытащил рекомендации сервера из списка рекомендаций по безопасности, поэтому не хочу их менять. Есть ли правильный способ добавить новые шифры в JDK?
Хорошо, я думаю, что это расходится с моим первоначальным вопросом, поэтому создаю здесь отдельный вопрос - stackoverflow.com/questions/71567383/…
Синтаксис для включения отладки SSL, по-видимому, немного изменился. Это сработало для меня:
System.setProperty("javax.net.debug", "ssl:handshake");
Полная документация здесь.
Если вы используете Java версии 8u261 или 11 и выше, уже недостаточно установить для этого sysprop значение
ssl
; вы должны добавить соответствующие «подтипы», такие какssl:handshake:keymanager
. Тем не менее, эта трассировка редко помогает при получении предупреждений о 40 проблемах, кроме отсутствия сертификата клиента — настроен ли ваш nginx на требование сертификата клиента? Что говорят журналы nginx?