Curso
He visto infinidad de imágenes de Docker expuestas por accidente con claves de API, contraseñas de bases de datos y tokens de autenticación incrustados en sus capas. Estas brechas de seguridad suelen producirse durante el proceso de build, cuando los desarrolladores necesitan acceso temporal a recursos privados pero, sin querer, acaban dejando credenciales en la imagen final.
El problema es que los enfoques tradicionales para gestionar credenciales durante los builds, como las variables de entorno o los argumentos de compilación, no están pensados para un uso efímero. Dejan rastros permanentes en los metadatos o en las capas de la imagen, creando vulnerabilidades que persisten mucho después de terminar el build. Surge así un dilema: ¿cómo te autenticas frente a recursos privados durante el build sin comprometer la seguridad?
Los Docker build secrets resuelven este problema crítico al permitir usar datos sensibles durante el build de la imagen sin dejar rastro en el artefacto final.
En este tutorial, te guiaré para implementar secretos de compilación de forma eficaz, desde los conceptos básicos hasta la integración avanzada en CI/CD, para que tus builds de contenedores se mantengan seguros.
Si estás empezando con Docker, te recomiendo algunos de nuestros cursos, como Introduction to Docker, Containerization and Virtualization with Docker and Kubernetes o Intermediate Docker.
¿Qué son los Docker build secrets?
Empecemos entendiendo qué hace diferentes a los build secrets frente a otros enfoques de gestión de credenciales. Los Docker build secrets son fragmentos efímeros de información sensible que están disponibles durante el proceso de build, pero nunca se almacenan en las capas ni en el sistema de archivos de la imagen. Solo existen en memoria durante pasos específicos del build y desaparecen al completarlos.
La necesidad de los build secrets surge de los flujos de trabajo modernos de desarrollo de aplicaciones.
A menudo necesitas autenticarte contra repositorios privados de paquetes, clonar repos de Git privados, descargar software con licencia o acceder a APIs internas durante los builds.
Sin build secrets, los desarrolladores recurren a atajos peligrosos, como hardcodear credenciales en Dockerfiles, pasar secretos como argumentos de build (que persisten en los metadatos de la imagen) o crear imágenes base demasiado permisivas con credenciales incrustadas.
Los riesgos de manejar mal los secretos son considerables. Las credenciales expuestas pueden dar lugar a accesos no autorizados a sistemas en producción, fugas de datos, incumplimientos normativos y daños reputacionales. Casos comunes de filtrado incluyen claves de API para gestores de paquetes, claves SSH para operaciones con Git, tokens de autenticación para servicios internos y credenciales de bases de datos para migraciones en tiempo de build.
Docker BuildKit: la base de los build secrets seguros
Antes de entrar en la implementación, necesitas entender BuildKit, el motor de build moderno que hace posibles los secretos seguros. BuildKit es el builder de nueva generación de Docker que sustituyó al motor clásico y ofrece mejoras importantes en rendimiento, caché y seguridad.
BuildKit usa un modelo de ejecución basado en grafos que rastrea dependencias entre pasos del build. Esta arquitectura permite montar secretos como sistemas de archivos temporales que solo existen durante instrucciones RUN concretas, garantizando que nunca formen parte de las capas de la imagen.
A diferencia del build clásico de Docker, donde todo el contexto de build puede entrar en la caché de capas, BuildKit trata los secretos como recursos especiales que evitan por completo la caché.
Activar BuildKit es sencillo. En Docker 23.0 y posteriores, BuildKit es el builder por defecto. En versiones anteriores, establece la variable de entorno DOCKER_BUILDKIT=1 antes de ejecutar los comandos de build:
export DOCKER_BUILDKIT=1
docker build -t myapp .
Como alternativa, actívalo de forma permanente configurando el daemon de Docker o usando Docker Buildx, que siempre utiliza BuildKit. La diferencia clave entre los builds clásicos y los habilitados con BuildKit es que, en los clásicos, los secretos pueden persistir en capas intermedias si no se gestionan con cuidado, mientras que BuildKit garantiza que los secretos son efímeros y nunca se escriben en disco como parte de la imagen.
Con la base segura de BuildKit, veamos los diferentes tipos de secretos que habilita y cómo implementar cada uno con eficacia.
Tipos e implementación de Docker build secrets
BuildKit admite tres mecanismos principales para manejar secretos durante los builds, cada uno diseñado para casos de uso concretos. Entender cuándo usar cada tipo te garantiza seguridad y funcionalidad óptimas.
Montajes de secretos: datos sensibles de uso general
Los montajes de secretos ofrecen el enfoque más flexible para manejar datos sensibles durante los builds. Permiten montar secretos como archivos en rutas específicas durante instrucciones RUN, poniendo credenciales a disposición de los comandos sin que persistan en las capas.
El proceso tiene dos pasos: pasar el secreto al comando de build y montarlo en el Dockerfile. Primero, crea un archivo de secreto local o usa una variable de entorno. Luego, haz referencia a él durante el build:
docker build --secret id=api_key,src=./api_key.txt -t myapp .
En tu Dockerfile, monta el secreto en la instrucción RUN que lo necesite:
RUN --mount=type=secret,id=api_key \
API_KEY=$(cat /run/secrets/api_key) && \
curl -H "Authorization: Bearer $API_KEY" https://api.example.com/package > /app/data.json
De forma predeterminada, los secretos se montan en /run/secrets/<id>, pero puedes indicar destinos personalizados con el parámetro target.
Las buenas prácticas incluyen montar secretos solo en las instrucciones RUN que los necesiten, no copiar nunca secretos al sistema de archivos de la imagen y usar builds multietapa para separar las fases que requieren secretos de la imagen final.
La fuente puede ser una ruta de archivo, o puedes usar env para pasar secretos desde variables de entorno: --secret id=token,env=API_TOKEN.
Para montar un secreto como variable de entorno en lugar de archivo, usa la opción env:
RUN --mount=type=secret,id=db_user,env=DB_USER \
--mount=type=secret,id=db_password,env=DB_PASSWORD \
./setup-database.sh
Puedes combinar las opciones target y env para montar un secreto a la vez como archivo y como variable de entorno.
Las buenas prácticas incluyen montar secretos solo en RUN específicas que los necesiten, no copiarlos nunca al sistema de archivos de la imagen y usar builds multietapa para separar las fases que requieren secretos de las imágenes finales.
Montajes SSH: acceso seguro a recursos privados
Los montajes SSH se ocupan específicamente de la autenticación basada en SSH, principalmente para acceder a repositorios Git privados durante los builds. En lugar de copiar claves SSH a la imagen (una pesadilla de seguridad), los montajes SSH proporcionan acceso temporal a tu agente SSH durante el build.
Para usarlos, asegúrate de que tu agente SSH se esté ejecutando localmente con las claves cargadas. Luego, referencia el montaje SSH en tu Dockerfile:
RUN --mount=type=ssh \
git clone git@github.com:myorg/private-repo.git /app
Compila la imagen con el reenvío SSH habilitado:
docker build --ssh default -t myapp .
Para varios hosts con claves distintas, puedes especificar montajes SSH con nombre:
RUN --mount=type=ssh,id=github \
git clone git@github.com:myorg/repo.git
Luego proporciona claves específicas durante el build:
docker build --ssh github=$HOME/.ssh/github_key -t myapp .
Verás que este enfoque mantiene la seguridad sin exponer las claves privadas en la imagen y permite el acceso autenticado a repositorios privados durante el proceso de build.
Autenticación de Git para contextos remotos
Cuando tu build de Docker necesita acceder a repositorios Git privados, ya sea como el propio contexto de build o al obtener dependencias, necesitas una forma de autenticarte sin incrustar credenciales. Es especialmente común al construir desde una URL de repo privado o al usar ADD para traer código privado.
BuildKit proporciona dos secretos predefinidos para autenticación de Git: GIT_AUTH_TOKEN y GIT_AUTH_HEADER. Son secretos "previos" que autentican el builder antes de ejecutar cualquier instrucción del Dockerfile, asegurando la descarga inicial del repositorio.
El patrón más habitual usa GIT_AUTH_TOKEN para autenticación HTTPS basada en token:
GIT_AUTH_TOKEN=$(cat ~/.github-token) docker build \
--secret id=GIT_AUTH_TOKEN \
https://github.com/myorg/private-repo.git
Funciona a la perfección con instrucciones ADD que obtienen repos privados:
FROM alpine
ADD https://github.com/myorg/private-configs.git /configs
En entornos efímeros de CI/CD, inyecta tokens desde el almacén de secretos de tu plataforma:
- name: Build from private repo
env:
GIT_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
docker build --secret id=GIT_AUTH_TOKEN https://github.com/myorg/app.git
El secreto GIT_AUTH_HEADER ofrece una alternativa para esquemas de autenticación personalizados cuando el token estándar no es suficiente.
Cómo usar Docker build secrets
Ahora que hemos visto los tipos de secretos, veamos cómo implementarlos eficazmente en escenarios reales.
Creación y estructuración de secretos para el build
Preparar bien los secretos es clave para la seguridad. Guarda los secretos en archivos fuera de tu contexto de build de Docker, añádelos a .gitignore y .dockerignore y usa permisos restrictivos (600 o 400).
Para múltiples secretos, crea un directorio dedicado:
mkdir -p .secrets
echo "my-api-key" > .secrets/api_key
chmod 600 .secrets/*
Luego, haz referencia a ellos durante los builds:
docker build \
--secret id=api_key,src=.secrets/api_key \
--secret id=db_password,src=.secrets/db_password \
-t myapp .
Para secretos basados en variables de entorno, muy comunes en CI/CD:
docker build \
--secret id=api_key,env=API_KEY \
--secret id=db_pass,env=DB_PASSWORD \
-t myapp .
Integración con builds multietapa
Los builds multietapa son muy potentes combinados con secretos. Usa secretos en etapas tempranas para obtener dependencias y copia solo los artefactos necesarios a la etapa final:
# Etapa de build: aquí se usan secretos
FROM python:3.11 AS builder
WORKDIR /app
COPY requirements.txt .
RUN --mount=type=secret,id=api_key \
API_KEY=$(cat /run/secrets/api_key) && \
curl -H "Authorization: Bearer $API_KEY" https://api.company.com/data.json -o data.json && \
pip install -r requirements.txt
# Etapa final: sin secretos presentes
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /app/data.json ./data.json
COPY . .
CMD ["python", "app.py"]
Así garantizas que los secretos solo existen durante la etapa de build y nunca aparecen en la imagen final.
Los builds multietapa resuelven con elegancia un único secreto, pero en aplicaciones reales suele haber más complejidad.
Veamos cómo gestionar escenarios con múltiples secretos o requisitos de build más intrincados.
Gestión de múltiples secretos y escenarios complejos
Los builds complejos suelen requerir varios secretos dentro de la misma instrucción RUN. BuildKit permite montar múltiples secretos a la vez:
RUN --mount=type=secret,id=api_key \
--mount=type=secret,id=db_password \
API_KEY=$(cat /run/secrets/api_key) && \
DB_PASS=$(cat /run/secrets/db_password) && \
./configure.sh
Si varias instrucciones necesitan los mismos secretos, combina comandos en una sola RUN para minimizar montajes de secretos manteniendo límites de seguridad.
Buenas prácticas de seguridad con Docker build secrets
Implementar build secrets correctamente exige seguir prácticas de seguridad contrastadas. Te comparto los patrones más eficaces que he visto para mantener la seguridad durante todo el proceso de build.
Prevenir la exposición y fuga de secretos
Tras construir una imagen, verifica que no haya fugas inspeccionando las capas:
docker history myapp:latest
docker save myapp:latest | tar -x
Examina las capas extraídas en busca de datos sensibles. Además, distingue entre secretos de build (temporales, usados durante el build) y secretos de tiempo de ejecución (necesarios cuando los contenedores se ejecutan). No uses secretos de build para credenciales de runtime. Emplea Docker secrets, secretos de Kubernetes o variables de entorno inyectadas en tiempo de ejecución.
Añade siempre los archivos de secretos a .gitignore:
# .gitignore
.secrets/
*.key
Y a .dockerignore para evitar incluirlos por accidente en los contextos de build:
# .dockerignore
.secrets/
*.key
.env
Gestión de secretos en entornos CI/CD
Las plataformas de CI/CD ofrecen gestión nativa de secretos que se integra sin esfuerzo con los Docker build secrets. En GitHub Actions:
- name: Build Docker image
env:
API_KEY: ${{ secrets.API_KEY }}
run: |
docker build \
--secret id=api_key,env=API_KEY \
-t myapp .
El principio clave es aprovechar los almacenes de secretos de la propia plataforma en lugar de guardar secretos en los repos. Los secretos de CI/CD se inyectan como variables de entorno, que BuildKit puede consumir directamente mediante el tipo de fuente env.
Permisos de secretos y control de acceso
Si compilas como usuario no root, asegúrate de que los archivos de secretos tengan permisos de lectura adecuados. Si tu Dockerfile usa USER para cambiar a un usuario no root, monta los secretos en ubicaciones accesibles para ese usuario:
FROM python:3.11-slim
RUN useradd -m appuser
USER appuser
RUN --mount=type=secret,id=token,uid=1000 \
cat /run/secrets/token > /dev/null
Para un mayor cumplimiento, implementa rotación de secretos. Usa tokens de corta duración cuando sea posible, automatiza la rotación en las pipelines de CI/CD y mantén registros de auditoría del uso de secretos.
Considera secretos con fecha de caducidad y procesos de renovación automatizados para minimizar ventanas de exposición.
Hasta ahora nos hemos centrado en builds de un único contenedor, pero las aplicaciones modernas suelen constar de varios servicios. Veamos cómo Docker Compose amplía las capacidades de secretos a arquitecturas multiservicio.
Integración de build secrets con Docker Compose
Docker Compose simplifica la gestión de secretos de build en aplicaciones con múltiples servicios. En tu docker-compose.yml, define secretos a nivel superior y haz referencia a ellos en la configuración de build de cada servicio:
services:
app:
build:
context: .
secrets:
- api_key
- db_password
secrets:
api_key:
file: ./.secrets/api_key
db_password:
environment: DB_PASSWORD
Luego, en tu Dockerfile, monta los secretos como de costumbre:
RUN --mount=type=secret,id=api_key \
--mount=type=secret,id=db_password \
./setup.sh
Compila con Compose:
docker-compose build
Este patrón escala bien en aplicaciones con múltiples servicios que requieren distintos secretos, manteniendo una gestión centralizada y respetando los límites de seguridad entre servicios.
Al implementar build secrets en tus proyectos, es normal encontrarte con problemas. Abordemos los desafíos más comunes y sus soluciones para ayudarte a diagnosticar con eficacia.
Problemas habituales y cómo solucionarlos
Incluso con una implementación correcta, surgen retos. Estos son los problemas más comunes y cómo resolverlos.
Errores de sintaxis y declaraciones de montaje
La sintaxis de --mount es estricta. Errores comunes: faltar comas entre parámetros, nombres de parámetros incorrectos y tipos de montaje erróneos. La sintaxis correcta es:
RUN --mount=type=secret,id=secret_name,target=/path \
command
Si el build falla con "secret not found", verifica que BuildKit esté habilitado y que el ID del Dockerfile coincida con el --secret id del comando de build.
Secretos no disponibles o no encontrados
Si los secretos no son accesibles, comprueba que el archivo de origen existe y se puede leer:
cat .secrets/api_key
docker build --secret id=api_key,src=.secrets/api_key .
Para variables de entorno, confirma que estén definidas:
echo $API_KEY
docker build --secret id=api_key,env=API_KEY .
Confusión entre variables de entorno y archivos
Con build secrets, por defecto los secretos se montan como archivos en /run/secrets/<id>. Para usarlos como variables de entorno, lee el contenido del archivo:
RUN --mount=type=secret,id=token \
export TOKEN=$(cat /run/secrets/token) && \
curl -H "Authorization: Bearer $TOKEN" https://api.example.com
No uses argumentos de build (ARG) para secretos, ya que persisten en los metadatos de la imagen.
Persistencia y problemas con la caché de capas
Los secretos no persisten entre instrucciones RUN por diseño. Si varias RUN necesitan el mismo secreto, combina los comandos o vuelve a montar el secreto:
RUN --mount=type=secret,id=token \
command1
RUN --mount=type=secret,id=token \
command2
BuildKit garantiza que los secretos nunca entren en la caché de capas.
Una vez domines lo fundamental y el troubleshooting más común, puede que te encuentres con escenarios que requieran enfoques más sofisticados. Veamos usos avanzados y casos límite que van más allá de las implementaciones estándar.
Usos avanzados de Docker build secrets
Para despliegues complejos, tendrás que tener en cuenta consideraciones adicionales más allá de la implementación básica.
Secretos en pipelines CI/CD complejas
Las pipelines CI/CD multietapa suelen requerir secretos en diferentes fases. Implementa secretos específicos por etapa en lugar de compartir credenciales. Usa las funciones de la plataforma para delimitar el alcance de los secretos, limitando qué etapas pueden acceder a cuáles. Automatiza la limpieza de secretos tras los builds para minimizar la ventana de exposición.
Secretos con builders no Docker
Builders alternativos como Buildah y Kaniko tienen soporte desigual para la sintaxis de secretos de BuildKit. Buildah admite un montaje similar mediante --secret flags. Kaniko, pensado para Kubernetes, usa otros mecanismos, normalmente secretos de Kubernetes montados como volúmenes. Si usas builders no Docker, consulta su documentación específica, ya que las implementaciones difieren bastante.
Secretos y cumplimiento normativo
Los build secrets se alinean con marcos de cumplimiento al proporcionar acceso a credenciales efímeras y auditables.
Para el RGPD, asegúrate de que los secretos no filtren datos personales a las capas. Los requisitos SOC2 se benefician de tener trazabilidad del uso de secretos: registra cuándo y quién los utiliza. Mantén registros de acceso a secretos para auditorías de cumplimiento.
Rotación y actualización de secretos
Establece procesos para rotar secretos sin interrumpir los builds. Usa archivos de secretos versionados o convenciones de nombres de variables de entorno que faciliten el cambio entre versiones.
Automatiza la rotación en las pipelines de CI/CD, refrescando los secretos desde almacenes centrales. Para tokens con caducidad, monitoriza su expiración y automatiza la renovación.
Conclusión: buenas prácticas y recomendaciones
Los Docker build secrets suponen una mejora fundamental de seguridad para el desarrollo de aplicaciones en contenedores. A lo largo de este tutorial, hemos visto cómo implementar secretos de forma segura, desde montajes básicos hasta integración compleja en CI/CD.
Las claves son claras: usa siempre los mecanismos de montaje de secretos de BuildKit en lugar de argumentos de build o credenciales hardcodeadas; aplica builds multietapa para aislar las fases que usan secretos de las imágenes finales; aprovecha la gestión de secretos de tu plataforma de CI/CD para flujos automatizados; y audita regularmente las imágenes para verificar que los secretos no han acabado en las capas.
Para las organizaciones que adopten estas prácticas, empieza con una política de gestión de secretos que defina qué secretos requieren acceso en tiempo de build, establece calendarios de rotación automatizados, implanta pruebas exhaustivas para verificar que los secretos no persisten en las imágenes y forma a los equipos de desarrollo en patrones adecuados de manejo de secretos. Si tratas los build secrets como un componente de seguridad crítico, reducirás significativamente tu superficie de ataque y crearás aplicaciones en contenedor más seguras.
Para seguir aprendiendo, te recomiendo estos recursos:
Preguntas frecuentes sobre Docker build secrets
¿Qué son los Docker build secrets?
Los Docker build secrets son fragmentos efímeros de información sensible disponibles durante el proceso de build, pero que nunca se almacenan en las capas de la imagen; solo existen en memoria durante pasos específicos del build.
¿Qué tipos de build secrets admite Docker?
Docker admite tres tipos: montajes de secretos para datos sensibles de uso general, montajes SSH para acceso seguro a repos Git privados y secretos de autenticación de Git (GIT_AUTH_TOKEN y GIT_AUTH_HEADER) para contextos remotos privados.
¿Cómo evito que los secretos aparezcan en mis imágenes de Docker?
Usa la sintaxis --mount=type=secret de BuildKit en las instrucciones RUN junto con builds multietapa; no uses argumentos de build ni variables de entorno para secretos, y audita regularmente las imágenes con docker history para verificar que no haya fugas.
¿Puedo usar Docker build secrets con Docker Compose?
Sí. Docker Compose admite build secrets mediante la sección secrets del archivo compose, lo que te permite definir secretos a nivel superior y referenciarlos en la configuración de build de los servicios.
¿Cómo funcionan los build secrets en pipelines de CI/CD?
Las plataformas de CI/CD inyectan secretos como variables de entorno que pueden pasarse a los builds de Docker con --secret id=name,env=VARIABLE_NAME, habilitando flujos automatizados sin almacenar credenciales en los repositorios.
Como fundador de Martin Data Solutions y científico de datos autónomo, ingeniero de ML e IA, aporto una cartera diversa en Regresión, Clasificación, PNL, LLM, RAG, Redes Neuronales, Métodos de Ensemble y Visión por Ordenador.
- Desarrolló con éxito varios proyectos de ML de extremo a extremo, incluyendo la limpieza de datos, análisis, modelado y despliegue en AWS y GCP, ofreciendo soluciones impactantes y escalables.
- Construí aplicaciones web interactivas y escalables utilizando Streamlit y Gradio para diversos casos de uso de la industria.
- Enseñó y tuteló a estudiantes en ciencia de datos y analítica, fomentando su crecimiento profesional mediante enfoques de aprendizaje personalizados.
- Diseñó el contenido del curso para aplicaciones de generación aumentada por recuperación (RAG) adaptadas a los requisitos de la empresa.
- Es autora de blogs técnicos de IA y ML de gran impacto, que tratan temas como MLOps, bases de datos vectoriales y LLMs, logrando un compromiso significativo.
En cada proyecto que asumo, me aseguro de aplicar prácticas actualizadas en ingeniería de software y DevOps, como CI/CD, code linting, formateo, monitorización de modelos, seguimiento de experimentos y una sólida gestión de errores. Me comprometo a ofrecer soluciones completas, convirtiendo los datos en estrategias prácticas que ayuden a las empresas a crecer y a sacar el máximo partido de la ciencia de datos, el aprendizaje automático y la IA.


