Encrypted Communication with the Elasticsearch Java Rest Client

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):

    truststore.path: "watcher-truststore.jks"
    truststore.password: "secretpass"
    key:                     certs/node.key
    certificate:             certs/node.crt
    certificate_authorities: "certs/ca.crt"  
    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.


Assemble connection details:

String user = "elastic";
String password = "changeme";
String host = "elasticsearch.cinhtau.net";
String port = 9200;
String trustStorePass = "fancyPassword";

// add basic auth
        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

    CLIENT = new RestHighLevelClient(builder);

    // do sth

} catch (IOException | CertificateException | NoSuchAlgorithmException | KeyStoreException | KeyManagementException | URISyntaxException e) {
} finally {


If it does not work check the SSL handshake. Enable DEBUG with


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