How to implement SSL with Self Signed Certificates on Spring Boot against Elasticsearch deployed at Openshift (a cloud-based Kubernetes)

5/10/2021

Does anyone know how to use SSL on Spring Boot application to connect with ElasticSearch which is deployed at Openshift in the form of https? I have a config.java in my Spring Boot application like the following:

@Configuration
@EnableElasticsearchRepositories(basePackages = "com.siolbca.repository")
@ComponentScan(basePackages = "com.siolbca.services")
public class Config {
	@Bean
    public RestHighLevelClient client() {
        ClientConfiguration clientConfiguration 
            = ClientConfiguration.builder()
                .connectedTo("elasticsearch-siol-es-http.siolbca-dev.svc.cluster.local")
                .usingSsl()
                .withBasicAuth("elastic","G0D1g6TurJ79pcxr1065pU0U")
                .build();

        return RestClients.create(clientConfiguration).rest();
    }

    @Bean
    public ElasticsearchOperations elasticsearchTemplate() {
        return new ElasticsearchRestTemplate(client());
    }
}

However, when I run it with Postman to run elasticsearch, an error appears like this:

javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

I've seen some tutorials on the internet that say it's a certificate issue but I can't get a clue how to implement it in my code because I'm a beginner to Java & Spring Boot. using-elasticsearch-java-rest-api-with-self-signed-certificates how-to-connect-spring-boot-2-1-with-elasticsearch-6-6-with-cluster-node-https

And here’s my configuration for elasticsearch.yml:

cluster:
  name: elasticsearch-siol
  routing:
    allocation:
      awareness:
        attributes: k8s_node_name
discovery:
  seed_providers: file
http:
  publish_host: ${POD_NAME}.${HEADLESS_SERVICE_NAME}.${NAMESPACE}.svc
network:
  host: "0"
  publish_host: ${POD_IP}
node:
  attr:
    attr_name: attr_value
    k8s_node_name: ${NODE_NAME}
  name: ${POD_NAME}
  roles:
  - master
  - data
  store:
    allow_mmap: false
path:
  data: /usr/share/elasticsearch/data
  logs: /usr/share/elasticsearch/logs
xpack:
  license:
    upload:
      types:
      - trial
      - enterprise
  security:
    authc:
      realms:
        file:
          file1:
            order: -100
        native:
          native1:
            order: -99
      reserved_realm:
        enabled: "false"
    enabled: "true"
    http:
      ssl:
        certificate: /usr/share/elasticsearch/config/http-certs/tls.crt
        certificate_authorities: /usr/share/elasticsearch/config/http-certs/ca.crt
        enabled: true
        key: /usr/share/elasticsearch/config/http-certs/tls.key
    transport:
      ssl:
        certificate: /usr/share/elasticsearch/config/node-transport-cert/transport.tls.crt
        certificate_authorities:
        - /usr/share/elasticsearch/config/transport-certs/ca.crt
        - /usr/share/elasticsearch/config/transport-remote-certs/ca.crt
        enabled: "true"
        key: /usr/share/elasticsearch/config/node-transport-cert/transport.tls.key
        verification_mode: certificate

Does anyone know how to use the provided certificate in my Spring Boot application? Thank you.

-- Achmad Fathur Rizki
elasticsearch
java
kubernetes
spring-boot

1 Answer

5/11/2021

I solved my problem by ignoring SSL certificate verification while connecting to elasticsearch from my Backend (Spring Boot). I followed some instruction from website below:

Ignore SSL Certificate Verification

I also modified the code by adding basic authentication as follows:

@Configuration
@EnableElasticsearchRepositories(basePackages = "com.siolbca.repository")
@ComponentScan(basePackages = "com.siolbca.services")
public class Config {
	@Bean
    public RestHighLevelClient createSimpleElasticClient() throws Exception {
        try {
        	final CredentialsProvider credentialsProvider =
        		    new BasicCredentialsProvider();
        		credentialsProvider.setCredentials(AuthScope.ANY,
        		    new UsernamePasswordCredentials("elastic","G0D1g6TurJ79pcxr1065pU0U"));
        		
            SSLContextBuilder sslBuilder = SSLContexts.custom()
                    .loadTrustMaterial(null, (x509Certificates, s) -> true);
                    final SSLContext sslContext = sslBuilder.build();
            RestHighLevelClient client = new RestHighLevelClient(RestClient
                    .builder(new HttpHost("elasticsearch-siol-es-http.siolbca-dev.svc.cluster.local", 9200, "https")) 
//port number is given as 443 since its https schema
                    .setHttpClientConfigCallback(new HttpClientConfigCallback() {
                        @Override
                        public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                            return httpClientBuilder
                                     .setSSLContext(sslContext)
                                     .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                                     .setDefaultCredentialsProvider(credentialsProvider);
                        }
                    })
                    .setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
                        @Override
                        public RequestConfig.Builder customizeRequestConfig(
                                RequestConfig.Builder requestConfigBuilder) {
                            return requestConfigBuilder.setConnectTimeout(5000)
                                    .setSocketTimeout(120000);
                        }
                    }));
            System.out.println("elasticsearch client created");
            return client;
        } catch (Exception e) {
            System.out.println(e);
            throw new Exception("Could not create an elasticsearch client!!");
        }
    }
	
}
-- Achmad Fathur Rizki
Source: StackOverflow