Search code examples
javaspring-bootelasticsearchspring-data-elasticsearch

How to configure security in elasticsearch 8.5.3 using Starter Data Elasticsearch 3.0.1 in maven java springboot


I was able to create an elasticsearch 8.5.3 server as a docker image, but with security completely disabled, and in my springboot application I am using ElasticsearchRepository to perform insert,update, and delete and ElasticsearchOperations to perform selection and search, both of these classes/interfaces are included in the Spring Boot Starter Data Elasticsearch 3.0.1 dependency, and I am also using the following application.yaml property to tell both where the server is at

spring:
 elasticsearch:
  uris = 
   - http://localhost:9700
# username: elastic
# password: 123

Now, here is my issue: I set up another elasticsearch server with complete security features to test my springboot code in a real life scenario, but I can't figure out how to change the application.yaml to add the certificate portion of the security options, I've been stuck on this portion for a week now, I know it contains options like spring.elasticsearch.username and spring.elasticsearch.password, which aren't the issue, but where is the option for the certificate, and how can I make the certificate work on both ElasticsearchRepository and ElasticsearchOperation? I gathered from the majority of tutorials that I need to construct a @configuration class, however the point is that, most, if not all of the tutorials use deprecated methods(I am stuck in a 'This is deprecated' loop), like for example High Level Rest Client. I'm confused as to how to make ElasticsearchRepository and ElasticsearchOperation utilize the specified @Configuration, and what is the alternative to the High Level Rest Client (I think its RestClient based on what I read on the official documentations, but I cant figure out how to implement it with spring boot elasticsearch data starter)


Solution

  • What you can do is to extend ElasticsearchConfiguration and override clientConfiguration method. There you can use usingSsl method and pass SSLContext :

    @Configuration
    class ElasitcSearchConfig extends ElasticsearchConfiguration {
    
        @Value("${spring.elasticsearch.client.certificate}")
        private String certificateBase64;
    
        @Override
        ClientConfiguration clientConfiguration() {
            final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                    .connectedTo("localhost:9200")
                    .usingSsl(getSSLConetxt())
                    .withBasicAuth("elastic", "changeme")
                    .build();
            return clientConfiguration;
        }
    
        private SSLContext getSSLContext() {
            byte[] decode = Base64.decoder.decode(certificateBase64)
    
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
    
            Certificate ca;
            try (InputStream certificateInputStream = new ByteArrayInputStream(decode)) {
                ca = cf.generateCertificate(certificateInputStream);
            }
    
            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);
    
            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = 
       TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);
    
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, tmf.getTrustManagers(), null);
            return context;
        }
    
    }
    

    certificateBase64 will hold elasticsearch certificate encoded in base64 format and can be injected through properties file or environment variable (name of the property spring.elasticsearch.client.certificate). The code to create ssl context was originally taken from this answer.