Skip to content
BotServBotServ
DockerSecretsDocker ComposeSeguridadVariables de entorno

Gestionar Docker Secrets con Compose

Cómo gestionar Secrets en Docker Compose de forma segura. Secrets externos, archivos .env y mejores prácticas.

S

schutzgeist

10 min read
Gestionar Docker Secrets con Compose

Gestionar Docker Secrets con Compose

Qué cubre este artículo sobre Docker Secrets con Compose

  • Qué son Docker Secrets y por qué son más seguros que las variables de entorno.
  • Qué métodos existen para gestionar Secrets en Docker Compose.
  • Cómo utilizar Secrets externos con Docker Swarm y Compose.
  • Cómo usar correctamente archivos .env y qué debes evitar.
  • Cuáles son los errores típicos con Secrets en Docker y cómo resolverlos.

Introducción: Docker Secrets explicado de forma clara

Los Secrets son datos confidenciales como contraseñas, claves de API, tokens y certificados. En Docker Compose, estos Secrets deben llegar a los contenedores sin que aparezcan en texto plano en el archivo docker-compose.yml o en la línea de comandos. Docker Secrets es un mecanismo que resuelve esto de forma segura.

Este artículo está dirigido a desarrolladores que usan Docker Compose y quieren gestionar Secrets de manera segura. Deberías entender cómo funciona Docker Compose y qué significa Secret Management. Si te interesa profundizar en seguridad en Docker, encontrarás más información en IRC-Security.de.

¿Por qué necesito Docker Secrets?

Imagina que administras un stack Docker con Nextcloud, PostgreSQL y Ollama. Cada servicio necesita contraseñas: la base de datos del administrador, Nextcloud para la conexión a la BD, Ollama para la API. Si escribes estas contraseñas como variables de entorno en docker-compose.yml, cualquiera que vea el archivo puede leerlas.

Aún peor: las variables de entorno son visibles dentro del contenedor. Cualquiera que acceda al contenedor puede ejecutar env para ver todas las contraseñas. Aparecen en logs, en volcados de memoria y en listas de procesos que cualquier usuario del sistema puede consultar.

Docker Secrets soluciona esto porque monta los Secrets en archivos visibles solo para el contenedor específico. No aparecen en variables de entorno, no aparecen en la lista de procesos y no aparecen en los logs.

Docker Secrets en breve

Docker Secrets son datos confidenciales que Docker gestiona y pone a disposición de los contenedores como archivos. El contenedor lee el Secret desde un archivo bajo /run/secrets/ en lugar de recibirlo como variable de entorno. El archivo existe solo en la memoria del contenedor y nunca se escribe en disco.

La idea central es simple: los Secrets pertenecen en archivos, no en variables de entorno. Los archivos pueden protegerse, rotarse y auditarse; las variables de entorno no.

¿A quién va dirigido Docker Secrets?

  • Desarrolladores que ejecutan stacks Docker Compose con datos sensibles.
  • Administradores de sistemas que gestionan Secrets en entornos Docker.
  • Responsables de seguridad que quieren garantizar que los Secrets no se expongan en texto plano.
  • Self-hosters que desean ejecutar sus servicios de forma segura.

Es útil tener experiencia previa con Docker Compose y conocimientos básicos de Secret Management. Si nunca has trabajado con Docker Compose, deberías leer primero los conceptos fundamentales.

Términos clave sobre Docker Secrets

  • Secret - Datos confidenciales como contraseñas, claves de API, tokens. Útil: en cualquier servicio que necesite autenticarse.
  • Docker Compose - Herramienta para definir stacks multi-contenedor. Útil: para cualquier stack Docker.
  • Docker Swarm - Orquestación de contenedores con Secret Management integrado. Útil: cuando quieres gestionar Secrets de forma nativa.
  • Archivo .env - Archivo con variables de entorno que Docker Compose carga automáticamente. Útil: para valores que no son críticos.
  • HashiCorp Vault - Sistema centralizado de Secret Management. Útil: con muchos Secrets y rotación necesaria.
  • Infisical - Gestor de Secrets de código abierto. Útil: como alternativa a Vault.
  • Mozilla SOPS - Herramienta para cifrar Secrets en archivos. Útil: si quieres versionar Secrets en Git.

Métodos para Secrets en Docker Compose

Existen varios métodos para gestionar Secrets en Docker Compose. Cada uno tiene sus ventajas e inconvenientes.

Método 1: Variables de entorno (no recomendado)

El método más simple pero inseguro. Las contraseñas aparecen como variables de entorno en el contenedor y son visibles para cualquiera que acceda a él.

services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: "mein-geheimes-passwort"

Solo deberías usar este método para datos no sensibles. Las contraseñas y claves de API no tienen lugar aquí.

Método 2: Archivo .env

El archivo .env está en el mismo directorio que docker-compose.yml y Docker Compose lo carga automáticamente. Las variables se referencian en el archivo Compose.

.env:

