Docker Secrets Gestión

Docker Secrets provide a secure mechanism for managing sensitive data in containerized environments, particularly within Docker Swarm. Esta guía completa cubre creating, storing, and managing secrets securely, differentiating between environment variables and secrets, implementing secrets in Docker Compose, rotating credentials, and best practices for production deployments. Proper secrets management prevents credential exposure and ensures compliance with security standards.

Tabla de Contenidos

Comprendiendo Docker Secrets

Docker Secrets are encrypted data blobs stored in the Swarm manager's database and passed securely to authorized servicios. Secrets are never written to disk in plaintext and are only accessible to servicios explicitly granted access.

Secret architecture:

  • Secrets encrypted at rest in manager database using Raft encryption
  • Transmitted securely over TLS to worker nodos
  • Decrypted only in memory for authorized contenedores
  • Never exposed in process listings or environment
  • Audit trail available through API
# Check Swarm status (required for Secrets)
docker swarm status

# Initialize Swarm if needed
docker swarm init

# List existing secrets
docker secret ls

# Inspect secret metadata
docker secret inspect <secret-name>

# Get secret value (manager-only, use carefully)
docker secret inspect --pretty <secret-name>

Secrets vs Configs (related feature):

  • Secrets: For sensitive data (passwords, tokens, keys)
  • Configs: For non-sensitive data (config files, public keys)
  • Both encrypted in transit, Configs not encrypted at rest

Creating and Gestionando Secrets

Crea secrets from files, stdin, or external sources.

Crea secrets from stdin:

# Crea secret from piped input
echo "MyDatabasePassword123!" | docker secret create db_password -

# Crea API key secret
echo "sk-1234567890abcdef" | docker secret create api_key -

# Crea TLS certificate
cat /path/to/cert.crt | docker secret create app_cert -

# Crea TLS key
cat /path/to/key.key | docker secret create app_key -

# Crea SSH key
cat ~/.ssh/id_rsa | docker secret create ssh_key -

Crea secrets from files:

# Crea secret from file
docker secret create db_config ./db_config.json

# Crea from environment file
docker secret create app_env ./app.env

# Crea from certificate
docker secret create tls_cert ./domain.crt

# Crea from key
docker secret create tls_key ./domain.key

Generate and create secrets:

# Generate random password and create secret
openssl rand -base64 32 | docker secret create db_password -

# Generate API token
head -c 32 /dev/urandom | base64 | docker secret create api_token -

# Generate encryption key
openssl rand -hex 32 | docker secret create encryption_key -

# Crea secret with random data
python3 -c "import secrets; print(secrets.token_urlsafe(32))" | docker secret create jwt_secret -

List and inspect secrets:

# List all secrets
docker secret ls

# Get detailed secret information
docker secret inspect db_password

# Inspect multiple secrets
docker secret inspect db_password api_key ssh_key

# Format output
docker secret ls --format "table {{.Name}}\t{{.CreatedAt}}"

# View secret creation date and ID
docker secret inspect --pretty db_password

# Check secret availability
docker secret inspect db_password --format='{{.ID}}'

Remueve secrets:

# Remueve unused secret
docker secret rm api_key

# Remueve multiple secrets
docker secret rm secret1 secret2 secret3

# List secrets before cleanup
docker secret ls | grep -v CREATED

# Remueve all secrets (dangerous - confirma servicios don't use them)
docker secret ls --format '{{.Name}}' | xargs docker secret rm

Using Secrets in Servicios

Despliega servicios with access to secrets through secure mounts.

Despliega servicio with secret:

# Crea secret
echo "db_user=admin" | docker secret create db_creds -

# Despliega servicio with secret access
docker servicio create \
  --name myapp \
  --secret db_creds \
  --réplicas 2 \
  myapp:latest

# Secret accessible at /run/secrets/db_creds in contenedor

# Verifica servicio has access
docker servicio inspect myapp | grep -A 5 Secrets

# Check secret in running tarea
docker exec <contenedor-id> cat /run/secrets/db_creds

Configura secret targets (different filename):

