Storing and Managing Secrets
Secrets are crucial in production environments to ensure that sensitive data such as passwords, API keys, or certificates are not hardcoded in the application or exposed in version control. Below are practices and examples for managing secrets in a Docker CLI context.
1. Using Environment Variables
A common method for managing secrets in Docker setups is through environment variables. This can be done in the docker-compose.yml
file or using Docker secrets in swarm mode.
Example: Environment Variables in docker-compose.yml
version: "2"
services:
server:
build:
context: .
dockerfile: server.Dockerfile
environment:
- DATABASE_URL=mysql://user:${MYSQL_PASSWORD}@mysql/db
In the above example, ${MYSQL_PASSWORD}
is expected to be set in the environment where docker-compose
is executed, thus controlling access to the MySQL database without exposing the password in the Dockerfile or compose file.
2. Docker Secrets in Swarm Mode
For a more secure management of sensitive information, Docker Secrets can be used when operating in swarm mode.
Step-by-Step: Docker Secrets
- Initialize Docker Swarm (if not already done):
docker swarm init
- Create a Secret:
echo "my_secret_password" | docker secret create mysql_password -
- Reference the Secret in
docker-compose.yml
:
version: "3.1"
services:
mysql:
image: mariadb:10.4
secrets:
- mysql_password
environment:
- TERM=dumb
- MYSQL_ALLOW_EMPTY_PASSWORD="true"
command: mysqld --innodb_file_per_table
secrets:
mysql_password:
external: true
In this example, the mysql_password
secret is securely made available to the MySQL container without embedding it directly in the configuration.
3. Encrypting Secrets
In addition to using environment variables and Docker secrets, it’s often a good practice to encrypt sensitive data. This can be done using tools such as openssl
.
Example: Encrypting a Secret
openssl enc -aes-256-cbc -salt -in secrets.txt -out secrets.txt.enc -k mypassword
You can then decrypt this in your Docker containers as needed using a similar command.
4. Using Configuration Management Tools
For complex setups, integrating with configuration management tools like HashiCorp Vault can help manage secrets dynamically.
Example: Fetching Secrets from Vault
Using a Go application inside a Docker container, one might retrieve secrets as follows:
package main
import (
"fmt"
"log"
"github.com/hashicorp/vault/api"
)
func main() {
client, err := api.NewClient(api.DefaultConfig())
if err != nil {
log.Fatalf("Error creating Vault client: %v", err)
}
secret, err := client.Logical().Read("secret/myapp")
if err != nil {
log.Fatalf("Error reading secret: %v", err)
}
if secret != nil {
fmt.Printf("Secret Value: %s\n", secret.Data["value"])
}
}
This Go application can be included in a Docker image, and upon executing, it will retrieve secrets stored securely in Vault.
5. Best Practices for Secrets Management
- Minimize Secret Lifespan: Regularly rotate secrets and avoid long-lived ones.
- Least Privilege: Only provide access to secrets that are necessary for the application operation.
- Audit Secrets Usage: Monitor access to secrets to identify misuse.
Employing the above methods ensures a secure and robust approach to managing production secrets in Docker environments, protecting sensitive information from unauthorized access.