POSTGRES_PASSWORD=mein-geheimes-passwort

docker-compose.yml:

services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

El archivo .env no debe subirse al repositorio Git. Agrégalo a .gitignore. Este método es mejor que tener contraseñas en texto plano en la Compose, pero las contraseñas aún terminan como variables de entorno en el contenedor.

Método 3: Docker Compose Secrets (recomendado)

Docker Compose soporta Secrets desde la versión 1.27. Defines los Secrets en la sección secrets y los vinculas a los contenedores. Los Secrets se ponen a disposición como archivos bajo /run/secrets/ en el contenedor.

services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
    secrets:
      - postgres_password

secrets:
  postgres_password:
    file: ./secrets/postgres_password.txt

El archivo ./secrets/postgres_password.txt contiene la contraseña en texto plano. Docker lee el archivo y pone el contenido a disposición del contenedor como archivo bajo /run/secrets/postgres_password. La contraseña no aparece en variables de entorno, sino que la aplicación la lee del archivo.

Importante: muchas imágenes oficiales soportan la convención *_FILE. En lugar de POSTGRES_PASSWORD usas POSTGRES_PASSWORD_FILE e indicas la ruta al archivo del Secret. Esto aplica a PostgreSQL, MySQL, Redis, Nextcloud y muchos otros.

Método 4: Secrets externos con Docker Swarm

Si usas Docker Swarm, puedes gestionar Secrets de forma centralizada y ponerlos a disposición de los contenedores. Los Secrets se almacenan cifrados en el Swarm y solo son accesibles para los contenedores que los necesitan.

# Crear Secret
echo "mein-geheimes-passwort" | docker secret create postgres_password -

# Usar Secret en Compose
services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
    secrets:
      - postgres_password

secrets:
  postgres_password:
    external: true

Este método es el más seguro porque los Secrets no residen en archivos en disco, sino que se almacenan en el Swarm. El requisito es tener un Swarm en ejecución.

Método 5: Herramientas de gestión de secretos

Para configuraciones más grandes vale la pena usar un sistema central de gestión de secretos como HashiCorp Vault o Infisical. Estos sistemas administran los secretos de forma centralizada, los rotan automáticamente y registran cada acceso.

La integración en Docker Compose suele hacerse a través de contenedores init o contenedores sidecar que obtienen los secretos y los ponen a disposición como archivo.

Ejemplo práctico: un stack con Docker Secrets

