2.5 · Seguridad básica : non-root, secretos y escaneo

Nivel 2 · Dockerfile y build

2.5Seguridad básica : non-root, secretos y escaneo

Objetivo: Reforzar una imagen : usuario non-root, ningún secreto embarcado, vulnerabilidades escaneadas.
Tiempo estimado: 12 min · lectura autónoma · Si solo tienes 5 min: lee «Lo esencial en 30s» + el esquema.

Lo esencial en 30 segundos

  • Non-root sistemático : el contenedor funciona en root por defecto — dos líneas (USER dedicado) lo cambian todo.
  • Cero secretos en la imagen : COPY o ENV fijado queda legible en el historial y se va con el push — inyectar en el run, nunca en el build.
  • Bases oficiales + escaneo rítmico : slim al día, CVE escaneadas, rebuild regular — la seguridad es un ritmo, no un estado.

Mini-caso hilado — Idir y la imagen que funcionaba en root

Último acto : la imagen configurable de Idir (2.4) está lista, pero funciona en root, un archivo de variables andaba por el contexto, y nadie ha escaneado nunca las capas. Idir refuerza : base slim oficial, usuario dedicado (el proporcionado por la imagen oficial), propiedad ajustada en el build, verificación vía exec + whoami — ya no es root. Excluye los archivos sensibles del contexto (.dockerignore), inyecta la config en el run, y luego escanea y actualiza la base. El nivel 2 está entregado : empaquetado, optimizado, versionado, configurable, reforzado.

Epílogo del hilo conductor 2.1-2.4 : la app de Idir funciona non-root, sin secretos, escaneada — lista para Compose (nivel 3).

1. No funcionar más en root

Por defecto, el proceso del contenedor es root : en caso de fallo, el impacto es máximo. Se crea un usuario dedicado (el usuario proporcionado por la imagen oficial como node, propiedad ajustada en el build) y se declara USER antes del CMD : dos líneas, un mundo de diferencia. Se verifica con exec … whoami : se debe ver al usuario dedicado, no root. Idir añade USER y controla : fin del root « para simplificar ».

2. Cero secretos en la imagen

Un secreto COPY o ENV en el Dockerfile queda legible en el historial de las capas y se va con el push con la imagen. Se inyecta en el run (variable -e, archivo montado, secreto gestionado) y se excluye del contexto (.dockerignore). Lo que nunca tiene commit ni se embarca nunca se filtrará desde el registro. Idir retira todo secreto del Dockerfile y del contexto : la config sensible viaja fuera de la imagen.

3. Escanear antes de desplegar

docker scout (o Trivy/Grype) lista las CVE de las capas con su gravedad. Reflejo : partir de bases slim oficiales, actualizar las etiquetas, reconstruir regularmente — una imagen de 6 meses acumula fallos. En producción, una variable en el run sigue visible vía inspect : se prefieren los secretos gestionados (archivos, orquestador, bóveda). Idir escanea, actualiza, recompila, reescanea : la seguridad es un ritmo.

Error frecuente de interpretación: « USER rompe mis permisos, vuelvo a root ». No : se ajusta la propiedad en el build (chown) o se alinea el UID en el run, no se vuelve a abrir la puerta. La regla de Idir : USER dedicado sistemático, permisos reparados correctamente, verificación whoami — root nunca es la solución.
Una imagen reforzada Base mínima, usuario dedicado, ningún secreto, escaneo regular Base slim oficial Menorsuperficie, etiquetas al díaUSER non-root Utilidaddedicada, whoami verificadoEscaneo + rebuild CVEtratadas, ritmo regular
Base mínima, usuario dedicado, ningún secreto, escaneo regular
Versión en texto del esquema (SEO / lectores de pantalla / traducción): 1) Idir REDUCE : base slim oficial al día — menor superficie atacable. 2) DEGRADA : USER dedicado declarado antes de CMD, propiedad ajustada en el build, whoami verificado vía exec — fin del root. 3) PROTEGE : secretos excluidos del contexto e inyectados en el run, imagen escaneada (CVE), rebuild regular. Lección : non-root + cero secretos + escaneo rítmico, es la base antes de la prod.

🔎 Ejemplo concreto — 🔎 Ejemplo concreto — Reforzar la app Node

La app de Idir, versión reforzada y verificada :

FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN chown -R node:node /app
USER node
EXPOSE 3000
CMD ["node", "server.js"]

docker scout quickview mon-app:1.0
docker exec -it app whoami   # → node, pas root

Lectura : la app funciona en « node », las capas están escaneadas, el puerto sigue declarado y publicado en el run.

Lección : el .dockerignore ha excluido los archivos sensibles antes incluso del build — ningún secreto embarcado.

Vocabulario de la sección

USER
El usuario de ejecución declarado en el Dockerfile (antes de CMD) : el contenedor ya no funciona en root.

Ejemplo sencillo: Idir declara USER node antes de arrancar su app.

Lo que no es: el propietario del repositorio de código.

