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

  1. Initialize Docker Swarm (if not already done):
docker swarm init
  1. Create a Secret:
echo "my_secret_password" | docker secret create mysql_password -
  1. 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.

References