Imagina que quieres configurar un stack con PostgreSQL, Nextcloud y Ollama. Los tres necesitan contraseñas. La estructura con Docker Secrets se vería así:

  1. Crear directorio de secretos: mkdir -p secrets
  2. Generar secretos:
    openssl rand -base64 32 > secrets/postgres_password.txt
    openssl rand -base64 32 > secrets/nextcloud_password.txt
    openssl rand -base64 32 > secrets/ollama_api_key.txt
    chmod 600 secrets/*.txt
  3. docker-compose.yml con secretos:
    services:
      postgres:
        image: postgres:16
        environment:
          POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
        secrets:
          - postgres_password
        volumes:
          - postgres-data:/var/lib/postgresql/data
    
      nextcloud:
        image: nextcloud:latest
        environment:
          POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
          NEXTCLOUD_ADMIN_PASSWORD_FILE: /run/secrets/nextcloud_password
        secrets:
          - postgres_password
          - nextcloud_password
        depends_on:
          - postgres
    
      ollama:
        image: ollama/ollama:latest
        environment:
          OLLAMA_API_KEY_FILE: /run/secrets/ollama_api_key
        secrets:
          - ollama_api_key
        volumes:
          - ollama-data:/root/.ollama
    
    secrets:
      postgres_password:
        file: ./secrets/postgres_password.txt
      nextcloud_password:
        file: ./secrets/nextcloud_password.txt
      ollama_api_key:
        file: ./secrets/ollama_api_key.txt
    
    volumes:
      postgres-data:
      ollama-data:
  4. Adaptar .gitignore: añade secrets/ para que los secretos no terminen en Git.
  5. Iniciar stack: docker compose up -d

Las contraseñas no están en docker-compose.yml, no aparecen en variables de entorno y no se registran en los logs. Cada contenedor lee solo el secreto que necesita.

Rotar secretos

Los secretos deben rotarse regularmente, especialmente en servicios que se usan a largo plazo. La rotación con Docker Compose Secrets funciona así:

  1. Generar nuevo secreto: openssl rand -base64 32 > secrets/postgres_password.txt.new
  2. Guardar secreto anterior: cp secrets/postgres_password.txt secrets/postgres_password.txt.bak
  3. Activar nuevo secreto: mv secrets/postgres_password.txt.new secrets/postgres_password.txt
  4. Reiniciar servicio: docker compose up -d postgres

Importante: en bases de datos, la contraseña debe cambiarse también en la base de datos misma. El secreto en el archivo no es suficiente, la contraseña debe actualizarse en la BD. En PostgreSQL se hace con ALTER USER postgres PASSWORD 'nueva-contraseña';.

Para rotación automatizada vale la pena usar una herramienta como HashiCorp Vault o Infisical que maneje la rotación automáticamente. El artículo Automatizar rotación de secretos lo explica en detalle.

Trampa tipícas con Docker Secrets

  • Secretos en Git: el archivo .env y el directorio secrets no deben ir a Git. Revisa tu .gitignore.
  • Permisos de archivo incorrectos: los archivos de secreto deben tener chmod 600, para que solo el propietario pueda leerlos.
  • Convención *_FILE no soportada: no todas las imágenes soportan leer contraseñas desde archivos. Revisa la documentación de la imagen.
  • Secretos en logs: algunas aplicaciones registran contraseñas cuando las leen desde archivos. Revisa los logs después de iniciar.
  • Sin rotación: quien usa la misma contraseña durante años corre el riesgo de que sea comprometida. La rotación regular es obligatoria.
  • Secretos en variables de entorno como alternativa: si una imagen no soporta *_FILE, las contraseñas suelen terminar en variables de entorno de todos modos. Es mejor buscar otra imagen o construir una propia.
  • Sin backup de secretos: si se pierden los archivos de secreto, los servicios quedan inaccesibles. Guarda los secretos en un lugar seguro.
  • Secretos en la imagen: algunos Dockerfiles contienen contraseñas como variables de entorno. Eso es un riesgo de seguridad masivo, porque cualquiera puede inspeccionar la imagen.

Enlaces y recursos sobre Docker Secrets

Puntos clave:

  • Docker Secrets es más seguro que variables de entorno porque están disponibles como archivo en el contenedor.
  • La convención *_FILE permite que muchas imágenes lean contraseñas desde archivos.
  • Los archivos .env son mejores que texto plano en el archivo Compose, pero no son ideales.
  • Secretos externos con Docker Swarm es el método más seguro.
  • Rotación, backup y .gitignore no son opcionales, son obligatorios.

Preguntas frecuentes: Docker Secrets con Compose

¿Qué son Docker Secrets?

Docker Secrets son datos confidenciales que Docker administra y pone a disposición de los contenedores como archivo bajo /run/secrets/. No aparecen en variables de entorno, no se registran en logs y no figuran en la lista de procesos.

¿Cuál es la diferencia entre .env y Docker Secrets?

Los archivos .env cargan variables como variables de entorno en el contenedor, donde son visibles para todos. Docker Secrets proporciona los datos como archivo, visible solo para ese contenedor específico y que no aparece en variables de entorno.

¿Qué es la convención *_FILE?

Muchas imágenes oficiales soportan leer contraseñas desde archivos. En lugar de POSTGRES_PASSWORD usas POSTGRES_PASSWORD_FILE e indicas la ruta al archivo de secreto. Esto aplica para PostgreSQL, MySQL, Redis, Nextcloud y muchos otros.

¿Necesito Docker Swarm para usar Secrets?

No, Docker Compose soporta secretos sin Swarm. Defines los secretos en la sección secrets y los asignas a los contenedores. Swarm solo se necesita si quieres usar secretos externos almacenados centralmente en el Swarm.

¿Cómo roto Docker Secrets?

Genera un nuevo secreto, reemplaza el archivo y reinicia el servicio. En bases de datos, la contraseña debe actualizarse también en la base de datos misma. Para rotación automatizada vale la pena usar una herramienta como HashiCorp Vault o Infisical.

¿Cómo evito que los secretos terminen en Git?

Añade el directorio secrets y el archivo .env a .gitignore. Verifica con git status que los archivos no sean rastreados. Como alternativa, usa Mozilla SOPS para versionear secretos cifrados en Git.

¿Qué hago si una imagen no soporta *_FILE?

Busca una imagen alternativa que soporte la convención, o construye una propia que lea la contraseña del archivo de secreto y la pase a la aplicación. Si eso no es posible, usa .env como alternativa, pero verifica que la contraseña no aparezca en los logs.

¿Cómo hago backup de Docker Secrets?

Guarda el directorio secrets en un lugar seguro, como un volumen cifrado o un gestor de contraseñas. Si se pierden los archivos de secreto, los servicios quedan inaccesibles. El backup también debe estar protegido.

¿Puedo usar HashiCorp Vault con Docker Compose?

Sí, a través de contenedores init o contenedores sidecar que obtienen los secretos de Vault y los ponen a disposición como archivo. Vale la pena cuando tienes muchos secretos y rotación automatizada.

¿Puedo versionear secretos cifrados en Git?

Sí, con Mozilla SOPS. SOPS cifra los valores de secreto en un archivo YAML o JSON, manteniendo la estructura visible pero protegiendo los valores. Esto permite versionar secretos en Git sin exponerlos en texto plano.

Fuentes y lecturas adicionales

Volver al blog
Share:

Entradas relacionadas