← Blog
// DEVSECOPS · CONTENEDORES

Endurece tu Dockerfile: los anti-patrones que delatan un contenedor inseguro

Publicado el 18 ago 2026 · 8 min de lectura
DevSecOpsDockerKubernetes

Un contenedor que arranca no es un contenedor seguro. La mayoría de los Dockerfiles pasan CI, sirven la app… y a la vez corren como root, arrastran secretos en sus capas y confían en imágenes que cambian bajo tus pies. Estos son los anti-patrones que revisa un linter, por qué importan y cómo arreglarlos.

1. Correr como root (el más común)

Por defecto, un contenedor corre como root. Si un atacante logra ejecución dentro del contenedor y luego encuentra un escape (o un volumen montado), hereda root en el host. La defensa es una línea:

RUN adduser --system --no-create-home app
USER app

Declara USER hacia el final, tras instalar dependencias (que sí necesitan privilegios).

2. Imagen base sin fijar (:latest o sin etiqueta)

FROM node o FROM node:latest significan «lo que haya hoy». Mañana el build es distinto y no sabes qué cambió: reproducibilidad rota y superficie que se mueve sola. Fija una etiqueta concreta —o mejor, un digest inmutable:

FROM node:20.11-alpine
# o, a prueba de balas:
FROM node:20.11-alpine@sha256:e4b2f...

3. Secretos en ENV / ARG

Un token en ENV DB_PASSWORD=... no «desaparece» en tiempo de ejecución: queda grabado en las capas de la imagen y en su historial. Cualquiera con la imagen lo extrae con docker history. No pongas secretos en el Dockerfile: usa build secrets (--secret) o inyéctalos en runtime.

4. curl | sh y ADD remoto

RUN curl https://get.ejemplo.com | sh ejecuta código remoto sin verificarlo: si comprometen ese servidor, comprometen tu build. Igual con ADD https://…, que descarga y confía. Descarga, verifica el checksum y luego ejecuta; y usa COPY (no ADD) para ficheros locales.

5. Imagen gorda = más superficie

apt-get install sin --no-install-recommends arrastra paquetes de más (más CVEs que parchear). Instala lo justo y limpia en la misma capa:

RUN apt-get update \
 && apt-get install -y --no-install-recommends curl \
 && rm -rf /var/lib/apt/lists/*

6. Sin HEALTHCHECK

Sin healthcheck, el orquestador no sabe si tu app está viva o colgada. Un contenedor «arriba» pero roto sigue recibiendo tráfico. Añade uno.

🐳 ¿Quieres verlo sobre tu propio fichero? Pega tu Dockerfile, docker-compose o manifiesto de Kubernetes en el linter de Dockerfile / IaC y te da una nota A–F con estos anti-patrones marcados. Todo en tu navegador; la config no se envía a ningún sitio.

Y al desplegar: compose y Kubernetes

El endurecimiento no acaba en el Dockerfile. En docker-compose y K8s, los sospechosos habituales son:

Un Dockerfile decente, de referencia

FROM node:20.11-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev && npm cache clean --force
COPY . .
USER node
HEALTHCHECK CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "server.js"]

Base fijada, sin secretos, usuario no root, healthcheck y solo dependencias de producción. Nada exótico: son cinco hábitos.

⚠️ El linter no sustituye a un escáner de imágenes (Trivy, Grype) ni a un pipeline de firma/SBOM. Es la primera capa: caza lo que se ve en el fichero antes de construir.

Checklist

Un buen Dockerfile no es más largo: es más aburrido. Y aburrido, en seguridad, es exactamente lo que quieres.

Comparte: LinkedIn X
Sergio Belmonte Morales
Sergio Belmonte Morales
Analista de Ciberseguridad · SOC · Especialista en Sentinel/KQL