Skip to the content.

Heroku Java Client Certificate Authentication

2019-09-20


Let’s say our Java application is deployed on Heroku platform and needs to connect to server using client certificate authentication.

In this article we will show how to securely deploy the Client keystore files using environment variables.

Storing passwords and secret data in environment variables is a common approach for cloud-native applications.

Normally private keys are stored in password-protected keystore files such as .p12 or jks on a file system.

However the problem becomes evident when it comes to deploying such files into the cloud:

❇ Fortunately it is easy for Java applications to fix this!

Here is the process:

  1. Security officer exports the private key file as a Base64 encoded string
  2. Security officer logs into the cloud management console (e.g. Heroku Dashboard)
  3. Security officer imports the Base64 encoded string into environment variable
  4. As an automatic deployment step, the same environment variable storing the Base64 encoded string is decoded and written as a binary file
  5. Credentials of this file are passed to the application during startup

Now only people having the access to cloud management console have access to the private key.

Let’s apply this solution in practice:

Export the .p12 file

Simply follow steps from this nice article using the built-in tools of your OS:

❗ Never use online tools for your private keys.

Import into Heroku

Write .p12 file using Gradle task

It is as simple as pasting the following task into your build.gradle and setting it to run before stage task:

task initKeyStore() {
    doLast {
        println("Creating keystore file from environment variables.")
        String keyStoreFileName = System.getenv("keyStoreFileName")
        if (keyStoreFileName != null) {
            String keyStoreBase64 = System.getenv("keyStoreBase64")
            new File(keyStoreFileName).withOutputStream {
                it.write(Base64.decoder.decode(keyStoreBase64))
            }
        }
    }
}
stage.dependsOn(initKeyStore)

Pass credentials in Heroku procfile

Heroku procfile does not support multi-line commands.

Therefore we recommend to create a shell script with our input - runApp.sh.

runApp.sh:

java \
 -Dserver.port=$PORT \
...
 -Djavax.net.ssl.keyStoreType=$keyStoreType \
 -Djavax.net.ssl.trustStoreType=$trustStoreType \
 -Djavax.net.ssl.keyStore=$keyStoreFileName \
 -Djavax.net.ssl.keyStorePassword=$keyStorePassword \
 $JAVA_OPTS \
...

Don’t forget to add execute permission using GIT and to push the commit:

git update-index --chmod=+x runApp.sh
git commit -m 'Add execute permissions to runApp.sh'
git push origin master

Conclusion

Thank you for your attention!