Skip to content

Commit

Permalink
ZOOKEEPER-4276. Serving only with secureClientPort fails (apache#2117)
Browse files Browse the repository at this point in the history
* Support TLS-only ZK server

* Cleanup

* Update documentation according to review comments
  • Loading branch information
abhilash1in authored and AlphaCanisMajoris committed Mar 28, 2024
1 parent fb71e3b commit 796b91c
Show file tree
Hide file tree
Showing 12 changed files with 734 additions and 85 deletions.
44 changes: 29 additions & 15 deletions zookeeper-docs/src/main/resources/markdown/zookeeperReconfig.md
Expand Up @@ -88,27 +88,41 @@ feature is disabled by default, and has to be explicitly turned on via

### Specifying the client port

A client port of a server is the port on which the server accepts
client connection requests. Starting with 3.5.0 the
_clientPort_ and _clientPortAddress_ configuration parameters should no longer be used. Instead,
this information is now part of the server keyword specification, which
A client port of a server is the port on which the server accepts plaintext (non-TLS) client connection requests
and secure client port is the port on which the server accepts TLS client connection requests.

Starting with 3.5.0 the
_clientPort_ and _clientPortAddress_ configuration parameters should no longer be used in zoo.cfg.

Starting with 3.10.0 the
_secureClientPort_ and _secureClientPortAddress_ configuration parameters should no longer be used in zoo.cfg.

Instead, this information is now part of the server keyword specification, which
becomes as follows:

server.<positive id> = <address1>:<port1>:<port2>[:role];[<client port address>:]<client port>**
server.<positive id> = <address1>:<quorum port>:<leader election port>[:role];[[<client port address>:]<client port>][;[<secure client port address>:]<secure client port>]

The client port specification is to the right of the semicolon. The
client port address is optional, and if not specified it defaults to
"0.0.0.0". As usual, role is also optional, it can be
_participant_ or _observer_
(_participant_ by default).
- [New in ZK 3.10.0] The client port specification is optional and is to the right of the
first semicolon. The secure client port specification is also optional and is to the right
of the second semicolon. However, both the client port and secure client port specification
cannot be omitted, at least one of them should be present. If the user intends to omit client
port specification and provide only secure client port specification (TLS-only server), a second
semicolon should still be specified to indicate an empty client port specification (see last
example below). In either spec, the port address is optional, and if not specified it defaults
to "0.0.0.0".
- As usual, role is also optional, it can be _participant_ or _observer_ (_participant_ by default).

Examples of legal server statements:

server.5 = 125.23.63.23:1234:1235;1236
server.5 = 125.23.63.23:1234:1235:participant;1236
server.5 = 125.23.63.23:1234:1235:observer;1236
server.5 = 125.23.63.23:1234:1235;125.23.63.24:1236
server.5 = 125.23.63.23:1234:1235:participant;125.23.63.23:1236
server.5 = 125.23.63.23:1234:1235;1236 (non-TLS server)
server.5 = 125.23.63.23:1234:1235;1236;1237 (non-TLS + TLS server)
server.5 = 125.23.63.23:1234:1235;;1237 (TLS-only server)
server.5 = 125.23.63.23:1234:1235:participant;1236 (non-TLS server)
server.5 = 125.23.63.23:1234:1235:observer;1236 (non-TLS server)
server.5 = 125.23.63.23:1234:1235;125.23.63.24:1236 (non-TLS server)
server.5 = 125.23.63.23:1234:1235:participant;125.23.63.23:1236 (non-TLS server)
server.5 = 125.23.63.23:1234:1235:participant;125.23.63.23:1236;125.23.63.23:1237 (non-TLS + TLS server)
server.5 = 125.23.63.23:1234:1235:participant;;125.23.63.23:1237 (TLS-only server)


<a name="sc_multiaddress"></a>
Expand Down
Expand Up @@ -91,7 +91,29 @@ public static String send4LetterWord(
String cmd,
boolean secure,
int timeout) throws IOException, SSLContextException {
LOG.info("connecting to {} {}", host, port);
return send4LetterWord(host, port, cmd, secure, timeout, null);
}

/**
* Send the 4letterword
* @param host the destination host
* @param port the destination port
* @param cmd the 4letterword
* @param secure whether to use SSL
* @param timeout in milliseconds, maximum time to wait while connecting/reading data
* @param sslContext SSL context
* @return server response
* @throws java.io.IOException
* @throws SSLContextException
*/
public static String send4LetterWord(
String host,
int port,
String cmd,
boolean secure,
int timeout,
SSLContext sslContext) throws IOException, SSLContextException {
LOG.info("connecting to {}:{} (secure={})", host, port, secure);

Socket sock = null;
BufferedReader reader = null;
Expand All @@ -101,14 +123,16 @@ public static String send4LetterWord(
: new InetSocketAddress(InetAddress.getByName(null), port);
if (secure) {
LOG.info("using secure socket");
try (X509Util x509Util = new ClientX509Util()) {
SSLContext sslContext = x509Util.getDefaultSSLContext();
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
SSLSocket sslSock = (SSLSocket) socketFactory.createSocket();
sslSock.connect(hostaddress, timeout);
sslSock.startHandshake();
sock = sslSock;
if (sslContext == null) {
try (X509Util x509Util = new ClientX509Util()) {
sslContext = x509Util.getDefaultSSLContext();
}
}
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
SSLSocket sslSock = (SSLSocket) socketFactory.createSocket();
sslSock.connect(hostaddress, timeout);
sslSock.startHandshake();
sock = sslSock;
} else {
sock = new Socket();
sock.connect(hostaddress, timeout);
Expand Down
Expand Up @@ -482,8 +482,8 @@ protected void pRequest2Txn(int type, long zxid, Request request, Record record)
// extract server id x from first part of joiner: server.x
Long sid = Long.parseLong(parts[0].substring(parts[0].lastIndexOf('.') + 1));
QuorumServer qs = new QuorumServer(sid, parts[1]);
if (qs.clientAddr == null || qs.electionAddr == null || qs.addr == null) {
throw new KeeperException.BadArgumentsException("Wrong format of server string - each server should have 3 ports specified");
if ((qs.clientAddr == null && qs.secureClientAddr == null) || qs.electionAddr == null || qs.addr == null) {
throw new KeeperException.BadArgumentsException("Wrong format of server string - each server should have at least 3 ports specified");
}

// check duplication of addresses and ports
Expand Down

0 comments on commit 796b91c

Please sign in to comment.