Logotipo de Bitdoze

Secretos en Docker Compose: Qué Funciona y Alternativas Seguras

Los secretos de Docker Compose explicados: qué hacen realmente, cuándo se necesitan los secretos de Swarm, cómo montar archivos de secretos de forma segura y alternativas seguras para producción.

Dragos

Actualizado Publicado 26 min de lectura

Diagrama que compara los montajes de archivos de secretos de Docker Compose con los secretos cifrados de Docker Swarm

Los secretos de Docker Compose son uno de los rincones más incomprendidos del ecosistema Docker: el Compose normal solo monta archivos de secretos, mientras que los secretos reales —cifrados y con alcance por servicio— son una función exclusiva de Swarm. Esta guía muestra cómo inyectar contraseñas de bases de datos, claves de API y claves privadas sin filtrarlas en Git, capas de imagen, logs o variables de entorno.

Dos cosas importan desde el principio:

  • Los “secretos de Docker” con cifrado son una función de Swarm. El Docker Compose normal no cifra los secretos en reposo; monta archivos. El cifrado real y el acceso con alcance por servicio solo ocurren en Docker Swarm.
  • Docker Compose aún puede montar datos secretos como archivos. Eso es lo que hace la clave secrets: en Compose normal. La seguridad depende del filesystem de tu host, tus backups y tu disciplina.

Cubriré ambos caminos: los secretos reales de Swarm y cómo referenciarlos desde Compose (Opción A), luego los archivos de secretos de Compose para entornos locales y autoalojados, además de alternativas para producción (Opción B). Si solo quieres que docker compose up funcione con un archivo de contraseña, salta a la Opción B.

Requisitos previos

  • Docker Engine 27+ con Compose v2 en cualquier host Linux. Confírmalo con docker version y docker compose version.
  • Root o sudo en ese host.
  • Una imagen de prueba a la que conectar los secretos. Postgres funciona de fábrica porque soporta POSTGRES_PASSWORD_FILE.
  • git, para el paso del .gitignore.
  • Solo para la Opción A: una sola máquina es suficiente. Un Swarm de un nodo sirve para aprender esto.

Puedes seguir la guía en un portátil, o en un VPS pequeño de Hetzner Cloud (~4 €/mes) si quieres una máquina desechable que puedas romper y reconstruir.

Los precios de los VPS subieron en general en 2026 — si estás reconsiderando una máquina alquilada, mira qué cambió y cuándo gana un mini PC.

Versiones

La sintaxis aquí apunta a Docker Engine 27+ con Compose v2 (el actual en Ubuntu 24.04). La sintaxis de secrets: es estable desde Compose v2, pero verifica los flags contra docs.docker.com si tu Engine es más antiguo.

Secretos de Docker vs secretos de Docker Compose: cuál es la diferencia

¿Qué son los secretos de Docker (secretos de Swarm)?

Los secretos de Docker son una función de Swarm para gestionar datos sensibles: contraseñas, claves de API, claves privadas TLS, etc. Cuando ejecutas servicios en Swarm, los secretos están:

  • Cifrados en reposo en el log Raft de Swarm en los managers
  • Cifrados en tránsito entre los nodos de Swarm
  • Expuestos a los contenedores como archivos en /run/secrets/<name>
  • Con alcance por servicio: solo los servicios que los solicitan explícitamente
  • Rotables: crea una versión nueva, actualiza el servicio, elimina la antigua

Este es el modelo de seguridad al que se refiere la gente cuando dice «secretos de Docker de verdad».

¿Qué son los «secretos» en Docker Compose (sin Swarm)?

En Docker Compose normal, una entrada secrets: es un bind mount ordenado: el archivo aparece en /run/secrets/<name> dentro del contenedor con una ruta estandarizada. Nada se cifra. Nada se almacena dentro de Docker. Lo que sí obtienes:

  1. Los secretos quedan fuera de las capas de imagen porque se inyectan en runtime.
  2. Configuración de app más limpia porque las apps leen /run/secrets/... en lugar de valores hardcodeados.
  3. Archivos amigables con el control de versiones porque el archivo Compose referencia archivos de secretos, y esos archivos quedan fuera de Git.

