Search Tutorials


Spring Boot + Elasticsearch + Azure Key Vault Example | JavaInUse

Spring Boot + Elasticsearch + Azure Key Vault Example

In previous tutorial we will implemented Spring Boot + Elasticsearch CRUD example. In this tutorials all the credentials we had hardcoded. This is not a good practice. Also we were storing the elasticsearch certificate needed for ssl connection to elasticsearch on disk only. This again is not a good security practice. In this tutorial we will be modifying the Spring Boot + Elasticsearch CRUD example to get the secrets and certificate from the azure keyvault. We have already looked at the basics of azure keyvault in Spring Boot + Azure Key Vault Hellow World Example.
The spring boot project we will be developing is as follows -
Spring Boot 3 + Elasticsearch CRUD + Azure Key Vault Example

Implementation

Azure Key Vault

In previous tutorial we had seen how to create and configure azure key vault. Also we had seen that how using azure client id, client secret and secret we connected to the azure key vault from spring boot application.
We will be making use of the previously created azure key vault. For this azure key vault we have already set the azure client id, client secret and secret as environment variables. Next in this azure key vault we will be storing the secrets and certificate.
  • Store secrets in key vault - In the key vault create secrets named elastic-username, elastic-password, truststore-password.
    Spring Boot 3 + Elasticsearch CRUD + Azure Key Vault Secrets
  • Store certificate in key vault - Usually the certificate we will be storing it in certificate section of key vault. However ours is a self signed certificate generated by elasticsearch in crt format. Azure key vault does not allow to upload the certificate in this format. So i will be storing the certificate in base64 encoded format as a secret. The later retrieve this base64 encoded string and convert it back into a certificate and use it. We do this using the following commands
    $fileContentBytes = get-content 'E:\trial\elasticsearch-8.13.4-windows-x86_64\elasticsearch-8.13.4\config\certs\http_ca.crt' -Encoding Byte
    [System.Convert]::ToBase64String($fileContentBytes) | Out-File 'cert-encoded-bytes.txt'
    

    Spring Boot 3 + Elasticsearch CRUD + Azure Key Vault create certificate
    Save this in key vault
    Spring Boot 3 + Elasticsearch CRUD + Azure Key Vault

Spring Boot Application

We will be modifying the Spring Boot + Elasticsearch CRUD application to fetch the secrets and certififcate from the azure key vault. For this we will be modifying the HttpClientConfigImpl configuration class to retrieve the necessary Elasticsearch credentials and certificate from Azure Key Vault, configure the Apache HttpClient with these credentials and a trusted SSL/TLS context, and return the configured HttpAsyncClientBuilder. This setup enables the Spring Boot application to securely communicate with the Elasticsearch cluster using the retrieved secrets from Azure Key Vault.
  • It retrieves the Elasticsearch username and password secrets from Azure Key Vault using the SecretClient from the Azure Key Vault client library.
  • It creates a CredentialsProvider object and sets the Elasticsearch username and password credentials using the retrieved secrets.
  • It configures the HttpAsyncClientBuilder with the CredentialsProvider object, ensuring that the Elasticsearch username and password are used for authentication when making HTTP requests.
  • It retrieves the Base64-encoded Elasticsearch certificate and the truststore password from Azure Key Vault.
  • It decodes the Base64-encoded certificate and creates a Java KeyStore object (PKCS12 format) with the decoded certificate and the retrieved truststore password.
  • It saves the KeyStore object as a truststore file (in this case, E:\trial\elasticsearch-8.13.4-windows-x86_64\elasticsearch-8.13.4\config\certs\truststore.p12).
  • It creates an SSLContext object using the generated truststore file and the retrieved truststore password .
  • It configures the HttpAsyncClientBuilder with the created SSLContext object, enabling secure SSL/TLS communication with the Elasticsearch cluster.
  • It returns the configured HttpAsyncClientBuilder object.
package com.javainuse.boot_elasticsearch_crud.config;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;

import javax.net.ssl.SSLContext;

import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback;
import org.springframework.context.annotation.Configuration;

import com.azure.identity.DefaultAzureCredentialBuilder;
import com.azure.security.keyvault.secrets.SecretClient;
import com.azure.security.keyvault.secrets.SecretClientBuilder;
import com.azure.security.keyvault.secrets.models.KeyVaultSecret;

@Configuration
public class HttpClientConfigImpl implements HttpClientConfigCallback {

	@Override
	public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {

		String keyVaultUrl = "https://javainuse.vault.azure.net/";

		try {

			// Create a SecretClient instance to interact with Azure Key Vault
			SecretClient secretClient = new SecretClientBuilder().vaultUrl(keyVaultUrl)
					.credential(new DefaultAzureCredentialBuilder().build()).buildClient();

			// Retrieve the elastic username secret from Azure Key Vault
			KeyVaultSecret elasticUsernameSecret = secretClient.getSecret("elastic-username");
			String elasticUsername = elasticUsernameSecret.getValue();

			// Retrieve the elastic password from Azure Key Vault
			KeyVaultSecret elasticPasswordSecret = secretClient.getSecret("elastic-password");
			String elasticPassword = elasticPasswordSecret.getValue();

			final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
			UsernamePasswordCredentials usernamePasswordCredentials = new UsernamePasswordCredentials(elasticUsername,
					elasticPassword);
			credentialsProvider.setCredentials(AuthScope.ANY, usernamePasswordCredentials);
			httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);

			String trustLocationStore = "E:\\trial\\elasticsearch-8.13.4-windows-x86_64\\elasticsearch-8.13.4\\config\\certs\\truststore.p12";

			// Retrieve the Base64-encoded secret from Azure Key Vault
			KeyVaultSecret certSecret = secretClient.getSecret("cert");
			String base64EncodedCert = certSecret.getValue();

			// Decode the Base64-encoded string to a certificate
			byte[] certificateBytes = Base64.getDecoder().decode(base64EncodedCert);

			// Retrieve the truststore password secret from Azure Key Vault
			KeyVaultSecret truststorePasswordSecret = secretClient.getSecret("truststorePassword");
			String truststorePassword = truststorePasswordSecret.getValue();

			// Create a PKCS12 KeyStore and load the certificate
			KeyStore trustStore = KeyStore.getInstance("PKCS12");
			trustStore.load(null, truststorePassword.toCharArray());

			CertificateFactory cf = CertificateFactory.getInstance("X.509");
			ByteArrayInputStream certInputStream = new ByteArrayInputStream(certificateBytes);
			X509Certificate x509Certificate = (X509Certificate) cf.generateCertificate(certInputStream);
			certInputStream.close();

			trustStore.setCertificateEntry("http_ca", x509Certificate);

			// Save the truststore to a file
			FileOutputStream truststoreOutputStream = new FileOutputStream(trustLocationStore);
			trustStore.store(truststoreOutputStream, truststorePassword.toCharArray());
			truststoreOutputStream.close();

			System.out.println("Truststore created successfully at: " + trustLocationStore);

			File trustLocationFile = new File(trustLocationStore);

			SSLContextBuilder sslContextBuilder = SSLContexts.custom().loadTrustMaterial(trustLocationFile,
					truststorePassword.toCharArray());
			SSLContext sslContext = sslContextBuilder.build();
			httpClientBuilder.setSSLContext(sslContext);

		} catch (Exception e) {
			System.out.println("Exception Occured");
		}
		return httpClientBuilder;
	}
}
These are the only code changes required.
Open the command prompt as an admin. Go to the elasticsearch bin folder and type the following command
elasticsearch.bat
This will start elasticsearch.
elasticsearch start
Start the spring boot application.
Spring Boot 3 + Elasticsearch CRUD + Azure Key Vault Code
If we now go to localhost:8080/employees we are able to retrieve the employee list from elasticsearch.
Spring Boot 3 + Elasticsearch CRUD + Azure Key Vault - retrive employees

Download Source Code

Download it -
Spring Boot 3 + Elasticsearch + Key Vault Example