# Secret accessible as different filename
docker servicio create \
  --name api \
  --secret source=api_key,target=api_secret \
  --secret source=db_password,target=password \
  myapi:latest

# In contenedor:
# cat /run/secrets/api_secret
# cat /run/secrets/password

Multiple secrets for one servicio:

# Crea multiple secrets
echo "admin" | docker secret create db_user -
echo "MyPassword123!" | docker secret create db_pass -
echo "sk-123abc" | docker secret create api_key -
echo "-----BEGIN CERTIFICATE-----..." | docker secret create tls_cert -

# Despliega with multiple secrets
docker servicio create \
  --name webapp \
  --secret db_user \
  --secret db_pass \
  --secret api_key \
  --secret source=tls_cert,target=certificate \
  --réplicas 3 \
  webapp:latest

# Application reads from /run/secrets/

Servicio update with secrets:

# Add new secret to running servicio
docker servicio update \
  --secret-add new_secret \
  myapp

# Remueve secret from servicio
docker servicio update \
  --secret-rm old_secret \
  myapp

# Replace secret reference
docker servicio update \
  --secret-rm old_api_key \
  --secret-add api_key \
  myapp

Secrets vs Environment Variables

Understand when to use secrets versus environment variables.

Comparison:

# Environment variables (NOT for secrets)
# - Visible in ps output
# - Visible in contenedor inspect
# - Visible in environment
# - Passed to child processes
# - Logged in Docker history

# Secrets (for sensitive data)
# - Not in ps output
# - Not in inspect output
# - Only accessible via /run/secrets/
# - Not inherited by child processes
# - Encrypted at rest and in transit

Environment variables example:

# Crea servicio with environment variables (non-sensitive)
docker servicio create \
  --name app \
  --env ENVIRONMENT=production \
  --env LOG_LEVEL=info \
  --env API_TIMEOUT=30 \
  myapp:latest

# Check env vars in running contenedor
docker exec <contenedor-id> env | grep -E "ENVIRONMENT|LOG_LEVEL"

Secrets example (sensitive):

# Crea secrets for sensitive data
echo "MyDatabasePassword!" | docker secret create db_password -
echo "sk-abc123def456" | docker secret create api_key -

# Crea servicio with secrets
docker servicio create \
  --name app \
  --secret db_password \
  --secret api_key \
  --env ENVIRONMENT=production \
  --env LOG_LEVEL=info \
  myapp:latest

# In application, read sensitive data from /run/secrets/
# Read config from environment variables

Asegura application pattern:

# Dockerfile showing best practice
cat > Dockerfile <<'EOF'
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY app.py .

# App reads secrets from /run/secrets/
# App reads config from environment variables

EXPOSE 5000
CMD ["python", "app.py"]
EOF

# Application code
cat > app.py <<'EOF'
import os

# Read non-sensitive config from environment
ENVIRONMENT = os.getenv("ENVIRONMENT", "development")
LOG_LEVEL = os.getenv("LOG_LEVEL", "info")

# Read sensitive data from secrets
try:
    with open("/run/secrets/db_password", "r") as f:
        DB_PASSWORD = f.read().strip()
except FileNotFoundError:
    DB_PASSWORD = os.getenv("DB_PASSWORD")  # fallback

try:
    with open("/run/secrets/api_key", "r") as f:
        API_KEY = f.read().strip()
except FileNotFoundError:
    API_KEY = os.getenv("API_KEY")  # fallback

# Configura application with loaded values
EOF

Docker Compose Secrets

Use secrets in Docker Compose for development and testing.

Compose file with secrets:

cat > docker-compose.yml <<'EOF'
version: '3.9'

servicios:
  db:
    imagen: postgres:15-alpine
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: admin
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
    volúmenes:
      - db_data:/var/lib/postgresql/data

  app:
    imagen: myapp:latest
    depends_on:
      - db
    secrets:
      - db_password
      - api_key
    environment:
      ENVIRONMENT: production
      DATABASE_HOST: db
    puertos:
      - "5000:5000"

secrets:
  db_password:
    file: ./secrets/db_password.txt
  api_key:
    file: ./secrets/api_key.txt

volúmenes:
  db_data:

EOF

# Crea secret files
mkdir -p secrets
echo "MyDatabasePassword123!" > secrets/db_password.txt
echo "sk-1234567890abcdef" > secrets/api_key.txt

# Inicia servicios
docker-compose up -d

# Access secrets from running contenedor
docker-compose exec app cat /run/secrets/db_password

External secrets source:

cat > docker-compose.yml <<'EOF'
version: '3.9'

servicios:
  web:
    imagen: nginx:alpine
    secrets:
      - source: tls_cert
        target: certificate.crt
      - source: tls_key
        target: certificate.key
    puertos:
      - "443:443"

secrets:
  tls_cert:
    file: /etc/ssl/certs/domain.crt
  tls_key:
    file: /etc/ssl/private/domain.key

EOF

docker-compose up -d

Secret Rotation and Updates

Safely update secrets without disrupting running servicios.

Rotation strategy:

# Current state: servicios using old_secret

# Step 1: Crea new secret
echo "NewPassword2024!" | docker secret create db_password_v2 -

# Step 2: Actualiza servicios to use new secret
docker servicio update \
  --secret-add db_password_v2 \
  myapp

# Step 3: Give contenedores time to read new secret
sleep 10

# Step 4: Reinicia contenedores to pick up new secret
docker servicio update \
  --force \
  myapp

# Step 5: Verifica servicios using new secret
docker servicio ps myapp

# Step 6: Remueve old secret after verification
sleep 30
docker secret rm db_password_v1

Rolling secret updates:

# Crea new secret version
echo "UpdatedPassword123!" | docker secret create api_key_v2 -

# Servicio with rolling update strategy
docker servicio update \
  --secret-rm api_key \
  --secret-add api_key_v2 \
  --update-parallelism 1 \
  --update-delay 30s \
  webapp

# Monitorea rolling update
watch -n 2 'docker servicio ps webapp'

# Verifica all tareas updated
docker servicio ps webapp --filter desired-state=running

Automated rotation script:

cat > rotate-secrets.sh <<'EOF'
#!/bin/bash

SERVICE="myapp"
SECRET="db_password"
NEW_PASSWORD=$(openssl rand -base64 32)
TIMESTAMP=$(date +%s)

# Crea versioned secret
docker secret create "${SECRET}_${TIMESTAMP}" <<< "$NEW_PASSWORD"

# Actualiza servicio to use new secret
docker servicio update \
  --secret-add "${SECRET}_${TIMESTAMP}" \
  "$SERVICE"

# Wait for servicio to stabilize
sleep 10

# Remueve old secrets (keep last 3 versions)
SECRETS=$(docker secret ls --format '{{.Name}}' | grep "^${SECRET}_" | sort -r)
VERSION_COUNT=0
while IFS= read -r old_secret; do
    ((VERSION_COUNT++))
    if [ $VERSION_COUNT -gt 3 ]; then
        docker secret rm "$old_secret"
    fi
done <<< "$SECRETS"

echo "Secret rotation completed for $SECRET"
EOF

chmod +x rotate-secrets.sh

# Schedule rotation
0 0 * * * /path/to/rotate-secrets.sh >> /var/log/secret-rotation.log 2>&1

Security Mejores Prácticas

Implement comprehensive security measures for secrets management.

Asegura secret creation and almacenamiento:

# Never expose secrets in command history
cat > /dev/null <<< "MyPassword" | docker secret create db_pass -

# Use secure file permissions during creation
umask 0077
echo "SecretToken" > /tmp/token.txt
docker secret create token - < /tmp/token.txt
shred -vfz -n 3 /tmp/token.txt

# Verifica secret not in bash history
history | grep secret  # Should show nothing

# Verifica secret not in Docker history
docker history myimage | grep -i secret  # Should show nothing

Audit and monitoring:

# Habilita secret audit logging
# Configura Docker daemon with audit policy

# Monitorea secret access
docker events --filter type=secret

# Check secret creation history
docker inspect <secret-id> --format='{{.CreatedAt}}'

# Log servicio updates affecting secrets
docker events --filter type=servicio

# Rotate secrets regularly
# Track secret versions for compliance

