Secrets y configuración en Docker Compose | Nicolás Garzón
no convierte automáticamente un archivo local en un secret manager seguro
Texto
Copiar secret source protegido
→ Compose mount
→ service autorizado
→ archivo dentro del containerLa seguridad depende de cómo se crea, almacena, distribuye, monta, rota y audita el valor.
YAML
Copiar services :
api :
image : my- api
secrets :
- db_password
secrets :
db_password :
file : ./secrets/db_password.txtEl service recibe el valor como archivo en un path de secrets definido por la plataforma, habitualmente bajo /run/secrets/ en entornos Linux compatibles.
Texto
Copiar /run/secrets/db_passwordNo una variable versionada en YAML.
YAML
Copiar services :
api :
secrets : [ db_password]
worker :
secrets : [ db_password, queue_token]
proxy :
secrets : [ tls_private_key] Cada service recibe solo lo necesario. No declares todos los secrets globales en todos los containers.
Esto aplica mínimo privilegio:
proxy no necesita password de database;
database no necesita token de API externa;
frontend no recibe secrets de backend.
Puede mapearse con una identidad diferente:
YAML
Copiar services :
api :
secrets :
- source : database_password
target : db_password
secrets :
database_password :
file : ./secrets/database- password.txtLas opciones exactas de uid/gid/mode pueden depender de plataforma y tipo de source. Verifica el resultado real en el Engine objetivo.
Texto
Copiar ./secrets/db_password.txt
Git;
backups del laptop;
permisos amplios;
malware;
logs del pipeline;
artefactos de CI;
compartir el directorio.
excluir en .gitignore y .dockerignore;
permisos restrictivos;
almacenamiento fuera del repository;
generación desde secret manager;
eliminación segura de archivos temporales;
runners efímeros;
rotación.
.gitignore evita commits accidentales, no protege el archivo local.
Compose puede entregar el archivo al container, pero normalmente no aporta por sí solo:
cifrado centralizado;
rotación automática;
auditoría avanzada;
acceso basado en identidad de workload;
expiración;
versionado seguro;
replicación HA;
revocación inmediata.
Para producción, considera un secret manager del proveedor, Vault, mecanismos del orquestador o una integración equivalente.
Compose puede seguir siendo el consumidor declarativo mientras otra herramienta materializa el valor.
YAML
Copiar services :
api :
environment :
DATABASE_PASSWORD : ${ DATABASE_PASSWORD}
simple;
ampliamente soportado.
aparece en inspect/configuración;
puede filtrarse en dumps;
herramientas pueden imprimir environment;
rotación suele requerir recreate.
Texto
Copiar DATABASE_PASSWORD_FILE=/run/secrets/db_password
no forma parte de metadata normal de environment;
permisos de filesystem;
integración con mecanismos de secrets.
el proceso puede leerlo y filtrarlo;
sigue existiendo como archivo;
la app debe soportarlo;
rotación y reload no son automáticos.
Muchas imágenes oficiales aceptan:
Texto
Copiar POSTGRES_PASSWORD_FILE=/run/secrets/postgres_passwordLa aplicación propia puede implementar la misma convención:
TypeScript
Copiar import { readFileSync } from 'node:fs' ;
const password = process. env. DATABASE_PASSWORD_FILE
? readFileSync ( process. env. DATABASE_PASSWORD_FILE , 'utf8' ) . trimEnd ( )
: process. env. DATABASE_PASSWORD ; Cuidado con trim: certificados, claves o valores donde whitespace importa no deben modificarse indiscriminadamente.
Valida que solo se defina una fuente para evitar ambigüedad.
Valores ordinarios pueden vivir en:
YAML
Copiar services :
api :
environment :
LOG_LEVEL : info
REQUEST_TIMEOUT_MS : "10000" YAML
Copiar services :
api :
volumes :
- type : bind
source : ./config/api.yaml
target : /app/config.yaml
read_only : true La aplicación debe validar ambos formatos. Compose distribuye; la app interpreta.
La especificación Compose puede modelar configs como recursos distintos de secrets según soporte de plataforma.
YAML
Copiar services :
proxy :
configs :
- proxy_config
configs :
proxy_config :
file : ./config/CaddyfileÚtil para contenido no sensible y versionable. Verifica semántica del backend utilizado: Compose local y orquestadores pueden materializar estos recursos de forma diferente.
Compose puede declarar secrets usados por el build mediante capacidades modernas:
YAML
Copiar services :
api :
build :
context : .
secrets :
- npmrc
secrets :
npmrc :
file : ~/.npmrcdocker
Copiar RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ciEse secret existe durante build. No debe aparecer en runtime.
El password de database, en cambio, se entrega cuando el container ejecuta. Mantén ambos canales separados.
Cambiar el source no garantiza que un process running use el nuevo valor.
crear nueva credencial;
permitir temporalmente ambas;
actualizar secret source;
recrear service;
verificar nuevas conexiones;
retirar credencial anterior;
revisar errores y rollback.
Un pool de database puede conservar conexiones existentes. Una app puede leer el archivo una sola vez al startup.
Bash
Copiar docker compose up -d --force-recreate apiPuede ser necesaria para materializar cambios. No la ejecutes sin entender impacto sobre tráfico y stateful dependencies.
En varios replicas, rota gradualmente y mantén compatibilidad temporal.
Bash
Copiar docker compose exec api ls -ln /run/secrets
owner numérico;
mode;
usuario del process;
rootless mapping;
read-only;
si otro process del container puede leerlo.
No hagas el secreto world-readable para resolver un error. Ajusta identidad y mecanismo.
contenido del secret;
connection string completa;
headers de auth;
paths junto a dumps de archivos;
output de env.
Texto
Copiar DATABASE_PASSWORD_FILE is missing or unreadableTexto
Copiar Could not read /run/secrets/db_password: actual-valueYAML
Copiar services :
api :
image : registry.example.com/api@sha256: ...
environment :
NODE_ENV : production
DATABASE_HOST : db
DATABASE_PASSWORD_FILE : /run/secrets/db_password
secrets :
- db_password
configs :
- source : api_config
target : /app/config.yaml
networks : [ data]
db :
image : postgres: 17
environment :
POSTGRES_USER : app
POSTGRES_DB : app
POSTGRES_PASSWORD_FILE : /run/secrets/db_password
secrets :
- db_password
networks : [ data]
secrets :
db_password :
file : /run/secure- material/database- password
configs :
api_config :
file : ./config/api.production.yaml
networks :
data :
internal : true El mismo secret se comparte porque ambos extremos lo necesitan. Ningún otro service lo recibe.
La credencial falla aunque visualmente sea correcta. Define formato y generación.
El archivo Compose es válido, pero up falla. Materializa el source antes y valida permisos.
No publiques la salida. Los file secrets reducen ese riesgo.
API usa valor nuevo y database solo acepta antiguo. Mantén una ventana compatible.
Todo valor enviado al navegador debe considerarse público, aunque venga de un secret manager.
El archivo source queda copiado fuera del sistema previsto. Controla backup y cifrado.
Corrección: source externo y controles de Git.
Corrección: proteger source y host.
Corrección: mínimo privilegio.
Corrección: procedimiento probado.
Corrección: file mount con permisos.
Corrección: canales y scopes distintos.
Compose monta secrets; no reemplaza un vault.
El archivo source sigue siendo la frontera crítica.
File mounts reducen exposición en metadata, pero el proceso aún puede filtrar el valor.
Distribuye cada secret solo al service necesario.
Rotación requiere coordinar consumidores y proveedores.
Build secrets y runtime secrets cumplen funciones diferentes.
Comprueba lo aprendido
Diseña secrets para API, database y proxy con mínimo privilegio.
¿Qué riesgos siguen existiendo al usar file secrets?
Describe una rotación compatible con pools de conexiones.
¿Cuándo usar environment, config y secret file?
¿Por qué Compose local no es un secret manager completo?
Seguridad de contenedores , donde se construye un modelo de amenaza desde la image hasta el host y el proceso comprometido.