Spring Boot + Elasticsearch + Azure Key Vault Example
The spring boot project we will be developing is as follows -
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.
-
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'
Save this in 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.batThis will start elasticsearch.
Start the spring boot application.
If we now go to localhost:8080/employees we are able to retrieve the employee list from elasticsearch.
Download Source Code
Download it -Spring Boot 3 + Elasticsearch + Key Vault Example