Es genuinamente útil. Solo recuerda que el valor solo es tan seguro como el host donde reside.

Diagrama que compara los montajes de archivos de secretos de Docker Compose normal con los secretos cifrados de Docker Swarm

El Compose normal hace un bind mount de un archivo y ahí se queda. Swarm añade un almacén cifrado, distribución cifrada y alcance por servicio.

Selector rápido antes de entrar en detalles:

Enfoque Úsalo cuando
Secretos de Swarm Corres Swarm y quieres cifrado en reposo, alcance por servicio y rotación real
Archivos de secretos de Compose Desarrollo, homelab, autoalojamiento en un solo host; tú proteges el host
Gestor de secretos (Vault, cloud) Múltiples hosts o plataformas, requisitos de cumplimiento, rotación automatizada

Opción A (nivel producción): secretos de Docker Swarm

Los secretos de Docker requieren el modo Swarm. Si no corres Swarm, salta a la Opción B.

1) Inicializar Swarm (una sola vez)

bash
docker swarm init

Un solo nodo es suficiente.

2) Crear un secreto

Evita echo "secret" > file siempre que puedas. Queda en el historial del shell y arrastra un salto de línea final (más sobre esto en los modos de fallo). Lee desde stdin en su lugar:

bash
printf '%s' 'mysupersecretpassword' | docker secret create my_db_password -

El comando imprime el ID del nuevo secreto. Esa es tu confirmación de que existe.

O desde un archivo:

bash
docker secret create my_db_password db_password.txt
chmod 400 db_password.txt

Listar los secretos:

bash
docker secret ls

Comandos habituales

Comando Descripción
docker secret create Crea un nuevo secreto
docker secret ls Lista todos los secretos
docker secret inspect Muestra los metadatos del secreto (no el valor)
docker secret rm <secret> Elimina un secreto

Docker no te permite leer el valor de un secreto a través del CLI. Es intencionado. Para el conjunto completo de comandos, vale la pena tener abierta en otra pestaña la chuleta de comandos esenciales de Docker.

Usar secretos de Swarm desde un archivo Compose

Si despliegas tu stack en Swarm (vía docker stack deploy), referencia un secreto de Swarm externo:

yaml
services:
  app:
    image: myapp:latest
    secrets:
      - my_db_password
    environment:
      DB_PASSWORD_FILE: /run/secrets/my_db_password

secrets:
  my_db_password:
    external: true
bash
docker stack deploy -c compose.yml demo

Verifica que el secreto realmente llegó, de fuera hacia dentro:

bash
docker service ls
# expect: demo_app  replicated  1/1

docker service inspect demo_app --format '{{json .Spec.TaskTemplate.ContainerSpec.Secrets}}'
# expect: [{"SecretName":"my_db_password","File":{...}}]

docker exec "$(docker ps -q --filter name=demo_app)" cat /run/secrets/my_db_password
# expect: mysupersecretpassword

Si docker service inspect imprime null, el servicio nunca recibió el secreto. Corrige el archivo Compose antes de depurar dentro del contenedor.

Leer secretos en los contenedores

Los secretos se montan como archivos en /run/secrets/<secret_name>. Lee el archivo al arrancar en lugar de pasar el valor por una variable de entorno:

Python

python
from pathlib import Path

db_password = Path("/run/secrets/my_db_password").read_text(encoding="utf-8").strip()

Node.js

js
const fs = require("node:fs");

const dbPassword = fs.readFileSync("/run/secrets/my_db_password", "utf8").trim();

Bash

bash
DB_PASSWORD="$(cat /run/secrets/my_db_password)"

