簡體   English   中英

為什么幾分鍾后 Spring 啟動應用程序和 Consul 之間的 SSL 連接失敗?

[英]Why is the SSL connection between a Spring Boot app and Consul failing after a few minutes?

我正在使用新版本的 Ubuntu、Consul 和 Spring Boot 升級環境。 乍一看,一切似乎都運行良好。 該應用程序連接到 Consul,請求其配置並啟動。 然而,幾分鍾后,有些東西中斷了,這條消息大約每 2 秒重復一次:

com.ecwid.consul.transport.TransportException: javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
    at com.ecwid.consul.transport.AbstractHttpTransport.executeRequest(AbstractHttpTransport.java:77)
    at com.ecwid.consul.transport.AbstractHttpTransport.makeGetRequest(AbstractHttpTransport.java:34)
    at com.ecwid.consul.v1.ConsulRawClient.makeGetRequest(ConsulRawClient.java:128)
    at com.ecwid.consul.v1.catalog.CatalogConsulClient.getCatalogServices(CatalogConsulClient.java:120)
    at com.ecwid.consul.v1.ConsulClient.getCatalogServices(ConsulClient.java:372)
    at org.springframework.cloud.consul.discovery.ConsulCatalogWatch.catalogServicesWatch(ConsulCatalogWatch.java:129)
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
    at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
    at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: javax.net.ssl.SSLHandshakeException: Remote host terminated the handshake
    at java.base/sun.security.ssl.SSLSocketImpl.handleEOF(SSLSocketImpl.java:1313)
    at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1152)
    at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1055)
    at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:395)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)

我追蹤到消息每 2 秒出現一次到應用程序運行狀況檢查的事實。 一旦錯誤第一次發生,它會在每次后續的運行狀況檢查中繼續發生。 通過關閉運行狀況檢查並重新啟動來確認這一點。 當達到 Consul-data 上的 TTL 時,這會導致錯誤僅發生一次。

這就是我對問題的理解結束的地方。 我試圖將其追溯到幾件事,但這些都沒有導致解決方案:

  • 檢查證書- 使用的證書由 Vault 生成,由中間證書簽名,由自簽名根證書簽名。 然后將它們與密鑰一起放入 pkcs12 包中並提供給應用程序。 這適用於所有 TLS 連接,也適用於 CLI 工具和curl 這似乎是一個死胡同。
  • 網絡連接- 由於正在重置連接,我試圖查看它是否是由於防火牆或安全組問題。 但是,相關端口 (8501) 對 TCP 和 UDP 流量都是開放的,並且所有使用nc的手動測試都顯示這些端口是可訪問的。
  • IPv6 錯誤- 在某處,我發現一個帖子說這可能是由於 IPv6 的錯誤。 我嘗試在機器上關閉 IPv6,重新啟動一切,然后重試。 沒有運氣,仍然是同樣的錯誤。
  • Consul 的版本- 我嘗試在我們的舊環境中運行應用程序,Consul 1.2.3 正在運行並且那里的錯誤沒有出現。 我仍在嘗試找出是否存在開始出現此問題的特定 Consul 版本,但尚未找到。
  • TLS 錯誤- 在 Consul 1.2.3 和 1.7.2 之間,Consul 的 TLS 支持以及底層 Go TLS 實現發生了一些變化。 這在使用 Consul 1.4.0 進行測試時暴露出來,它提供了一個略有不同的 TLS 錯誤。 互聯網上的一些建議是 Go 和 OpenJDK 之間的實現存在沖突。 我嘗試強制 Java 應用程序使用 TLS 1.2,但同樣沒有運氣。
  • 握手調試- 根據評論中的提示,我使用-Djavax.net.debug=ssl:handshake來了解握手期間發生的情況。 在最初的幾分鍾內,產生的額外 output 在我看來就像正常的握手。 一旦出現問題,握手的 output 在“Produced Client Hello message”之后立即停止,並帶有“Remote host terminate the handshake”。 我無法對這個連接的另一端做同樣的事情。 Consul 是一個 Golang 應用程序。 如果有人知道如何為 Golan 應用程序獲取相同的調試信息,請告知。

我希望有人知道如何找到這個問題的原因,或者更好的是,有一個解決方案。

經過更多的挖掘和嘗試其他版本的東西。 我發現使用 GraalVM 會產生不同但更具描述性的錯誤。 當嘗試連接到 Consul 應用程序時,它會立即終止並顯示以下消息:

Caused by: javax.net.ssl.SSLHandshakeException: extension (5) should not be presented in certificate_request
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:307)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:263)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:254)
    at java.base/sun.security.ssl.SSLExtensions.<init>(SSLExtensions.java:90)
    at java.base/sun.security.ssl.CertificateRequest$T13CertificateRequestMessage.<init>(CertificateRequest.java:818)
    at java.base/sun.security.ssl.CertificateRequest$T13CertificateRequestConsumer.consume(CertificateRequest.java:922)
    at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
    at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
    at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:421)
    at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:177)
    at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:164)
    at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1151)
    at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1062)
    at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:71)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:220)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:164)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:139)
    at com.ecwid.consul.transport.AbstractHttpTransport.executeRequest(AbstractHttpTransport.java:61)

這讓我在 Golang GitHub 頁面上遇到了一個問題: https://github.com/golang/go/issues/35722 它詳細介紹了來自不同人的類似問題,但細節不斷略有不同。 在該線程中,提到了 Go 和 Java 之間的 TLS 1.3 實現之間的差異。 OpenJDK 維護者也參與並參考了這個問題: https://bugs.openjdk.java.net/browse/JDK-8236039

它已被修復並關閉,但在我的任何常規二進制發行版中尚不可用。 我將嘗試檢查該版本是否真正解決了問題。 但是,有一個解決方法是在 Java 中禁用 TLS1.2。 您可以通過將-Djdk.tls.client.protocols=TLSv1.2添加到啟動 arguments 來執行此操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM