Elasticsearch - How to set-up configuration in a springboot application when ssl is enabled for elasticsearch
-
The Elasticsearch documentation shows 2 different ways to create a SSLContext that can be used to access the cluster (this is nothing that can be done from Spring Data Elasticsearch):
- Using certificate fingerprint
String fingerprint = "<certificate fingerprint>"; SSLContext sslContext = TransportUtils.sslContextFromCaFingerprint(fingerprint);Using it in code - with spring data elasticsearch
import co.elastic.clients.transport.TransportUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.data.elasticsearch.client.ClientConfiguration; import org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration; import javax.net.ssl.SSLContext; import java.net.URI; @Configuration @Slf4j public class ESRestClient extends ElasticsearchConfiguration { @Value("${elasticsearch.url}") private String elasticsearchUrl; @Value("${elasticsearch.hostname}") private String hostname; @Value("${elasticsearch.port}") private Integer port; @Value("${elasticsearch.username}") private String username; @Value("${elasticsearch.password}") private String password; @Override public ClientConfiguration clientConfiguration() { String fingerprint = "55f8d706125b0a54896e7e457842e1d4a036a8cb413199de3489a38d701016b0"; SSLContext sslContext = TransportUtils .sslContextFromCaFingerprint(fingerprint); // final String stringUrl = System.getenv("ELASTICSEARCH_URL"); final URI uri = URI.create(elasticsearchUrl); String host = uri.getHost(); int port = uri.getPort() == -1 ? 9200 : uri.getPort(); final ClientConfiguration.MaybeSecureClientConfigurationBuilder builder = ClientConfiguration.builder().connectedTo(host + ":" + port); // enable SSL if https is being used in the URL boolean isSsl = "https".equals(uri.getScheme()); if (isSsl) { builder.usingSsl(sslContext); builder.withBasicAuth(username, password); } return builder.build(); } }Using it in code - with Java API client
import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.json.jackson.JacksonJsonpMapper; import co.elastic.clients.transport.ElasticsearchTransport; import co.elastic.clients.transport.TransportUtils; import co.elastic.clients.transport.rest_client.RestClientTransport; import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.impl.client.BasicCredentialsProvider; import org.elasticsearch.client.RestClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.net.ssl.SSLContext; @Configuration @Slf4j public class ElasticsearchClientConfig { @Value("${elasticsearch.url}") private String elasticsearchUrl; @Value("${elasticsearch.hostname}") private String hostname; @Value("${elasticsearch.port}") private Integer port; @Value("${elasticsearch.username}") private String username; @Value("${elasticsearch.password}") private String password; @Bean public ElasticsearchClient getElasticSearchClient() { String fingerprint = "55f8d706125b0a54896e7e457842e1d4a036a8cb413199de3489a38d701016b0"; SSLContext sslContext = TransportUtils .sslContextFromCaFingerprint(fingerprint); BasicCredentialsProvider credsProv = new BasicCredentialsProvider(); credsProv.setCredentials( AuthScope.ANY, new UsernamePasswordCredentials(username, password) ); RestClient restClient = RestClient .builder(new HttpHost(hostname, port, "https")) .setHttpClientConfigCallback(hc -> hc .setSSLContext(sslContext) .setDefaultCredentialsProvider(credsProv) ) .build(); // Create the transport with a Jackson mapper ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper()); // And create the API client return new ElasticsearchClient(transport); } }- Using ca_certificate
Note that the certificate fingerprint can also be calculated using openssl x509 with the certificate file:
openssl x509 -fingerprint -sha256 -noout -in /path/to/http_ca.crtIf you don’t have access to the generated CA file from Elasticsearch you can use the following script to output the root CA fingerprint of the Elasticsearch instance with openssl s_client:
openssl s_client -connect localhost:9200 -servername localhost -showcerts </dev/null 2>/dev/null \ | openssl x509 -fingerprint -sha256 -noout -in /dev/stdinUsing it in code:
File certFile = new File("/path/to/http_ca.crt"); SSLContext sslContext = TransportUtils.sslContextFromHttpCaCrt(certFile);This SSLContext can then be passed to the Spring Data Elasticsearch configuration - there’s an overload method usingSsl(SSLContext).
Depending on the context, you have two options for verifying the HTTPS connection: either verifying with the CA certificate itself or using the CA certificate fingerprint. For both cases, the Java API Client’s TransportUtils class provides convenience methods to easily create an SSLContext.