Los tres leen el archivo al arranque, lo que mantiene el valor fuera del entorno. Esa es la superficie que exponen docker inspect, los crash dumps y los procesos hijo.

Dónde muerde la Opción A:

  • docker stack deploy falla con secret my_db_password not found si el secreto aún no existe. Los secretos externos deben crearse antes del despliegue; el archivo del stack no los crea por ti.
  • Un salto de línea final de echo o de un editor pasa a formar parte del valor. Los fallos de autenticación con una contraseña «correcta» casi siempre son esto. Regenéralo con printf '%s'.
  • Si tu imagen de contenedor baja privilegios a un usuario no-root, un archivo 600 propiedad de root le queda ilegible. Corrige el propietario o corre el contenedor con un UID coincidente; mira cómo correr contenedores como usuario no-root.

Revertir la Opción A

Quita un secreto de un servicio en ejecución y luego elimínalo:

bash
docker service update --secret-rm my_db_password demo_app
docker secret rm my_db_password

La actualización del servicio dispara un reinicio progresivo de las tareas, así que hazlo en una ventana tranquila. Ten en cuenta que los secretos son inmutables: no hay edición. «Cambiar» un secreto siempre significa crear uno nuevo, apuntar el servicio a él y eliminar el antiguo, que es lo que cubre la sección de rotación más abajo.

Opción B (amigable con Compose): archivos de secretos de Docker Compose

Este es el camino para la mayoría de lectores: desarrollo local y autoalojamiento en un solo host, ya sea un VPS o un mini PC compacto como servidor casero. Si gestionas varios stacks de Compose a mano, gestionar tus stacks de Compose con Dockge encaja muy bien con este flujo de trabajo.

Paso 1: crea un directorio de secretos (y mantenlo fuera de Git)

bash
mkdir -p secrets
printf '%s' 'change-me-before-use' > secrets/db_password.txt
chmod 600 secrets/db_password.txt

.gitignore:

text
secrets/
*.env

Paso 2: declara el secreto en compose.yml

yaml
services:
  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

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

No hace falta la clave version:; Compose v2 la ignora y muestra un aviso si está presente. POSTGRES_PASSWORD_FILE la lee el entrypoint de Postgres en la primera inicialización, así que crea el volumen de datos después de que el secreto exista.

Paso 3: verificar

bash
docker compose config --quiet && echo "compose file OK"
# resolves the file, catches YAML errors; silence is good

docker compose up -d

docker compose exec db ls -l /run/secrets/
# expect: -rw------- ... db_password  (bind mount keeps host permissions)

docker compose exec db env | grep change-me
# expect: no output, the value never entered the environment

Y en el host:

bash
stat -c '%a %U:%G' secrets/db_password.txt
# expect: 600 root:root

Cómo se ve el fallo: que docker compose config falle con un error «secret not found» significa que escribiste external: true en lugar de file:. Un /run/secrets/ vacío dentro del contenedor significa que ese servicio nunca declaró el secreto.

Los archivos de secretos no son solo para contraseñas. Las claves privadas TLS siguen el mismo patrón de montaje, y puedes verlo de principio a fin en la configuración de certificados wildcard de Traefik con Let’s Encrypt y Cloudflare.

Llevar esto a producción

El mismo archivo compose se despliega en un PaaS autoalojado con un flujo de despliegue real, gestión de env y proxy encima. Si esa es la dirección que tomas, aquí está cómo desplegar una app Docker Compose en Dokploy.

Secretos externos vs basados en archivo en Docker Compose

Verás dos patrones:

  • Basados en archivo (file: ...): «monta este archivo del host en el contenedor como /run/secrets/<name>». Es lo que la mayoría usa en Docker Compose normal.
  • Externos (external: true): «el secreto ya existe en la plataforma». Relevante para los secretos de Swarm, creados con docker secret create y compartidos entre servicios y stacks, gestionados con independencia del archivo Compose y rotables sin tocar el archivo.
