1

I'm new to spring-boot & Elasticsearch technology stack and I want to establish secure HTTPS connection between my spring-boot app & elastic search server which runs locally. These are the configurations that I have done in elasticsearch.yml

Giving credintials for elasticsearch server

xpack.security.enabled: true

xpack.security.transport.ssl.enabled: true

For secure inter nodes connection inside elasticsearch cluster

xpack.security.transport.ssl.verification_mode: certificate

xpack.security.transport.ssl.keystore.path: elastic-certificates.p12

xpack.security.transport.ssl.truststore.path: elastic-certificates.p12

For secure Https connection with clients and elasticsearch clustrer

xpack.security.http.ssl.enabled: true

xpack.security.http.ssl.keystore.path: elastic-certificates.p12

xpack.security.http.ssl.truststore.path: elastic-certificates.p12

xpack.security.http.ssl.client_authentication: optional

Enabling PKI authentication

xpack.security.authc.realms.pki.pki1.order: 1

I have generated CA and client certificate which signed by generated CA according to this link

https://www.elastic.co/blog/elasticsearch-security-configure-tls-ssl-pki-authentication

And I have added CA to my java keystore.

This is the java code i'm using to establish connectivity with elasticsearch server.

@Configuration public class RestClientConfig extends AbstractElasticsearchConfiguration {

private static final Logger LOG = LoggerFactory.getLogger(RestClientConfig.class);

private static final String CERT_FILE = "client.p12";
private static final String CERT_PASSWORD = "";
private static final String USER_NAME = "elastic";
private static final String USER_PASS = "pwd";

@Override
@Bean
public RestHighLevelClient elasticsearchClient() {

    final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
            .connectedTo("localhost:9200")  // set the address of the Elasticsearch cluster
            .usingSsl(createSSLContext())  // use the SSLContext with the client cert
            .withBasicAuth(USER_NAME, USER_PASS)   // use the headers for authentication
            .build();
    return RestClients.create(clientConfiguration).rest();
}

private SSLContext createSSLContext() {
    try {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        KeyManager[] keyManagers = getKeyManagers();
        sslContext.init(keyManagers, null, null);
        return sslContext;
    } catch (Exception e) {
        LOG.error("cannot create SSLContext", e);
    }
    return null;
}

private KeyManager[] getKeyManagers()
        throws KeyStoreException, NoSuchAlgorithmException, IOException, CertificateException, UnrecoverableKeyException {
    try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(CERT_FILE)) {
        KeyStore clientKeyStore = KeyStore.getInstance("PKCS12");
        clientKeyStore.load(inputStream, CERT_PASSWORD.toCharArray());
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(clientKeyStore, CERT_PASSWORD.toCharArray());
        return kmf.getKeyManagers();
    }
}

And my client certificate called "client.p12" included in resources folder in the spring-boot application. In elasticsearch side everything seems to be fine. But when I run the spring-boot app it gives this warning & exception

Cannot create index: Host name 'localhost' does not match the certificate subject provided by the peer (CN=instance); nested exception is java.lang.RuntimeException: Host name 'localhost' does not match the certificate subject provided by the peer (CN=instance)

java.io.IOException: Host name 'localhost' does not match the certificate subject provided by the peer (CN=instance)

Caused by: javax.net.ssl.SSLPeerUnverifiedException: Host name 'localhost' does not match the certificate subject provided by the peer (CN=instance)

I'm doing this because I have an idea to migrate elastic search server to a another VPS hosting later.

this is the command I used for generate client certificate

bin/elasticsearch-certutil cert --ca
config/elastic-stack-ca.p12
-name "CN=something,OU=Consulting Team,DC=mydomain,DC=com" ENTER client.p12 ENTER ENTER

searching this error in internet I figured out there is a issue with my client certificate. It has something to do with SAN names with elastic nodes. But I have very little knowledge about these certificate stuff. So it's really confusion for me. If Some one can give me in-detailed explanation why this is occurring & solution to this I'm really appreciating it & grateful. A Proper link will also be helpful. This question already asked in How to connect 'spring boot 2.1 with elasticsearch 6.6' with cluster node 'https'? link But no luck for me.

1 Answers1

0

Your issue looks similar to another issue, see here: Certificate for <localhost> doesn't match any of the subject alternative names

So I would assume that if you add the SAN extension localhost as DNS and the ip address of localhost to the elasticsearch certificate it should work. So adding the following additional parameters: --dns localhost --ip 127.0. 0.1. Can you give the command below a try and share your results here?

bin/elasticsearch-certutil cert --ca config/elastic-stack-ca.p12 -name "CN=something,OU=Consulting Team,DC=mydomain,DC=com" --dns localhost --ip 127.0. 0.1

By the way you have configured Elasticsearch to optionally request the client certificate, but not marked as required see: xpack.security.http.ssl.client_authentication: optional. So it is not required and therefor it does not make sense to create a KeyManager and construct a sslcontext from it. But I think you need to export the public certificate of the certificate of Elasticsearch and supply that to your http client by transforming it to a TrustManager and creating a sslcontext from it. I have a working example here: ElasticSearch RestHighLevelClient SSL example.

Hakan54
  • 3,121
  • 1
  • 23
  • 37
  • Sir, Some how I managed to solve my problem. It's about adding this "--dns localhost --ip 127.0. 0.1" to my Elasticsearch certificate. Second thing, is it worth creating a KeyManager and construct a sslcontext from it by configuring as "xpack.security.http.ssl.client_authentication: required" in elasticsearch.yml. Your SSL example bit complicated me to understand & please give me opinion if I'm going to change this Elasticsearch server into another hosting environment how the configurations should be changed. I mean I can't use .connectedTo("localhost:9200") in my java code right? – Anjula Samarasinghe May 24 '21 at 06:47
  • Really glad to hear that the two additional parameters did the trick! In your initial question you mentioned that the client authentication is optional. You shared the following configuration: `xpack.security.http.ssl.client_authentication: optional` therefore I said that you don't need the KeyManager, but if you marked it as required then obviously you need it. – Hakan54 May 24 '21 at 08:35
  • If you are going to host ElasticSearch on somewhere else lets say behind `https://my-domain.com` you won't be able to access it through localhost as it is running on a server and not on your machine anymore and next to that you also need to add `*.my-domain.com` as dns option when creating the certificate for ElasticSearch so you won't get the same ssl exception as before. – Hakan54 May 24 '21 at 08:39
  • Really appreciating for your contribution sir. Thanks a lot. – Anjula Samarasinghe May 24 '21 at 13:59