I think I've found the way to connect SolrCloud to an external ZooKeeper ensemble via SSL.
By default, Solr does not use SSL to connect to ZooKeeper. So if the ZooKeeper configuration requires SSL for client connections, Solr will complain like this when it tries to connect to ZooKeeper: --8<---------------cut here---------------start------------->8--- WARN - 2022-03-25 12:34:43.681; org.apache.zookeeper.ClientCnxn; Session 0x0 for sever localhost/127.0.0.1:2182, Closing socket connection. Attempting reconnect except it is a SessionExpiredException. => EndOfStreamException: Unable to read additional data from server sessionid 0x0, likely server has closed socket at org.apache.zookeeper.ClientCnxnSocketNIO.doIO(ClientCnxnSocketNIO.java:77) org.apache.zookeeper.ClientCnxn$EndOfStreamException: Unable to read additional data from server sessionid 0x0, likely server has closed socket at org.apache.zookeeper.ClientCnxnSocketNIO.doIO(ClientCnxnSocketNIO.java:77) ~[zookeeper-3.6.2.jar:3.6.2] at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:350) ~[zookeeper-3.6.2.jar:3.6.2] at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1275) ~[zookeeper-3.6.2.jar:3.6.2] --8<---------------cut here---------------end--------------->8--- On the ZooKeeper side, the corresponding log entry is something like this: --8<---------------cut here---------------start------------->8--- 2022-03-25 12:34:43,652 [myid:1] - ERROR [nioEventLoopGroup-4-2:NettyServerCnxnFactory$CertificateVerifier@448] - Unsuccessful handshake with session 0x0 2022-03-25 12:34:43,682 [myid:1] - WARN [nioEventLoopGroup-4-2:NettyServerCnxnFactory$CnxnChannelHandler@284] - Exception caught io.netty.handler.codec.DecoderException: io.netty.handler.ssl.NotSslRecordException: not an SSL/TLS record: 0000002d000000000000000000000000000075300000000000000000000000100000000000000000000000000000000000 at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:478) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:829) Caused by: io.netty.handler.ssl.NotSslRecordException: not an SSL/TLS record: 0000002d000000000000000000000000000075300000000000000000000000100000000000000000000000000000000000 at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1232) at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1300) at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508) at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447) ... 17 more --8<---------------cut here---------------end--------------->8--- This error message indicates that ZooKeeper was expecting an SSL connection, but the client (i.e. Solr) was connecting without SSL. The solution is to add the appropriate ZooKeeper Java properties. Notice that these are exactly the same properties needed by standalone ZooKeeper's 'zkServer.sh' and 'zkCli.sh' to connect to ZooKeeper via SSL [1] [2]. Add the following to bin/solr.in.sh: --8<---------------cut here---------------start------------->8--- SOLR_OPTS="$SOLR_OPTS -Dzookeeper.client.secure=true -Dzookeeper.clientCnxnSocket=org.apache.zookeeper.ClientCnxnSocketNetty -Dzookeeper.ssl.keyStore.location=/path/to/zk-keystore.jks -Dzookeeper.ssl.keyStore.password=thepassword -Dzookeeper.ssl.trustStore.location=/path/to/zk-truststore.jks -Dzookeeper.ssl.trustStore.password=thepassword" --8<---------------cut here---------------end--------------->8--- [1]: https://stackoverflow.com/questions/43930797/configuring-ssl-in-zookeeper [2]: https://cwiki.apache.org/confluence/display/zookeeper/zookeeper+ssl+user+guide (Note that this ^ webpage says, "There is currently no support for SSL for the communication between ZooKeeper servers". That statement is no longer correct. "Quorum TLS" is available from ZooKeeper 3.5.5 onwards).