file: (Compose normal) external: true (Swarm)
Dónde vive el valor Un archivo en el host El almacén cifrado de Swarm
Cifrado en reposo No Sí
Funciona con docker compose up Sí No: «secret not found»
Funciona con docker stack deploy Sí (montado tal cual) Sí (el uso previsto)
Rotación Sobrescribe el archivo, recrea los contenedores Inmutable: añade v2, actualiza el servicio, elimina v1

Usa los basados en archivo para desarrollo, pruebas y autoalojamiento en un solo host. Usa secretos externos de Swarm en despliegues Swarm, sobre todo cuando un secreto lo comparten varios servicios.

Secretos de Docker vs variables de entorno en Compose

No pongas valores secretos en variables de entorno

Algunas guías antiguas muestran secretos definidos directamente en el archivo Compose o traídos desde variables de entorno. Salta ese patrón. Los valores pasados por environment: son legibles en docker inspect, acaban en crash dumps y todos los procesos hijo que la app lance los heredan.

Si aun así necesitas variables de entorno, mantén los roles separados:

  • .env para configuración no sensible: puertos, tags de imagen, feature flags
  • un gestor de secretos de verdad para valores sensibles en producción (Vault o un proveedor cloud)
  • genera el archivo de secreto durante el despliegue y móntalo (nunca lo commitees)

Para la mecánica completa de la inyección, mira cómo funcionan ARG y ENV en Docker y Docker Compose.

Buenas prácticas para los secretos de Docker Compose

El objetivo central nunca cambia: mantén los secretos fuera de las imágenes, de Git y de los logs, y minimiza el radio de impacto cuando algo se filtra.

Convenciones de nombres

  • Nombres descriptivos: prod_db_password en lugar de secret1.
  • Prefijos consistentes: prod_ para producción, dev_ para desarrollo.
  • Nada de información sensible en los propios nombres.

Control de versiones

  • Nunca commitees valores secretos.
  • Añade el directorio de secretos a .gitignore (secrets/).
  • Mantén un directorio secrets.example/ con archivos de marcador de posición, o documenta los nombres de archivo requeridos en un README.
  • Trata los archivos .env como secretos si contienen contraseñas o tokens.

Rotar secretos

En Swarm, la rotación es crear-nuevo, cambiar, eliminar-viejo:

bash
printf '%s' 'new-password' | docker secret create my_db_password_v2 -

docker service update \
  --secret-rm my_db_password \
  --secret-add source=my_db_password_v2,target=my_db_password \
  demo_app

# after the rollout verifies:
docker secret rm my_db_password

El truco de source=...,target=... mantiene estable la ruta dentro del contenedor para que la config de la app no cambie.

Si el despliegue falla, revierte mientras el secreto antiguo aún existe:

bash
docker service update \
  --secret-rm my_db_password_v2 \
  --secret-add my_db_password \
  demo_app

Por eso eliminas el secreto antiguo al final, nunca primero.

En Compose normal, la rotación es: sobrescribe el archivo y luego docker compose up -d --force-recreate db. Compose monta el archivo una vez al crear el contenedor y no lo vigila, así que sin recrearlo el contenedor sigue sirviendo el valor antiguo.

Y rota la credencial en el origen (el rol de base de datos, la clave de API del cloud), no solo dentro de Docker. Rotar el montaje pero no la credencial no rota nada que importe.

Blindar el host

Con Compose normal, el host es el modelo de seguridad:

