Mastodon hachyterm.io

Today I tried to create a docker secret for a Docker Swarm stack.

Why?
The secret is encrypted and you cannot read it. I’ve used environment variables before, but they are stored as plain text. You can see them if you inspect the Docker service/image.

It took me a while to figure out how to use docker secrets with a docker-compose.yml.

You can use Docker secrets both locally (docker-compose up) and for production (docker stack deploy).

In this post I’ll show you how to use Docker secrets with docker-compose.

Create a secret

“External” Create

You can manually create a secret from the command line before you run your docker-compose.yml file.

1. Create secret from stdin

In your terminal:

printf "some string that is your secret value" | docker secret create my_secret -

where my_secret will be the name of the Docker secret.

2. Create from file

Let’s say you have file with a password. For example,db_pass.txt has the following content: superSecretPassword.

Now you can create a new secret from that file:

docker secret create my_db_pass db_pass.txt

where my_db_pass is the name of your secret.

List all available secrets:

docker secret ls

You should see an entry with my_db_pass.

Directly Inside docker-compose.yml

Inside your docker-compose.yml you need to create a top-level entry called secrets:

version: '3'

secrets:
  psql_user:
    file: ./psql_user.txt
  psql_password:
    file: ./psql_password.txt

Here we have two secrets psql_user and psql_password which are created from the files with the same name.

This technique does not require the initial setup with docker secret create.

Please remember that storing the “secret” files as plain text files on your production machine is not secure. You’ll have to find a way to hide the text files.

You need compose version 3.

How to Use a Secret in docker-compose.yml

Let’s say we initialize two secrets for a database:

printf "my_db_user" | docker secret create db_user -
printf "superSecretDBpassword" | docker secret create db_password -

First, you need the top-level declaration of all secrets.

Example:

version: '3'

secrets:
  db_user:
    external: true
  db_password:
    external: true

Here we use the external keyword to show that we created the secrets before using the docker-compose.yml file. You can use external secrets when Docker is in swarm mode (docker swarm init).

For a local setup, you might want to use the file version:

version: '3'

secrets:
  db_user:
    file: ./my_db_user.txt
  db_password:
    file: ./my_db_pass.txt

Now you have to tell each service which secrets it is allowed to use.

Example:

version: '3'

secrets:
  db_user:
    external: true
  db_password:
    external: true

services:
  postgres_db:
  image: postgres
  secrets:
    - db_user
    - db_password

The postgres_db service can now access the db_user and db_password secrets.

How can I use the secrets now?

You can access the secrets via /run/secret/<secret-name> in docker-compose.yml.

Please note that the secrets are stored as files.

Example:

version: '3'

secrets:
  db_user:
    external: true
  db_password:
    external: true

services:
  postgres_db:
  image: postgres
  secrets:
    - db_user
    - db_password
  environment:
    - POSTGRES_USER_FILE=/run/secrets/db_user
    - POSTGRES_PASSWORD_FILE=/run/secrets/db_password

As you can see, we must adjust the environment variables to append a _FILE directive.

Inspect a Secret

In your terminal:

docker secret inspect <name-of-secret>

The command will show some information about the secret, but not the hidden value.

And Now?

Now you know how to use secrets. They are more secure than environment variables if you use them correctly.

Further Reading