Tema 10
Una imagen segura se construye con intención: base confiable, dependencias controladas, capas limpias, permisos mínimos, usuario no root y ausencia de secretos. El objetivo es entregar solo lo necesario para ejecutar la aplicación.
La seguridad de un contenedor empieza antes de ejecutarlo. Una imagen mal construida puede incluir paquetes vulnerables, herramientas innecesarias, secretos, usuarios privilegiados, archivos con permisos amplios o dependencias sin control.
El Dockerfile o archivo equivalente define muchas de esas decisiones. Por eso debe tratarse como código de infraestructura: versionado, revisado, escaneado y mantenido.
Construir imágenes seguras no significa agregar más controles dentro de la imagen, sino reducir lo que contiene y hacer explícito lo que necesita para funcionar.
Una imagen segura debe ser mínima, verificable, reproducible y ejecutarse con permisos reducidos. Estos principios guían las decisiones de build.
La imagen base es el punto de partida. Si está desactualizada o viene de una fuente no confiable, ese riesgo se hereda en todas las imágenes construidas sobre ella.
| Criterio | Buena práctica | Riesgo si se ignora |
|---|---|---|
| Origen | Usar registries aprobados e imágenes oficiales o internas | Base alterada o sin mantenimiento |
| Tamaño | Preferir bases mínimas cuando sean compatibles | Más paquetes y más vulnerabilidades |
| Soporte | Elegir imágenes con actualizaciones frecuentes | Vulnerabilidades sin parche disponible |
| Versión | Fijar versión o digest en producción | Builds no reproducibles o cambios inesperados |
| Compatibilidad | Validar que la base contiene solo lo que la app requiere | Dependencias innecesarias o fallas operativas |
Un tag como latest es cómodo, pero puede apuntar a contenido distinto con el tiempo. Para producción conviene usar versiones explícitas y, cuando sea posible, digest criptográfico.
Comparación práctica:
latest: simple, pero mutable y poco reproducible.Usar digest mejora trazabilidad, pero también exige proceso de actualización para no quedar atado a imágenes vulnerables antiguas.
Los builds multi-stage separan el entorno de compilación del entorno de ejecución. Esto permite usar herramientas pesadas durante el build y copiar al resultado final solo los artefactos necesarios.
Beneficios:
Las dependencias son una fuente frecuente de vulnerabilidades. Incluyen paquetes del sistema operativo, librerías del lenguaje, módulos externos y binarios descargados durante el build.
Buenas prácticas:
Ejecutar como root dentro del contenedor aumenta el impacto de una vulnerabilidad. Aunque root en un contenedor no siempre equivale a root del host, sigue otorgando más poder dentro del entorno aislado y puede combinarse con otras malas configuraciones.
Para reducir riesgo:
USER.Una imagen puede ejecutar como usuario no root y aun así tener permisos inseguros. Archivos escribibles por todos, claves privadas legibles o directorios críticos modificables pueden facilitar abuso.
| Elemento | Riesgo | Control |
|---|---|---|
| Archivos de aplicación | Modificación de código en runtime | Propietario correcto y permisos de solo lectura |
| Directorios temporales | Escritura fuera de rutas esperadas | Limitar escritura a rutas necesarias |
| Claves o certificados | Lectura por procesos no autorizados | No incluirlos en imagen; montar secretos en runtime |
| Binarios | Reemplazo o ejecución no prevista | Permisos mínimos y ausencia de herramientas innecesarias |
Los builds a veces necesitan acceder a repositorios privados, paquetes internos o servicios de firma. Esos accesos no deben quedar persistidos en capas, historial, logs o variables finales.
Prácticas seguras:
ARG o ENV..dockerignore.El contexto de build es el conjunto de archivos enviados al motor de construcción. Si incluye archivos innecesarios, aumenta el riesgo de copiar secretos, artefactos temporales, dependencias locales o documentación sensible.
El archivo .dockerignore ayuda a excluir:
.git y metadatos del repositorio..env, credenciales y claves privadas.Reducir superficie significa eliminar todo lo que no aporte a la ejecución de la aplicación. Esto limita vulnerabilidades disponibles y dificulta acciones posteriores de un atacante.
Medidas habituales:
Una imagen debe poder vincularse con su origen. Las etiquetas de metadatos ayudan a saber qué repositorio, commit, versión, pipeline y fecha generaron el artefacto.
Metadatos útiles:
El escaneo de imágenes detecta vulnerabilidades conocidas en paquetes del sistema, librerías y dependencias. Debe ejecutarse antes de publicar y desplegar imágenes.
| Momento | Qué valida | Acción esperada |
|---|---|---|
| Pull request | Dockerfile y dependencias declaradas | Detectar malas prácticas temprano |
| Build | Imagen resultante | Bloquear vulnerabilidades críticas según política |
| Registry | Imágenes almacenadas | Alertar nuevas CVE sobre imágenes existentes |
| Pre-deploy | Imagen candidata a producción | Verificar firma, digest y cumplimiento |
Un Dockerfile seguro depende del lenguaje y aplicación, pero este ejemplo muestra ideas generales: build separado, usuario no root, copia mínima y runtime reducido.
FROM node:22-bookworm-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-bookworm-slim AS runtime
ENV NODE_ENV=production
WORKDIR /app
RUN useradd --create-home --shell /usr/sbin/nologin appuser
COPY --from=build /app/dist ./dist
COPY --from=build /app/package*.json ./
RUN npm ci --omit=dev && npm cache clean --force
USER appuser
EXPOSE 3000
CMD ["node", "dist/server.js"]
Este ejemplo no es universal. En producción habría que fijar versiones con más precisión, escanear dependencias, evaluar una base más mínima y usar secretos solo en runtime.
latest en producción..dockerignore.ARG, ENV o archivos temporales.latest para despliegues productivos?.dockerignore adecuado?Construir imágenes seguras exige disciplina en el Dockerfile, control de dependencias, reducción de superficie y permisos mínimos. Cada decisión tomada en el build afecta directamente el riesgo del contenedor en runtime.
En el próximo tema estudiaremos el escaneo de vulnerabilidades en imágenes, dependencias y paquetes del sistema.