Principle of least privilege:

# Only grant secrets to servicios that need them
# Avoid wildcard secret grants

docker servicio create \
  --name specific_service \
  --secret db_password \
  --secret api_key \
  myapp:latest

# Only specific servicios should have each secret
# Not all servicios need all secrets

Encryption and compliance:

# Verifica Swarm encryption enabled
docker swarm inspect self | grep -i encrypt

# Use external secret management for compliance
# Integrate with Vault, AWS Secrets Manager, etc.

# Require authentication for secret operations
docker nodo update --role manager \
  <nodo-id>

# Managers-only can create/remove secrets
# Restricted access control

External Secrets Gestión

Integrate with external secrets management systems.

HashiCorp Vault integration:

# Example Vault integration setup
cat > Dockerfile <<'EOF'
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y curl jq

COPY vault-client.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/vault-client.sh

WORKDIR /app
COPY app.py .

ENTRYPOINT ["/usr/local/bin/vault-client.sh"]
CMD ["python", "app.py"]
EOF

cat > vault-client.sh <<'EOF'
#!/bin/bash

# Autentica with Vault
VAULT_TOKEN=$(curl -X POST \
  http://vault:8200/v1/auth/kubernetes/login \
  -d @- <<< '{"jwt":"'$VAULT_SA_TOKEN'","role":"app"}' \
  | jq -r '.auth.client_token')

# Fetch secret from Vault
SECRET=$(curl -H "X-Vault-Token: $VAULT_TOKEN" \
  http://vault:8200/v1/secret/data/app/database \
  | jq -r '.data.data.password')

# Export as environment variable
export DB_PASSWORD="$SECRET"

# Ejecuta application
exec "$@"
EOF

chmod +x vault-client.sh

AWS Secrets Manager integration:

# Docker servicio with AWS Secrets Manager access
docker servicio create \
  --name app \
  --env AWS_REGION=us-east-1 \
  --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
  myapp:latest

# Application code to fetch secrets
cat > fetch-secret.py <<'EOF'
import boto3
import json

client = boto3.client('secretsmanager')

def get_secret(secret_name):
    try:
        response = client.get_secret_value(SecretId=secret_name)
        return json.loads(response['SecretString'])
    except Exception as e:
        print(f"Error: {e}")
        return None

# Usage
db_secret = get_secret('prod/database')
db_password = db_secret['password']
EOF

Solución de Problemas Secrets

Diagnose and resolve secrets-related issues.

Depura secret access:

# Verifica secret exists
docker secret ls | grep db_password

# Check secret metadata
docker secret inspect db_password

# Verifica servicio has secret access
docker servicio inspect myapp | grep -A 20 Secrets

# Prueba secret availability in contenedor
docker exec <contenedor-id> ls -la /run/secrets/

# Read secret content from contenedor
docker exec <contenedor-id> cat /run/secrets/db_password

# Check file permissions
docker exec <contenedor-id> stat /run/secrets/db_password

Common issues and solutions:

# Issue: Servicio can't access secret
# Solution: Verifica secret is assigned to servicio

docker servicio update --secret-add missing_secret myapp

# Issue: Secret not found in contenedor
# Solution: Verifica correct secret name

docker exec <contenedor-id> ls /run/secrets/

# Issue: Secret file permissions denied
# Solution: Secrets have 600 permissions, run as correct user

# In Dockerfile:
# RUN addgroup -S app && adduser -S app -G app
# USER app

# Issue: Old secret still accessible after update
# Solution: Reinicia contenedores to reload

docker servicio update --force myapp

Conclusión

Docker Secrets provide a production-grade mechanism for managing sensitive data in containerized environments. By understanding the distinction between secrets and environment variables, implementing proper access controls, and integrating with orchestration systems, you create secure infrastructure that meets compliance requirements. Inicia with basic secret creation and servicio assignment, progress to automated rotation, and eventually integrate with external secrets management systems for enterprise deployments. Regular audits of secret access and rotation schedules asegúrate de que your secrets remain protected as your infrastructure evolves. Treat secrets management as a foundational security practice, not an afterthought.