Search code examples
spring-bootdockersslkuberneteskeystore

Containerized Springboot Application - Loading an Embedded Keystore (.jks/.p12) from within the JAR


Background: I have a springboot app that is containerized using docker and runs on a kubernetes cluster. It performs API calls, and relies on an SSLContext that requires loading a .jks truststore, like so:

SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(ResourceUtils.getFile(keyStoreFilePath),
                        keyStorePassword.toCharArray(), new TrustSelfSignedStrategy()).build();

Note that the String keyStoreFilePath is currently injected as an environment/property variable at release time, and points to a location like /etc/ssl/keystore.jks on the host machine that runs a container. The disadvantage is that I have to resort to mounting this as a persistent volume in kubernetes for my containerized application to access it.

Instead, I decided to embed it into the application's classpath so that our operations team don't have to setting it up in all the host machines. But when I do, by specifying the keyStoreFilePath value like so: classpath:security/keystore.jks, it runs fine when I run the project in Eclipse/STS. But it fails with the error below inside the container:

class path resource [security/cacerts] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/app.jar!/BOOT-INF/classes!/security/cacerts","stackTrace":"org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:217)

Again, what is interesting is that the exact same thing runs just fine in Eclipse, but fails inside the container. Any pointers?

Update: verified the keystore.jks file is < 1 MB in size.


Solution

  • I was able to figure this out. Since the keystore.jks is embedded within the jar and needs to be loaded from the classpath (classpath:security/keystore.jks), we can not read it as a file. Instead, we will have to read it as an input stream - true for all resources within the jar file (classpath). So, I have to do something like this to get it to work:

    KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
    keystore.load(truststoreResource.getInputStream(), keyStorePassword.toCharArray());
    SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(keystore, new TrustSelfSignedStrategy()).build();
    

    This answer was helpful.