启动Ignite瘦客户端时握手头部校验失败问题排查
按照Ignite官方文档开启TLS模式启动服务端,服务端使用根证书rootCA生成的.pfx文件作为SslContextFactory的KeyStore,启动后日志正常输出:Security status [authentication=off, tls/ssl=on]。
但为瘦客户端配置SSL(使用同一rootCA生成的.pfx文件,在SslStreamFactory中指定路径和密码),调用Ignition.StartClient()时:
- 客户端立即报错:
Received an unexpected EOF or 0 bytes from the transport stream - 服务端抛出错误堆栈:
native error: java.io.IOException: Handshake header check failed: 493
at org.apache.ignite.internal.processors.odbc.ClientMessage.readFrom(ClientMessage.java:186)
at org.apache.ignite.internal.processors.odbc.ClientListenerNioMessageParser.decode(ClientListenerNioMessageParser.java:66)
at org.apache.ignite.internal.util.nio.GridNioCodecFilter.onMessageReceived(GridNioCodecFilter.java:113)
at org.apache.ignite.internal.util.nio.GridNioFilterAdapter.proceedMessageReceived(GridNioFilterAdapter.java:109)
at org.apache.ignite.internal.util.nio.GridNioServer$HeadFilter.onMessageReceived(GridNioServer.java:3753)
at org.apache.ignite.internal.util.nio.GridNioFilterChain.onMessageReceived(GridNioFilterChain.java:175)
at org.apache.ignite.internal.util.nio.GridNioServer$DirectNioClientWorker.processRead(GridNioServer.java:1379)
at org.apache.ignite.internal.util.nio.GridNioServer$AbstractNioClientWorker.processSelectedKeysOptimized(GridNioServer.java:2527)
at org.apache.ignite.internal.util.nio.GridNioServer$AbstractNioClientWorker.bodyInternal(GridNioServer.java:2282)
at org.apache.ignite.internal.util.nio.GridNioServer$AbstractNioClientWorker.body(GridNioServer.java:1911)
at org.apache.ignite.internal.util.worker.GridWorker.run(GridWorker.java:125)
at java.base/java.lang.Thread.run(Unknown Source)
客户端错误堆栈显示失败在SslStream.AuthenticateAsClient()方法:
at System.Net.Security.SslStream.d__1761.MoveNext()
at System.Threading.Tasks.ValueTask1.get_Result()
at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable1.ConfiguredValueTaskAwaiter.GetResult()
at System.Net.Security.SslStream.d__1751.MoveNext()
at System.Net.Security.SslStream.d__172.MoveNext()
at System.Net.Security.SslStream.AuthenticateAsClient(SslClientAuthenticationOptions sslClientAuthenticationOptions)
at System.Net.Security.SslStream.AuthenticateAsClient(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation)
at Apache.Ignite.Core.Client.SslStreamFactory.Create(Stream stream, String targetHost)
at Apache.Ignite.Core.Impl.Client.ClientSocket.GetSocketStream(Socket socket, IgniteClientConfiguration cfg, String host)
at Apache.Ignite.Core.Impl.Client.ClientSocket..ctor(IgniteClientConfiguration clientConfiguration, EndPoint endPoint, String host, Nullable1 version, Action1 topVerCallback, Marshaller marshaller)
at Apache.Ignite.Core.Impl.Client.ClientFailoverSocket.Connect(SocketEndpoint endPoint)
at Apache.Ignite.Core.Impl.Client.ClientFailoverSocket.GetNextSocket()
at Apache.Ignite.Core.Impl.Client.ClientFailoverSocket..ctor(IgniteClientConfiguration config, Marshaller marsh, TransactionsClient transactions)
at Apache.Ignite.Core.Impl.Client.IgniteClient..ctor(IgniteClientConfiguration clientConfiguration)
at Apache.Ignite.Core.Ignition.StartClient(IgniteClientConfiguration clientConfiguration)
移除客户端SslStreamFactory配置后可正常连接,请问错误原因是什么?
核心原因
这个错误本质是客户端与服务端的SSL握手流程不匹配,常见触发场景如下:
端口配置不匹配
Ignite服务端默认区分普通客户端端口(默认10800)和SSL客户端端口(默认10801)。如果服务端仅在SSL端口启用了TLS,而客户端连接了未开启SSL的普通端口,服务端会收到不符合预期的SSL握手请求,直接断开连接,导致客户端收到EOF错误(对应服务端日志的Handshake header check failed)。SSL配置参数不兼容
- 证书链不完整:客户端使用的.pfx文件未包含rootCA证书,导致无法验证服务端证书,握手失败。
- 协议版本不一致:服务端启用的SSL/TLS版本(如TLS 1.2)与客户端默认启用的版本不匹配,协商失败后连接中断。
- 证书用途错误:将服务端证书用作客户端证书,服务端验证不通过直接断开连接。
- 服务端SSL配置未生效到客户端连接器
若服务端仅配置了集群内部通信的SSL,未给客户端连接器(ClientConnectorConfiguration)配置SSL上下文,会导致服务端的客户端端口未启用SSL,客户端发起SSL请求时被拒绝。
解决步骤
- 确认服务端SSL端口配置
检查服务端配置,确保客户端连接器已启用SSL并指定正确端口:
<bean class="org.apache.ignite.configuration.IgniteConfiguration"> <!-- 其他配置 --> <property name="clientConnectorConfiguration"> <bean class="org.apache.ignite.configuration.ClientConnectorConfiguration"> <property name="port" value="10800"/> <!-- 普通端口 --> <property name="sslPort" value="10801"/> <!-- SSL端口 --> <property name="sslContextFactory"> <bean class="org.apache.ignite.ssl.SslContextFactory"> <property name="keyStorePath" value="path/to/server.pfx"/> <property name="keyStorePassword" value="your-password"/> <property name="keyStoreType" value="PKCS12"/> </bean> </property> </bean> </property> </bean>
- 客户端连接正确的SSL端口
确保客户端配置中指定服务端的SSL端口(默认10801):
var cfg = new IgniteClientConfiguration { Endpoints = new[] { "localhost:10801" }, // 连接SSL端口 SslStreamFactory = new SslStreamFactory { CertPath = "path/to/client.pfx", CertPassword = "your-password", EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13 // 与服务端版本对齐 } };
- 完善证书信任配置
若客户端不需要发送自身证书,可仅配置信任rootCA:
SslStreamFactory = new SslStreamFactory { TrustedCertPath = "path/to/rootCA.crt", // 直接信任根证书 EnabledSslProtocols = SslProtocols.Tls12 }
- 验证证书用途
确保客户端使用的是rootCA签发的客户端专用证书,而非服务端证书文件。若不需要客户端证书认证,可在服务端关闭客户端证书验证:
<bean class="org.apache.ignite.ssl.SslContextFactory"> <!-- 其他配置 --> <property name="needClientAuth" value="false"/> </bean>
内容的提问来源于stack exchange,提问作者DeviantSpark

