After updating my elasticsearch to 7.2 and updating kibana, and after enabling security and therefore SSL, my java (spring) application lost connection to it. Spring JPA still doesn't support ES 7 and security+SSL was a paid plugin, and now it is part of the basic free package.
Because of this, I have been trying to configure my own client to send the requests using the RestHighLevelClient provided by elasticsearch SDK. With SSL turned of for the development mode, I have been able to connect and create my indexes, but as soon as I turn it on, I cannot get it to work.
I followed a tutorial to setup a valid self signed certificate to use with it. The tutorial uses a certificate tool provided with elasticsearch.
The steps were as follows:
- Generate a CA:
bin/elasticsearch-certutil ca
ENTER ENTER - Generate a certificate from this CA:
bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12
ENTER ENTER ENTER
(both generated without passwords)
-
Install the certificates in the ES configuration file (elasticsearch.yml):
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode:certificate
xpack.security.transport.ssl.keystore.path: certs/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: certs/elastic-certificates.p12 -
Defined user passwords:
bin/elasticsearch-setup-passwords interactive
-
Generated a client certificate (this part I still do not fully understand):
bin/elasticsearch-certutil cert --ca config/certs/elastic-stack-ca.p12 -name "CN=xyz,OU=XXX Team,DC=mydomain,DC=com"
ENTER
client.p12 ENTER
ENTER
After these steps, since ES was running fine, I started creating the java part that connects to the ES server.
For that I instantiated a Keystore: KeyStore truststore = KeyStore.getInstance("PKCS12");
Then I loaded my client certificate (client.p12) from the classpath:
try (InputStream resource = new ClassPathResource(keystorePath).getInputStream()) {
truststore.load(resource, new char[] {});//keystore pass is empty
} catch (NoSuchAlgorithmException | CertificateException | IOException e) {
log.error(e.getMessage(), e);
}
Then I built a SSL context as follows:
sslBuilder = SSLContexts.custom().loadTrustMaterial(truststore, new TrustSelfSignedStrategy());
And finally, from that context I have created my rest client builder (that I use to create my RestHighLevelClient:
RestClientBuilder builder = RestClient.builder(
new HttpHost(elasticAddress, elasticPort, "https"))
.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setSSLContext(sslContext));
return new RestHighLevelClient(builder);
The problem I'm getting is when I try to connect. In my java client I get this exception:
javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
and in elastic I get this exception:
Caused by: javax.net.ssl.SSLHandshakeException: null cert chain
The elasticsearch documentation says that when these exceptions occur, the problem is: The SSLHandshakeException indicates that a self-signed certificate was returned by the client that is not trusted as it cannot be found in the truststore or keystore. This SSLException is seen on the client-side of the connection.
But it doesn't explain how to solve this problem. I have followed the official 7.2 documentation tutorial for certificate generation, and also for the java setup (the code they provide as example doesn't work and uses a JKS store which they don't explain how to generate).
This question is a clone of my original question in SO: https://stackoverflow.com/questions/57259477/elasticsearch-7-2-java-client-ssl-configuration-failing-bad-certificate
If you want som SO reputation, you can answer there