Grishka
Grishka

Reputation: 2595

How do I generate a secret key and share it between two containers in docker-compose? Is it possible?

The problem: I'd like to use imgproxy in my project, but I need some way to generate a signing key when the containers are first run. I then need to share that key between two containers: imgproxy, which accepts it in an environment variable, and my server application, where I could read it from wherever needed. The key needs to be unique and random for each deployment. It would be great to avoid having to run any additional commands before docker-compose up to generate these keys.

What I considered so far:

Anyway, what's the best/correct way to approach this? This feels like a popular use case, so surely there has to be something I missed?

Upvotes: 1

Views: 1116

Answers (1)

David Maze
David Maze

Reputation: 160013

The best way to handle this is to create the secret externally; in Compose, perhaps in a .env file. This will translate well to other environments and doesn't require changing code at all. This also works well with secrets that require some user intervention to set up (for example, signing a TLS certificate), it will survive a docker-compose down, and it works even if you split the two halves of the application into separate environments.

If these considerations don't matter to you, and it's really important that the startup be autonomous, you could put the secret into a shared file. Decide that one of the containers is "first". Write a script that runs at startup time that generates the secret:

#!/bin/sh
# Create a random token if it doesn't already exist
if [ ! -f /secrets/token ]; then
  dd if=/dev/random bs=48 count=1 | base64 > /secrets/token
fi
# Read back the token into an environment variable
SECRET_TOKEN=$(cat /secrets/token)
# Run the main container process
exec "$@"

In your Dockerfile, COPY this script in and make it be the image's ENTRYPOINT. This must use JSON-array syntax, ENTRYPOINT ["entrypoint.sh"]. If you're launching your application via ENTRYPOINT, move that command into CMD instead (or combine a split ENTRYPOINT/CMD into CMD).

Now in your Compose setup, you need to create a volume and share it between the two containers.

version: '3.8'
volumes:
  secrets: # empty
services:
  imgproxy:
    image: ...
    volumes:
      - secrets:/secrets # matches the path in the entrypoint script
  server:
    image: ...
    volumes:
      - secrets:/secrets # could be a different path

(In particular if you're considering eventually running this application on Kubernetes, this approach won't work well. Of the volume types Kubernetes supports, few can be mounted into multiple containers at the same time. There is a native Kubernetes Secret object that's intended for this use, but that then gets back to the original pattern of "create the secret separately".)

Upvotes: 1

Related Questions