2.5Seguridad básica : non-root, secretos y escaneo
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.
🔎 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
- Añade un USER non-root a tu Dockerfile (antes de CMD) y recompila.
- Verifica con exec + whoami (usuario dedicado, no root).
- Escanea la imagen y anota las CVE críticas.
- Actualiza la base, recompila, reescanea : compara.
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.
✓ 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.
- 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.
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.
¿Qué imagen filtrará un secreto con el push ?