bash
sudo chown root:root secrets
sudo chmod 700 secrets
sudo chown root:root secrets/*
sudo chmod 600 secrets/*

Si un contenedor corre con un UID no-root, haz chown del archivo concreto a ese UID o chgrp a un grupo al que pertenezca ese UID.

Los backups necesitan el mismo tratamiento: tu directorio de secretos acabará dentro de los backups del host, así que cifra los backups (restic con una clave age, o almacenamiento compatible con S3 con cifrado en servidor y credenciales restringidas) en lugar de enviar archivos de secretos en texto plano junto a tus dumps de base de datos.

Para un servidor expuesto a internet, empieza con cómo proteger un servidor Docker expuesto a internet, y añade bloqueo automatizado con CrowdSec para proteger tu VPS.

Un secreto montado no protege un puerto publicado

Un servicio con secretos publicado en 0.0.0.0 está expuesto por muy bien que montes el secreto. Docker publica puertos a través de iptables y puede saltarse las reglas de UFW; lee por qué Docker se salta las reglas del firewall UFW antes de confiar en un firewall que no has verificado.

Hábitos adicionales que importan

  • Declara los secretos por servicio. Solo los servicios que necesitan un secreto deberían verlo.
  • Prefiere el consumo por archivo: usa variables *_FILE en lugar de meter valores en el entorno.
  • No imprimas secretos. Evita loguear objetos de configuración que incluyan rutas o valores de secretos.
  • Para producción seria entre varios hosts, pasa a un gestor de secretos de verdad, cubierto en las alternativas de abajo.

Solución de problemas con los secretos de Docker Compose

Síntoma / error Causa Solución
secret my_db_password not found en docker compose up external: true solo se resuelve bajo Swarm / docker stack deploy En Compose normal usa file: con una ruta, o crea primero el secreto en Swarm
La autenticación de la app falla aunque la contraseña parece correcta Un salto de línea final de echo o de un editor pasó a ser parte del valor Regenéralo con printf '%s'; comprueba el último byte con xxd secrets/db_password.txt (no debe terminar en 0a). Postgres recorta los saltos de línea finales; la mayoría de las demás imágenes no
permission denied al leer /run/secrets/<name> El contenedor corre como no-root y el bind mount mantiene propiedad de root Haz chown del archivo del host al UID del contenedor, o define user: en compose (mira los modos de fallo en la Opción A)
Valor secreto horneado en la imagen Intentaste hacerle COPY o pasarlo como ARG de build Los secretos son solo de runtime por diseño; usa los montajes --secret de BuildKit para los builds, que no persisten en las capas
Valor visible en la salida de docker inspect o docker compose config Se pasó vía environment: Muévelo a secrets: más una variable *_FILE
La app no soporta *_FILE La app solo lee variables de entorno planas Un pequeño wrapper en el entrypoint: export DB_PASSWORD="$(cat /run/secrets/db_password)" y luego exec "$@". Compromiso: el valor vuelve al entorno de ese árbol de procesos
Editaste el archivo del host y el contenedor sigue mostrando el valor antiguo Compose monta el archivo una vez al crear el contenedor; los editores reemplazan el archivo (nuevo inodo), rompiendo el bind mount docker compose up -d --force-recreate <service>

Ejemplos de secretos de Docker Compose

Cuatro casos habituales. La pestaña de Postgres es el camino completo sin tropiezos; las demás son fragmentos listos para insertar. Todas usan file: porque es lo que soporta el Compose normal. En Swarm, cambia file: por external: true y crea primero el secreto con el CLI.

Postgres

yaml
services:
  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
    volumes:
      - pgdata:/var/lib/postgresql/data

  app:
    image: myapp:latest
    secrets:
      - db_password
    environment:
      DB_PASSWORD_FILE: /run/secrets/db_password

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

volumes:
  pgdata:

Generar y verificar:

bash
printf '%s' "$(openssl rand -base64 24)" > secrets/db_password.txt
chmod 600 secrets/db_password.txt
docker compose up -d
docker compose logs db | grep -m1 "database system is ready"
# expect: ... database system is ready to accept connections

docker compose exec app ls -l /run/secrets/
# expect: db_password listed with restrictive permissions

Clave API

yaml
services:
  worker:
    image: myapp:latest
    secrets:
      - api_key
    environment:
      API_KEY_FILE: /run/secrets/api_key

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

Si la app no soporta la convención *_FILE, usa el wrapper de entrypoint de la tabla de problemas.

Certificados TLS

yaml
services:
  web:
    image: nginx:1.27
    secrets:
      - source: site_certificate
        target: site.crt
      - source: site_key
        target: site.key
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro

secrets:
  site_certificate:
    file: ./certs/site.crt
  site_key:
    file: ./certs/site.key

Con target:, los archivos aparecen en /run/secrets/site.crt y /run/secrets/site.key. Apunta ahí las directivas ssl_certificate de tu nginx.conf. El proceso maestro de Nginx corre como root, así que una clave 600 es legible. Es el mismo patrón que la guía de certificados wildcard de Traefik (enlazada en la Opción B) recorre de principio a fin.

Claves JWT

yaml
services:
  auth:
    image: myapp:latest
    secrets:
      - jwt_private_key
      - jwt_public_key
    environment:
      JWT_PRIVATE_KEY_FILE: /run/secrets/jwt_private_key
      JWT_PUBLIC_KEY_FILE: /run/secrets/jwt_public_key

secrets:
  jwt_private_key:
    file: ./secrets/jwt_private_key.pem
  jwt_public_key:
    file: ./secrets/jwt_public_key.pem

Aplica chmod 600 a la clave privada. La clave pública puede quedarse en 644; los servicios a menudo necesitan verificar tokens sin poseer la mitad privada.

Limitaciones de los secretos de Docker Compose y alternativas seguras

El requisito del modo Swarm

Los secretos de Docker de verdad requieren Swarm. El Compose normal solo te da montajes de archivos: sin almacén cifrado, sin alcance por servicio impuesto por un orquestador. Para Kubernetes, usa Kubernetes Secrets (idealmente con cifrado en reposo activado e integración con un gestor de secretos externo).

Con eso en mente, aquí están las alternativas, con el coste operativo honesto de cada una:

  1. Archivos de secretos montados vía Compose

    • Pros: simple, mantiene los secretos fuera de las capas de imagen, funciona dondequiera que corra Compose
    • Contras: la seguridad depende del filesystem del host, los backups y la disciplina operativa
    • Es el default sensato para un solo host.
  2. Variables de entorno (usar con cautela)

    • Pros: simples, soportadas universalmente
    • Contras: fáciles de filtrar vía docker inspect, crash dumps, logs o procesos hijo
    • Evítalas para valores muy sensibles cuando existe una opción basada en archivos.
  3. Gestores de secretos en la nube

    • AWS Secrets Manager, SSM Parameter Store, Google Secret Manager, Azure Key Vault
    • Pros: acceso basado en IAM, logs de auditoría, rotación gestionada
    • Contras: acoplamiento a la plataforma; el precio es por secreto más por consulta, aunque los tiers gratuitos suelen cubrir los secretos de un homelab
  4. HashiCorp Vault

    • Pros: agnóstico de plataforma, secretos dinámicos, auditabilidad
    • Contras: un servicio con estado más que respaldar, actualizar y desellar. Exagerado por debajo de unos cinco servicios o sin un requisito real de cumplimiento
  5. Kubernetes Secrets (más operadores de secretos externos)

    • Pros: de primera clase en el ecosistema k8s, se integran con almacenes de secretos
    • Contras: requiere k8s; los Secrets básicos se almacenan en etcd sin cifrar salvo que actives el cifrado en reposo
    • Combínalos con el External Secrets Operator para sincronizar desde un gestor de secretos en la nube.
  6. Docker Config

    • La misma maquinaria de Swarm para configuración no sensible. Úsalo junto a los secretos para mantener config y credenciales en formas consistentes

Mi ranking honesto para un autoalojador en solitario: primero archivos de secretos de Compose, segundo un PaaS autoalojado, Vault o un gestor cloud solo cuando un requisito real lo exige. Si gestionar archivos de secretos a mano te suena a tarea pesada, el punto medio es un PaaS autoalojado: comparativa de plataformas PaaS autoalojadas cubre las opciones, y guardan env y secretos por app por ti manteniendo tus archivos compose.

FAQ

¿Los secretos de Docker Compose están cifrados?

No. En Compose normal, secrets: es un montaje de archivo y no añade cifrado. El cifrado en reposo en el log Raft y la distribución cifrada entre nodos son funciones exclusivas de Docker Swarm. Con Compose normal, tu modelo de seguridad es el filesystem del host: permisos, cifrado de disco y backups.

¿Funcionan los secretos de Compose sin Swarm?

Sí, como montajes de archivos planos. Declara el secreto con file: en tu archivo compose y la app lo lee en /run/secrets/<name>. La variante external: true es la que requiere Swarm.

¿Son los secretos de Docker mejores que las variables de entorno?

En general sí para valores sensibles. Leer un archivo al arranque mantiene el valor fuera de la salida de docker inspect, fuera de los crash dumps y fuera del entorno que heredan los procesos hijo. No es perfecto (un dump de memoria aún puede filtrarlo), pero cierra las rutas de fuga más comunes. Queda algo de superficie de fuga por diseño cuando una app solo acepta env vars; usa un wrapper de entrypoint como último recurso.

¿Dónde se almacenan los secretos de Compose en el host?

Exactamente donde apunta tu file:, por ejemplo ./secrets/db_password.txt. Compose hace bind-mount del archivo dentro del contenedor en el momento de la creación y no copia nada en la imagen ni en el almacenamiento propio de Docker. Borra el archivo y el secreto desaparece para los contenedores futuros. En Swarm, los valores viven en el log Raft cifrado de los nodos manager.

¿Cómo roto un secreto sin downtime?

En Swarm: crea un secreto nuevo versionado, docker service update para apuntar el servicio a él, y elimina el secreto antiguo después de verificar el despliegue. Los secretos son inmutables, así que no hay edición en el lugar. En Compose normal: sobrescribe el archivo y luego docker compose up -d --force-recreate. Los comandos de rotación y el camino de reversión están en la sección de buenas prácticas de arriba.

¿Puedo usar secretos durante docker build?

No con secrets:. Los secretos de Compose son construcciones de runtime; cualquier cosa que hornees en una capa se queda en la imagen para siempre, incluso en capas que creías haber eliminado. Para los builds, usa los montajes de secretos de BuildKit: docker build --secret id=mytoken,src=./secrets/token.txt con RUN --mount=type=secret,id=mytoken en el Dockerfile. Se exponen solo en tiempo de build y no persisten en las capas.

Conclusión: ¿qué enfoque de secretos de Docker deberías usar?

La regla de decisión que yo aplicaría:

  • ¿Corres Swarm multi-nodo, o quieres cifrado y alcance gestionados por Docker? Usa secretos de Swarm (Opción A).
  • ¿Compose normal en un solo host? Usa archivos de secretos (Opción B), blinda el host y cifra los backups.
  • ¿Requisitos de cumplimiento, múltiples plataformas o Kubernetes? Un gestor de secretos de verdad, o k8s Secrets con cifrado en reposo.
  • El cifrado es solo de Swarm. Los secretos de Compose normal son montajes de archivos, nada más.
  • Los secretos y las variables de entorno son herramientas distintas. Prefiere lecturas *_FILE y mantén los valores fuera de docker inspect.
  • Verifica la entrega con cat /run/secrets/… dentro del contenedor en lugar de asumir que el montaje funcionó.
  • En Compose normal, el host es el perímetro: permisos de archivos, backups cifrados, firewall verificado.

Elijas el camino que elijas, prefiere aplicaciones que lean desde /run/secrets/... y mantén los valores secretos fuera de las imágenes, de Git y de los logs. Si el siguiente paso en tu lista es el hardening del host, empieza aquí:

Protege tu servidor Docker ahora