elasticsearch/elasticsearch — pull request #2105 by tlrx (2012-07-18 19:56:27+00:00)
Title: Add SSL support to Netty transport layer for Client/Node-to-Node communication

This pull request modifies the Netty transport layer in order to support SSL for client/node to node communication within an elasticsearch cluster.

Configuration
-------------------
SSL encryption is activated with a new configuration entry *transport.tcp.compress*. If set to true, the keystore and trustore of the node must also be configured:

# Enable SSL/TLS encryption for all communication between nodes:
#
# transport.tcp.ssl: true

# Settings for SSL/TLS encryption
#
# transport.tcp.ssl.keystore: /path/to/the/keystore
# transport.tcp.ssl.keystore_password: password
# transport.tcp.ssl.keystore_algorithm: SunX509
#
# transport.tcp.ssl.truststore: /path/to/the/truststore
# transport.tcp.ssl.truststore_password: password
# transport.tcp.ssl.truststore_algorithm: PKIX

If keystores settings are not set in configuration file, it looks for JVM options (-Djavax.net.ssl.keyStore=..., -Djavax.net.ssl.trustStore=...)

Before starting the cluster, make sure that all nodes recognize each other (by importing the certificates in other nodes' trustores)

A *generate.sh* script can be used to create keystores for testing:

$./generate.sh 3 // will create 3 keystores and 3 certificates

Transport Client
-----------------------
SSL can be configured for a TransportClient with the Java API:

TransportClient client = new TransportClient(settingsBuilder()
.put("client.transport.nodes_sampler_interval", "30s")
.put("transport.tcp.ssl", true)
.put("transport.tcp.ssl.keystore", "/opt/certificates/esnode1.jks")
.put("transport.tcp.ssl.keystore_password", "mypassword")
.put("transport.tcp.ssl.truststore", "/opt/certificates/esnode1.jks")
.put("transport.tcp.ssl.truststore_password", "mypassword")
.put("client.transport.sniff", false).build());

client.addTransportAddress(new InetSocketTransportAddress("localhost", 9300));

Use cases
---------------
1. If a node tries to join a cluster but is not identified (certificate is unknown): discovery/recovery will fail, the node will start but won't join the cluster. The error message in log file is "org.elasticsearch.transport.SSLTransportException: SSL / TLS handshake failed, closing the channel" on cluster side.

2. If a non-SSL node tries to join a cluster configured for SSL: discovery/recovery will fail, the node will start but won't join the cluster. The error message in log file is "StreamCorruptedException: invalid data length".

3. If a transport client tries to connect to a cluster but is not identified: a NoNodeAvailableException is thrown.

Perf
------
One should pay attention to performance :/

NettyEchoBenchmark:

Warming up...
Warmed up
Ran 50000, TPS 9069.47215672048
Ran 50000, TPS 8939.746111210441
Ran 50000, TPS 10322.047894302228
Ran 50000, TPS 9238.728750923872
Ran 50000, TPS 10181.225819588679
Ran 50000, TPS 13319.126265316996
Ran 50000, TPS 9823.18271119843
Ran 50000, TPS 9529.25481227368
Ran 50000, TPS 9072.763563781527
Ran [500000] iterations, payload [100]: took [51], TPS: 9803.921568627451

NettyEchoSSLBenchmark:

Warming up...
Handshake completed on server side
Handshake completed on client side
Warmed up
Ran 50000, TPS 5730.002292000916
Ran 50000, TPS 6375.924509053813
Ran 50000, TPS 5571.651437486071
Ran 50000, TPS 6209.6373571783415
Ran 50000, TPS 5787.0370370370365
Ran 50000, TPS 5855.486590935707
Ran 50000, TPS 5726.720879624328
Ran 50000, TPS 5262.050094716901
Ran 50000, TPS 5755.726948313572
Ran [500000] iterations, payload [100]: took [87], TPS: 5747.126436781609

Code review and comments are welcome! :)