Using secrets/passwords securely in processes (Using Docker Secrets, not storing passwords in process variables)

Hey all

So we have had some discussions about how to store secrets/passwords when working with Processes:

Recently we came up with the following solution:

Using Docker Secrets (Blog | Docker) you can manage sensitive data: with the Secrets feature, which basically creates a in-memory volume that stores your secret(s): Manage sensitive data with Docker secrets | Docker Docs

How Docker manages secrets
When you add a secret to the swarm, Docker sends the secret to the swarm manager over a mutual TLS connection. The secret is stored in the Raft log, which is encrypted. The entire Raft log is replicated across the other managers, ensuring the same high availability guarantees for secrets as for the rest of the swarm management data.
Reference from: Manage sensitive data with Docker secrets | Docker Docs

So with this we created a Docker-Compose File that looks like:

version: '3.1'

services:
  camunda:
    build: .
    environment:
      JAVA_OPTS: -Djava.security.egd=file:/dev/./urandom -Duser.timezone=America/Montreal
      MY_PASSWORD_FILE: /run/secrets/my_password
    secrets:
      - my_password
    ports:
      - "8080:8080"

secrets:
  my_password:
    file: my_password.json

Our Dockerfile looks like:

FROM camunda/camunda-bpm-platform:tomcat-7.7.0

# add custom configurations
COPY docker/camunda/conf/ conf

# Copy third-party Java libraries
COPY docker/camunda/lib/* lib

(you only really need line 1. The rest is use for adding additional configs (such as deployment-aware=false) and adding the Jsoup.jar)

Next, in the same folder as the dockerfile and docker-compose file we have our my_password.json file.

which could look like this:

{
  "someKey": "somePassword",
  "someKey2": "somePassword2"
}

folder-structure

You can use .txt files or whatever format you like.

And of course DO NOT commit your password file into your GIT-repo/SCM. Use gitignore at the very least to omit the password file from commits.

When you run docker-compose up, Camunda will be deployed, and a ‘Secrets’ volume will be created.


Now that we have Camunda running with the Secrets volume, we need to access it.

So during the process execution, we can run the following Javascript (nashorn) at any point to retrieve a password, all in-memory and without the use of process variables.

/**
 * Load Passwords Json File and returns a specific password
 *
 * @param string passwordKey The json property key that the password is stored. Currently only single level json is supported.
 * @param string passwordEnvName The Env Variable name that the JSON is stored in using Docker Secrets
 * @return string The password. Assumes that all passwords are strings and therefore returns a string.
 */
function getPassword(passwordKey, passwordEnvName)
{
  with (new JavaImporter(java.lang.System, java.nio.file))
  {
    var passwordPath = System.getenv(passwordEnvName)
    var passwordFileBytes = Files.readAllBytes(Paths.get(passwordPath))
  }

  var String = Java.type('java.lang.String')
  var passwordFileString = new String(passwordFileBytes)

  var passwordJson = JSON.parse(passwordFileString)
  var password = passwordJson[passwordKey]

  return password.toString()
}

var myPassword = getPassword('someKey', 'MY_PASSWORD_FILE')

Of course you can modify this structure and the way you use Docker Secrets to just return single text files.

The Process could look like this if you were to save the password (which you should not) as a process variable:


Also take a look at the docs for info about Rotating your secrets: Manage sensitive data with Docker secrets | Docker Docs


Quick Start / Ready to Go:

Here is a dockerfile and docker-compose ready to be used:

Includes Jsoup, deployment-aware=false and the Docker Secrets configuration that is explained above.


Enjoy

As always if you end up using this, please share your experience and thoughts!

1 Like

Shoutout to @hawky4s

For Further reference for updating Secrets:

Specifically:

and

Which was merged just 1 day ago.

and a great writup on the use of secrets and docker-compose: https://blog.mikesir87.io/2017/05/using-docker-secrets-during-development/

For additional reference:

See the Consuming Secret Values from Volumes section of:https://kubernetes.io/docs/concepts/configuration/secret/ for when you deploy Camunda into Kubernetes. The Docker Secrets Volumes pattern that you use during development can then be used interchangeably with the kubernetes secrets setup.

Hi Gurus, I have this hypothetical use case that I am trying to solve with Camunda. I have spring boot app with embedded camunda that exposes a REST API to get CustomerInfo. REST API then invokes the bpmn process as shown below that in turn invokes two endpoints that require this token to be passed. Passing this token as a process variable can pose security risk if it is compromised. As mentioned above, ThreadLocals can work here as long as tasks are synchronous. Singletons is an another option but works on the same node only. Are there any other better approaches?

Thanks in advance !

I am using redis cache and variable keeps value = redis:key instead of password ssh key or other sensitive info. Every time need to pass password to rest api, I read var value like user.id user.password and replace it with value of redis key.

Redis cache has live time 1-24 hours, so if a look history data there no sensitive info there, and redis cache mostly exipired.

Thank you @MaximMonin . I was thinking of Redis as well. The token itself will expire in about 30 minutes and storing this away from bpmn process is a safer bet. Storing inside bpmn will be visible via the Admin/Tasklist.