As discussed in the previous article, Docker secrets are a secure way to manage sensitive information in Dockerized environments. You got to see how you could incorporate secrets into compose files and also how you could manage secrets using the docker secret
command.
As a follow-up to the previous article, we’ll be looking at three practical use cases of Docker secrets. We’ll go through how to use Docker secrets in a Dockerfile, manage WordPress secrets with Docker secrets, and roll back a secret. Through these practical examples, you will better understand how you can use Docker secrets in real-world scenarios.
Prerequisites
To fully understand the hands-on examples in this article, you should have a basic understanding of Docker and Docker secrets. If you’re new to Docker secrets, you can check out the previous article to get started.
Additionally, you should have Docker installed on your machine preferably with Docker Swarm enabled.
Using Docker Secrets in a Dockerfile
In some cases, you might need to incorporate secrets directly into your Docker image. This could be necessary when you need to build an image that requires a secret to be present at build time. In this example, we’ll look at incorporating a secret into a Docker image using a Dockerfile.
Step 1: Create a Secret
First, you must create a secret that will be incorporated into the Docker image. You can create a secret using the docker secret create
command.
For this tutorial, let’s say you have an AWS access key stored in a file named aws_credentials
in your home directory ($HOME/.aws/credentials
).
Step 2: Create a Dockerfile
Create a Dockerfile in your project directory. This Dockerfile will define the steps needed to build your Docker image, including how to access and use the secret.
FROM your_base_image
# Create a directory for the secret
RUN mkdir -p /run/secrets# Copy the secret file into the container
COPY $HOME/.aws/credentials /run/secrets/aws_credentials# Use the secret in your build process
RUN --mount=type=secret,id=mytoken \
TOKEN=$(cat /run/secrets/aws_credentials) \
# Your build commands here
Replace your_base_image
with the base image you’re using for your Docker image.
This Dockerfile creates a directory for the secret, copies the secret file into the container, and then uses the secret in the build process. The --mount=type=secret,id=mytoken
flag allows you to pass the secret to the build process securely.
In an actual scenario, you would replace the # Your build commands here
with the specific commands needed to build your Docker image.
NOTE: As emphasized in the previous article, sharing secrets over version control systems like Git is not recommended. For this example, we’re assuming the secret file is stored locally on your machine, so it’s not shared with others.
Step 3: Build Your Docker Image
Now, build your Docker image using the docker build
command. Make sure to use the --secret
flag to pass the secret to the build process.
docker build --secret id=mytoken .
This command will build your Docker image while securely passing the secret to the build process.
Step 4: Use the Secret in Your Application
You can now use the secret in your application as needed. For example, if you’re using the AWS access key in your application to interact with AWS services, you can access it using the TOKEN
environment variable set in the Dockerfile.
NOTE: Remember to replace mytoken
with a meaningful identifier for your secret. Also, ensure that the secret file (aws_credentials
in this example) is stored securely and is only accessible to authorized users.
Managing WordPress Secrets
WordPress is a popular content management system that often requires sensitive information like database passwords to be securely managed.
In this example, we’ll create single-node MySQL and WordPress services using Docker secrets to manage sensitive credentials. We’ll set up a MySQL database for WordPress and configure WordPress to connect to MySQL.
Overview
This tutorial can get a bit complex, so let’s break it down into steps:
- Generate random alphanumeric passwords for MySQL root and WordPress database.
- Create Docker secrets for MySQL and WordPress.
- Set up a MySQL service with Docker secrets.
- Configure a WordPress service to use MySQL with Docker secrets.
- Verify the services are running and test WordPress functionality.
Step 1: Generate Docker Secrets
Generate random passwords for MySQL root and WordPress database:
# Generate MySQL root password
openssl rand -base64 20 | docker secret create mysql_root_password -
# Generate WordPress database password
openssl rand -base64 20 | docker secret create mysql_password -
You should now have two Docker secrets with an output similar to:
uxm1a4sjjsg7enq2m1dtmvnon
5judi7jm6d02xs99lj8061wul
Step 2: Create MySQL Service
Create a MySQL service with Docker secrets:
docker network create -d overlay mysql_private
docker service create \
--name mysql \
--replicas 1 \
--network mysql_private \
--mount type=volume,source=mydata,destination=/var/lib/mysql \
--secret source=mysql_root_password,target=mysql_root_password \
--secret source=mysql_password,target=mysql_password \
-e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_root_password" \
-e MYSQL_PASSWORD_FILE="/run/secrets/mysql_password" \
-e MYSQL_USER="wordpress" \
-e MYSQL_DATABASE="wordpress" \
mysql:latest
Your output should look similar to:
v87xhur2iqhwhvmql11345l7k
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
This command creates a MySQL service with the specified secrets and environment variables. The MySQL service will be connected to the mysql_private
overlay network.
Step 3: Create WordPress Service
Create a WordPress service that connects to MySQL using Docker secrets:
docker service create \
--name wordpress \
--replicas 1 \
--network mysql_private \
--publish published=30000,target=80 \
--mount type=volume,source=wpdata,destination=/var/www/html \
--secret source=mysql_password,target=wp_db_password \
-e WORDPRESS_DB_USER="wordpress" \
-e WORDPRESS_DB_PASSWORD_FILE="/run/secrets/wp_db_password" \
-e WORDPRESS_DB_HOST="mysql:3306" \
-e WORDPRESS_DB_NAME="wordpress" \
wordpress:latest
You should see output similar to:
whoumrpbcry3exply4fl9euue
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
This command creates a WordPress service that connects to the MySQL service using Docker secrets. The WordPress service will be accessible on port 30000.
Step 4: Verify and Test
Finally, verify that the services are running and test WordPress functionality:
# Verify services
docker service ls
# Test WordPress
docker service ps wordpress
You output should look similar to:
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
q2qzd1d2hup1 wordpress.1 wordpress:latest docker-desktop Running Running 2 minutes ago
Access http://localhost:30000/
from any swarm node to set up WordPress using the web-based wizard. Verify that WordPress is operational and its state is saved across service restarts.
NOTE: You need an active Docker Swarm to run the services. If you’re using Docker Desktop, you can enable Swarm mode by running docker swarm init
.
Rotating Back a Secret
Rotating a secret means changing its value without affecting the services that use it. This is an important security practice to prevent unauthorized access to sensitive information.
This tutorial will demonstrate how to rotate a secret in Docker, building upon the previous use case. We’ll create a new secret with a new MySQL password, update the MySQL and WordPress services to use it, and then remove the old secret.
Step 1: Create a New Secret
Generate a new password and store it as a secret named mysql_password_v2
:
openssl rand -base64 20 | docker secret create mysql_password_v2 -
vwqvnkm1gploicqk2g32vwpf2
Step 2: Update Services
Update the MySQL service to grant it access to the old and new secrets. Remove the old secret and add the new one:
docker service update \
--secret-rm mysql_password mysql
docker service update \
--secret-add source=mysql_password,target=old_mysql_password \
--secret-add source=mysql_password_v2,target=mysql_password \
mysql
You should see output similar to:
mysql
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Waiting 5 seconds to verify that tasks are stable...
service update paused: update paused due to failure or early termination of task f98yfogvf606ddrdc0z3b1paf
mysql
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
This command updates the MySQL service to use the new secret while keeping the old secret for backward compatibility.
Step 3: Change MySQL Password
Change the MySQL password for the WordPress user using the mysqladmin
CLI. This command reads the old and new passwords from the secret files:
docker container exec $(docker ps --filter name=mysql -q) \
bash -c 'mysqladmin --user=wordpress --password="$(< /run/secrets/old_mysql_password)" password "$(< /run/secrets/mysql_password)"'
You should see output similar to:
mysqladmin: [Warning] Using a password on the command line interface can be insecure.
Warning: Since password will be sent to server in plain text, use ssl connection to ensure password safety.
This command changes the MySQL password for the WordPress user to the new password.
Step 4: Update WordPress Service
Update the WordPress service to use the new password. Trigger a rolling restart of the service:
docker service update \
--secret-rm mysql_password \
--secret-add source=mysql_password_v2,target=wp_db_password \
wordpress
You should see output similar to:
```bash
wordpress
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
```This command updates the WordPress service to use the new secret and removes the old secret.
Step 5: Verify Functionality
On the WordPress site, verify that you can still access and interact with the site as expected. Ensure that the MySQL password change did not affect the WordPress functionality.
NOTE: You might be wondering how all this can work in CI/CD pipelines such as Semaphore. To make this possible, you’ll need scripts. So, instead of manually running these commands on your machine, the CI/CD pipeline will execute this script and commands automatically whenever there is a new code push or a trigger event. To try it out, check out this GitHub repository that goes through this process.
However, Semaphore has a much simpler way of including secrets into your project. You can check this page on creating and managing secrets to know more.
Step 6: Revoke Access and Cleanup
After verifying that the services are operational, revoke access to the old secret and clean up the old secret:
docker service update \
--secret-rm mysql_password \
mysql
docker secret rm mysql_password
You should see output similar to:
```bash
mysql
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
mysql_password
```
Conclusion
In this article, we looked at three practical use cases of Docker secrets. We explored how to incorporate secrets into a Docker image using a Dockerfile, manage WordPress secrets using Docker secrets, and rotate a secret in Docker.
With these examples, using secrets in various scenarios becomes more straightforward. You can now apply Docker secrets to your projects to securely manage sensitive information and improve the security of your Dockerized applications.
Originally published at https://semaphoreci.com on May 29, 2024.