This post is older than a year. Consider some information might not be accurate anymore.
Used: elasticsearch v6.2.4
Elasticsearch with the X-Pack extensions allows you to secure the communication with your Elasticsearch cluster. This post elaborates what actions are needed, to use secure encrypted communication from a Java Rest Client with the encrypted Elasticsearch cluster.
In my scenario my Elasticsearch v6.2.4 cluster holds monitoring and audit data and is encrypted. My elasticsearch.yml
(relevant snippets only):
xpack:
http.ssl:
truststore.path: "watcher-truststore.jks"
truststore.password: "secretpass"
ssl:
key: certs/node.key
certificate: certs/node.crt
certificate_authorities: "certs/ca.crt"
security:
enabled: true
transport.ssl.enabled: true
http.ssl.enabled: true
Create TrustStore
In order to access this Elasticsearch data node, your client needs a Java truststore with above certificates. You can either add them to the default truststore or create a new one.
I prefer the last option. To create a new truststore:
keytool -import \
-alias elasticCA \
-file /opt/elasticsearch/config/ca.crt \
-keystore truststore.jks
Above command also imports the root ca of your Elasticsearch cluster. In order to comply to the certificate chain, you can also import the data node certificate.
keytool -importcert \
-keystore truststore.jks \
-alias myEsNode \
-file /opt/elasticsearch/config/node.crt
Connect to Elasticsearch
Starting the JVM it is essential to pass the the truststore, if not the default truststore is used.
-Djavax.net.ssl.trustStore="C:/lib/elasticsearch/security/truststore.jks"
Assemble connection details:
String user = "elastic";
String password = "changeme";
String host = "elasticsearch.cinhtau.net";
String port = 9200;
String trustStorePass = "fancyPassword";
// add basic auth
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(user, password));
HttpHost elasticHost = new HttpHost(host, port, "https");
Load keystore and set SSL context builder
try {
Path keyStorePath = Paths.get(ClassLoader.getSystemResource("truststore.jks").toURI());
KeyStore truststore = KeyStore.getInstance("jks");
try (InputStream is = Files.newInputStream(keyStorePath)) {
truststore.load(is, trustStorePass.toCharArray());
}
SSLContextBuilder sslBuilder = SSLContexts.custom().loadTrustMaterial(truststore, null);
final SSLContext sslContext = sslBuilder.build();
RestClientBuilder builder = RestClient.builder(elasticHost).
setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setSSLContext(sslContext));
builder.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
builder.setRequestConfigCallback(requestConfigBuilder -> requestConfigBuilder
.setConnectTimeout(5000)
.setSocketTimeout(60000))
.setMaxRetryTimeoutMillis(60000);
CLIENT = new RestHighLevelClient(builder);
// do sth
aggregateData();
} catch (IOException | CertificateException | NoSuchAlgorithmException | KeyStoreException | KeyManagementException | URISyntaxException e) {
LOGGER.error(e);
} finally {
CLIENT.close();
}
Troubleshooting
If it does not work check the SSL handshake. Enable DEBUG with
-Djavax.net.debug=ssl
My use case:
adding as trusted cert:
Subject: CN=Taft Point
Issuer: CN=Elastic Certificate Tool Autogenerated CA
Algorithm: RSA; Serial number: 0x2756a4197a0b7813ade473cc53c20d07684d336a
Valid from Wed Nov 29 13:49:33 CET 2017 until Sat Nov 28 13:49:33 CET 2020
adding as trusted cert:
Subject: CN=Elastic Certificate Tool Autogenerated CA
Issuer: CN=Elastic Certificate Tool Autogenerated CA
Algorithm: RSA; Serial number: 0xd5a6359b11aac3cc52fdebe29743e331badb7ad9
Valid from Wed Nov 29 13:49:32 CET 2017 until Sat Nov 28 13:49:32 CET 2020
My happy path. Look out for this crucial messages in the handshake:
*** ClientHello, TLSv1.2
*** ServerHello, TLSv1.2
*** Certificate chain
***
Found trusted certificate:
*** ECDH ServerKeyExchange
*** ServerHelloDone
*** ECDHClientKeyExchange
*** Finished