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.
Actualizado Publicado 26 min de lectura

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 versionydocker 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
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:
- Los secretos quedan fuera de las capas de imagen porque se inyectan en runtime.
- Configuración de app más limpia porque las apps leen
/run/secrets/...en lugar de valores hardcodeados. - 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.
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)
docker swarm initUn 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:
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:
docker secret create my_db_password db_password.txt
chmod 400 db_password.txtListar los secretos:
docker secret lsComandos 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:
services:
app:
image: myapp:latest
secrets:
- my_db_password
environment:
DB_PASSWORD_FILE: /run/secrets/my_db_password
secrets:
my_db_password:
external: truedocker stack deploy -c compose.yml demoVerifica que el secreto realmente llegó, de fuera hacia dentro:
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: mysupersecretpasswordSi 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
from pathlib import Path
db_password = Path("/run/secrets/my_db_password").read_text(encoding="utf-8").strip()Node.js
const fs = require("node:fs");
const dbPassword = fs.readFileSync("/run/secrets/my_db_password", "utf8").trim();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 deployfalla consecret my_db_password not foundsi 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
echoo 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 conprintf '%s'. - Si tu imagen de contenedor baja privilegios a un usuario no-root, un archivo
600propiedad 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:
docker service update --secret-rm my_db_password demo_app
docker secret rm my_db_passwordLa 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)
mkdir -p secrets
printf '%s' 'change-me-before-use' > secrets/db_password.txt
chmod 600 secrets/db_password.txt.gitignore:
secrets/
*.envPaso 2: declara el secreto en compose.yml
services:
db:
image: postgres:17
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txtNo 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
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 environmentY en el host:
stat -c '%a %U:%G' secrets/db_password.txt
# expect: 600 root:rootCó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 condocker secret createy 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
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:
.envpara 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_passworden lugar desecret1. - 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
.envcomo secretos si contienen contraseñas o tokens.
Rotar secretos
En Swarm, la rotación es crear-nuevo, cambiar, eliminar-viejo:
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_passwordEl 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:
docker service update \
--secret-rm my_db_password_v2 \
--secret-add my_db_password \
demo_appPor 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:
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
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
*_FILEen 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
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:
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 permissionsClave API
services:
worker:
image: myapp:latest
secrets:
- api_key
environment:
API_KEY_FILE: /run/secrets/api_key
secrets:
api_key:
file: ./secrets/api_key.txtSi la app no soporta la convención *_FILE, usa el wrapper de entrypoint de la tabla de problemas.
Certificados TLS
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.keyCon 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
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.pemAplica 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:
-
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.
-
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.
-
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
-
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
-
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.
-
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
*_FILEy mantén los valores fuera dedocker 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í:


