Use Docker Secrets
Use Docker secrets for sensitive data — Docker.
Focus: use docker secrets for sensitive data
Hardcoding database passwords, API tokens, or SSH keys into your Docker images feels convenient — until one leaked file exposes your entire infrastructure. That lingering .env file in the build context or a hard-coded secret in a Dockerfile is a ticking time bomb in production. This lesson teaches you how to use Docker secrets for sensitive data — a secure, built-in mechanism that keeps credentials out of images, environment variables, and container layers — so you can deploy with confidence.
The problem this lesson solves
Containers need secrets: database passwords, API tokens, TLS certificates, or private keys. The naive approach — putting secrets in environment variables, copying them into images with COPY, or baking them into config files — introduces two fatal flaws:
- Secrets leak into image layers. Any
docker historyor image pull exposes the secret forever. - Secrets spread across environments. A hard-coded secret in a development image might end up cloned into production.
Even using .env files is risky: if the file is accidentally committed, copied into a volume, or logged during debugging, the secret is compromised. Docker secrets solve this by injecting sensitive data only into the container at runtime — never into the image or the build cache.
Core concept / mental model
Think of Docker secrets as a secure courier service between the Swarm manager and your container. You declare a secret by name, and the manager delivers the actual value (e.g., a password) to only the containers that need it — encrypted in transit and at rest on the manager. The secret is written to a temporary in-memory filesystem (/run/secrets/) inside the container and removed when the container stops.
Key definitions
- Secret: a blob of data — a password, API key, or certificate — referenced by name.
- Docker Swarm: the orchestrator that manages secret distribution. Secrets are a Swarm feature, not available for standalone containers.
docker secret create: registers a secret with the Swarm manager./run/secrets/<secret_name>: the default mount point inside the container where the secret contents appear as a plain text file.
This is not about encrypting data at rest in your database — it’s about securing the transmission and storage of secrets between the orchestration layer and the container runtime.
Why not environment variables?
Environment variables are inspectable via docker inspect, docker exec env, or even inside a compromised container. Docker secrets are ephemeral and scope-limited: they exist only as files in the memory of the specific task (container) that needs them.
How it works step by step
1. Initialize your Swarm (one-time)
Secrets require Swarm mode, even on a single-node setup.
docker swarm init
2. Create the secret
Use docker secret create with a file or standard input.
echo "my-super-secret-password" | docker secret create db_password -
The trailing
-means read from stdin. Alternatively, usedocker secret create db_password ./password.txt.
3. Grant access to a service
When deploying a service with docker service create, attach the secret using the --secret flag.
docker service create \
--name my_app \
--secret db_password \
--publish 3000:3000 \
my_image:latest
4. Read the secret inside the container
Inside the container, the secret is available as a file at /run/secrets/db_password.
# Python example: read a Docker secret
import os
def read_secret(secret_name):
secret_path = f"/run/secrets/{secret_name}"
try:
with open(secret_path, "r") as f:
return f.read().strip()
except FileNotFoundError:
return os.environ.get(secret_name, "default_fallback")
db_pass = read_secret("db_password")
print(f"DB password length: {len(db_pass)}")
Expected output:
DB password length: 24
5. Clean up
When you remove the service, the secret file is automatically destroyed.
docker service rm my_app
docker secret rm db_password
Hands-on walkthrough
Let’s build a complete end-to-end example with a PostgreSQL service that uses a secret for the password.
Step 1: Create the secret
docker swarm init
echo "s3cureP@ssw0rd!" | docker secret create postgres_password -
Step 2: Deploy PostgreSQL with the secret
docker service create \
--name postgres \
--secret postgres_password \
-e POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password \
-e POSTGRES_USER=myuser \
-e POSTGRES_DB=mydb \
--publish 5432:5432 \
postgres:15
Notice we use
POSTGRES_PASSWORD_FILE— many Docker images support this pattern instead ofPOSTGRES_PASSWORDto avoid passing secrets as env vars.
Step 3: Verify the secret inside the container
# Find the container ID
docker ps --filter "name=postgres"
# Confirm the file exists
docker exec <container-id> cat /run/secrets/postgres_password
Expected output:
s3cureP@ssw0rd!
Step 4: Use the secret in a Python application
Let’s write a minimal Python client that connects to PostgreSQL using the secret.
# app.py
import psycopg2
import os
def get_secret(secret_name):
with open(f"/run/secrets/{secret_name}") as f:
return f.read().strip()
conn = psycopg2.connect(
host="postgres",
user="myuser",
password=get_secret("postgres_password"),
dbname="mydb"
)
print("Connected successfully")
conn.close()
Compare options / when to choose what
| Method | Security | Persistence | Secret rotation | Recommended for |
|---|---|---|---|---|
| Docker Secrets | High (in-memory, encrypted) | Ephemeral per container | Manual or via service update | Production Swarm services |
| Environment variables | Medium (leaked via inspect) | Persistent in image if baked | Rebuild image | Development / quick tests |
.env file |
Low (committed easily) | Filesystem | Manual | Local dev only |
| Vault/External secret store | Very high | N/A | Automated | Large-scale multi-service |
Choose Docker secrets when you need a simple, built-in mechanism for Swarm services with zero external dependencies. For more complex rotation or cross-cluster secrets, consider HashiCorp Vault or cloud-native secret managers (AWS Secrets Manager, GCP Secret Manager).
Troubleshooting & edge cases
Secret not appearing in /run/secrets/
- Ensure the service is running in Swarm mode. Run
docker info | grep Swarm— it should sayactive. - Verify the secret exists:
docker secret ls. - The container must be part of one or more services that have the secret attached.
Permission denied when reading the secret
The secret file is created with root ownership. If your application runs as a non-root user (best practice), adjust the service to mount the secret with the correct UID/GID:
docker service create \
--name my_app \
--secret source=db_password,target=db_password \
--user 1000:1000 \
my_image
Secret too large
Docker secrets are designed for small blobs (recommended <500 KB). For larger files, consider mounting a volume with proper encryption or using a dedicated secret store.
Updating a secret without restarting the service
Docker does not automatically update secrets inside running containers. To rotate a secret:
1. Create a new secret with a new name (db_password_v2).
2. Update the service to add the new secret and remove the old one.
3. Rebuild your application to read the new file path, or use a symlink approach.
docker service update \
--secret-rm db_password \
--secret-add db_password_v2 \
my_app
Secrets in Docker Compose (Swarm mode)
Docker Compose files can declare secrets only when deployed to a Swarm (using docker stack deploy). Example docker-compose.yml:
version: "3.8"
services:
app:
image: my_app
secrets:
- db_password
secrets:
db_password:
external: true # created via `docker secret create`
Deploy with:
docker stack deploy -c docker-compose.yml my_stack
What you learned & what's next
You now know how to use Docker secrets for sensitive data — from creating and attaching secrets to reading them inside containers. You understand why secrets are safer than environment variables or image layers, and you’ve seen how to handle common pitfalls like permissions and rotation.
In the next lesson, you’ll explore Docker configs — a similar mechanism for non-sensitive configuration files (like .env templates or JSON configs) that also lives outside the image. You’ll apply both secrets and configs to build a production-ready multi-service stack.
Practice recap
Mini exercise: Deploy a simple Redis service that reads a password from a Docker secret. Create a secret redis_pass with value s3cret, then run docker run -d --name redis-secure --secret redis_pass redis:7-alpine -requirepass $(cat /run/secrets/redis_pass). Verify you can connect using redis-cli -a s3cret.
Common mistakes
- Trying to use
docker secret createwithout initializing a Swarm — the command fails with a Swarm-related error. - Hard-coding the secret value in a Dockerfile
COPYinstruction, which embeds it into the image layer forever. - Forgetting to update the service when rotating a secret — the container holds the old value until recreated.
- Assuming secrets are automatically updated inside running containers — they are not; you must explicitly restart the service.
Variations
- Use
docker secret create my_secret -with stdin for piping output from password generators. - Specify a custom target path inside the container with
--secret source=my_secret,target=/custom/path. - Combine Docker secrets with a wrapper script that reads
/run/secrets/and exports them as environment variables for legacy apps.
Real-world use cases
- Inject database credentials into a production Swarm service running PostgreSQL or MySQL — the password never touches the image.
- Securely distribute TLS certificate private keys to a load-balanced NGINX service without embedding them in the build artifact.
- Provide API keys to a microservice that consumes an external SaaS — rotate the key by creating a new secret and updating the service.
Key takeaways
- Docker secrets require Swarm mode — even on a single node, run
docker swarm initfirst. - Secrets are mounted as files at
/run/secrets/<name>inside the container, never as environment variables by default. - Secrets are encrypted at rest on the manager and in transit, and they are never stored in image layers.
- To update a secret, create a new one and use
docker service updatewith--secret-rmand--secret-add. - Docker secrets are for small, sensitive blobs (<500 KB); use external secret managers for larger or dynamic secrets.
- In Compose files for Swarm, define secrets as
external: trueand create them beforehand withdocker secret create.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.