How to make your Docker images secrets enabled
Integrated into Docker swarm, Docker secrets gives a complete and secure way to manage sensitive data shared with your containers.
No more environment variables or worth plain text files with username and password shared or baked into your containers.
Everything in Docker secrets have been built based on 2 concepts:
- security
- simplicity
Here’s a quick review of how it works (courtesy of Docker blog):
The following diagram provides a high-level view of how the Docker swarm mode architecture is applied to securely deliver a new type of object to our containers: a secret object.
In Docker, a secret is any blob of data, such as a password, SSH private key, TLS Certificate, or any other piece of data that is sensitive in nature. When you add a secret to the swarm (by running docker secret create), Docker sends the secret over to the swarm manager over a mutually authenticated TLS connection, making use of the built-in Certificate Authority that gets automatically created when bootstrapping a new swarm.
Secrets creation is dead simple:
$ echo "My super secret password" | docker secret create super_secret -
Now we need to share our newly created secret with a service
nodes cannot request the secrets themselves, and will only gain access to the secrets when provided to them by a manager – strictly for the services that require them.
2 methods are available:
- using CLI:
docker service create --name="redis" --secret="super_secret" redis:alpine
- using compose (3.1+):
version: "3.1" services: redis: image: redis:latest deploy: replicas: 1 secrets: - super_secret secrets: super_secret: external: true
What does it mean to our services ?
Sharing a secret to a specific service will create in the service container’s filesystem, the file :
/run/secrets/[secret name]
in which sensitive data is stored.
Here comes our main topic: How to make your docker images secrets enabled ??
As explained, secrets are stored in files shared securely with our services.
Which means our Docker images must be customized to read the needed files.
Here’s a very simple example using percona-xtradb-cluster Docker image.
Percona Docker images needs at least a mysql root password which is shared using the cough environment variable cough: MYSQL_ROOT_PASSWORD
docker run -e MYSQL_ROOT_PASSWORD=my-secret-pw -d [percona:tag]
To make our image secrets enabled, we just have to give the ability to read our secret file.
Easy as one!, two!, three!
One: edit the file entrypoint.sh
Two: add MYSQL_ROOT_PASSWORD_FILE as a valid variable:
if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" -a -z "$MYSQL_ROOT_PASSWORD_FILE" ]; then
echo >&2 'error: database is uninitialized and password option is not specified '
echo >&2 ' You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ROOT_PASSWORD_FILE, MYSQL_ALLOW_EMPTY_PASSWORD or MYSQL_RANDOM_ROOT_PASSWORD'
exit 1
fi
Three: make entrypoint.sh
read our secret file
if [ ! -z "$MYSQL_ROOT_PASSWORD_FILE" -a -z "$MYSQL_ROOT_PASSWORD" ]; then
MYSQL_ROOT_PASSWORD=$(cat $MYSQL_ROOT_PASSWORD_FILE)
fi
Build your image and you’re ready to go!
Here’s an example using docker-compose:
- Create the mysql root password secret:
echo R00tT00r | docker secret create percona-secret -
- create the appropriate docker-compose.yml:
version: "3.1" services: redis: image: percona-server:[your special tag] deploy: replicas: 1 secrets: - percona-secret secrets: percona-secret: external: true
- deploy your percona secrets enabled stack:
docker stack deploy -c docker-compose.yml percona
Done!
Look for part two, where I will show more patterns for using docker secret
Have fun !
R.