Reflejo: USER dedicado antes de CMD, siempre.

Secreto
Contraseña, clave, token : información sensible que NUNCA debe entrar en la imagen ni en el repositorio.

Ejemplo sencillo: Idir inyecta la config sensible en el run, nunca en el build.

Lo que no es: un simple ajuste como el puerto.

Reflejo: sensible = fuera de la imagen, fuera de git.

CVE
Una referencia pública de vulnerabilidad conocida, con su gravedad : lo que los escáneres listan capa por capa.

Ejemplo sencillo: Idir anota las CVE críticas de su escaneo y actualiza la base.

Lo que no es: un error de configuración del Dockerfile.

Reflejo: escanear = listar las CVE.

Superficie de ataque
Todo lo embarcado y atacable en la imagen : se reduce (slim, multi-etapa, rebuild).

Ejemplo sencillo: Idir entrega en slim sin SDK : menos embarcado, menos exposición.

Lo que no es: el número de contenedores lanzados.

Reflejo: menos embarcado = menos exposición.

En la práctica — En la práctica — Reforzar tu imagen

  1. Añade un USER non-root a tu Dockerfile (antes de CMD) y recompila.
  2. Verifica con exec + whoami (usuario dedicado, no root).
  3. Escanea la imagen y anota las CVE críticas.
  4. Actualiza la base, recompila, reescanea : compara.
Tus imágenes funcionan en non-root, sin secretos, con un escaneo al día.

Script listo para decir — anunciar una imagen reforzada (30 s)

« La imagen funciona en usuario dedicado, verificado por whoami — fin del root. Ningún secreto dentro : la config sensible se inyecta en el run y se excluye del contexto. Base oficial al día, escaneo sin críticas, rebuild regular previsto. Se puede subir y desplegar con serenidad. »

Para decir mostrando el whoami non-root de Idir y luego el informe de escaneo.

Modelo copiar-pegar — Dockerfile reforzado non-root

FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN chown -R node:node /app
USER node
EXPOSE 3000
CMD ["node", "server.js"]

Permiso roto

USER rompe la escritura sobre un volumen : Idir ajusta la propiedad en el build en lugar de volver a root.

Archivo sensible embarcado

Variables subidas con la imagen : Idir las retira, .dockerignore + inyección en el run.

Escaneo olvidado

Imagen de 6 meses nunca reescaneada : Idir actualiza la base, recompila, reescanea — ritmo retomado.

Secreto visible en el run

Variable sensible legible vía inspect : Idir pasa a secretos gestionados (archivos, orquestador) en prod.

Prudencia: Seguridad básica obligatoria : haz funcionar tus contenedores en usuario non-root (USER dedicado, nunca root « para simplificar »), NUNCA embarques un secreto en la imagen (ni COPY ni ENV fijado : legible en el historial, subido al registro — inyecta en el run vía secretos gestionados), parte de imágenes oficiales al día (slim) y escanea antes de cada despliegue con rebuild regular. Un push público es irreversible : controla la visibilidad del repositorio antes de subir.

✓ Buenas prácticas

  • USER dedicado sistemático, verificado por whoami.
  • Bases slim oficiales al día.
  • Rebuild regular (CVE = ritmo).

✗ Errores frecuentes

  • Quedarse en root « para simplificar ».
  • Hacer commit de un archivo de variables con secretos.
  • Escanear una vez y luego olvidar.

Puntos clave

  • Non-root : USER dedicado antes de CMD, dos líneas, enorme efecto.
  • Cero secretos con commit o embarcados (inyectados en el run, excluidos del contexto).
  • Se escanea (CVE), se actualiza, se reconstruye regularmente.
  • Base oficial mínima = menor superficie de ataque.

Desafío 48h — aplica mañana

Refuerza tu imagen 1.0 : USER non-root + whoami verificado, .dockerignore sin archivos sensibles, escaneo + actualización + rebuild comparado.

Lista de salida de la sección
  • Puedo ejecutar una imagen en non-root (USER + whoami verificado).
  • Sé excluir todo secreto de la imagen y del contexto (inyectado en el run).
  • Escaneo, actualizo y reconstruyo a ritmo regular.
Autoevaluación 1-5 : ¿whoami responde otra cosa que root ?¿mi historial no contiene ningún secreto ?

Preguntas frecuentes

USER rompe mis permisos, ¿qué hacer ?

A menudo un volumen montado en root : ajusta la propiedad (chown) en el build o alinea el UID en el run. No vuelvas a root por facilidad : repara el permiso correctamente y vuelve a verificar con whoami.

ENV con contraseña en el run, ¿es seguro ?

Mejor que en la imagen, pero visible vía inspect : en producción se prefieren los secretos gestionados (archivos montados, orquestador, bóveda). El run solo es una etapa, no una protección.

Comprueba tu comprensión

¿Qué imagen filtrará un secreto con el push ?

Recursos adicionales (opcional, para ir más allá)

Examen del nivel 2Preguntas inéditas y más difíciles para validar tus conocimientos