Escaneo y corrección de seguridad de imágenes Docker: tutorial práctico con Trivy e integración CI/CD

El 10 de diciembre de 2021, la curva de alertas en el panel de monitorización se disparó de repente. Alguien en el grupo de operaciones compartió un número CVE: CVE-2021-44228, la vulnerabilidad Log4Shell que conmocionó a toda la comunidad técnica. Más de una docena de microservicios usaban imágenes base con esta vulnerabilidad, y todo el equipo pasó la noche actualizando imágenes y redesplegando.
En la retrospectiva posterior, el jefe preguntó: «¿Cómo es que ni siquiera sabíamos qué vulnerabilidades tenían las imágenes que usábamos?»
Un estudio de NSFOCUS indica que el 76% de las imágenes en Docker Hub tienen vulnerabilidades de seguridad conocidas. ¿Esa imagen python:3.9 que usas ahora? ¿nginx:latest? Probablemente esconden decenas de CVE.
Seguro que te preguntas: ¿cómo saber qué vulnerabilidades hay en una imagen? ¿Cómo corregirlas cuando las encuentras? ¿Cómo detectarlas automáticamente en el flujo CI/CD para evitar desplegar imágenes vulnerables en producción?
Estas preguntas las fui resolviendo durante dos años de experiencia en producción. En este artículo te enseño paso a paso:
- Cómo escanear rápidamente vulnerabilidades en imágenes Docker con herramientas como Trivy
- Métodos sistemáticos para corregir vulnerabilidades (no se trata solo de «actualizar la versión de la imagen»)
- Cómo integrar el escaneo automatizado en plataformas CI/CD como GitHub Actions y GitLab CI
Todos los comandos y configuraciones son código práctico que puedes copiar y ejecutar directamente. Créeme, después de leer esto evitarás muchos desvíos.
"Un informe de investigación de NSFOCUS de marzo de 2018 indicó que, en una muestra aleatoria de imágenes de Docker Hub, más de tres cuartas partes (76%) tenían vulnerabilidades de seguridad conocidas."
Panorama de amenazas de seguridad en imágenes Docker
¿Qué problemas de seguridad pueden tener las imágenes Docker?
Siendo sincero, cuando empecé con contenedores, yo también pensaba que una imagen Docker era simplemente un «programa empaquetado» que funcionaba y listo. Hasta que en una ocasión tardamos tres días en detectar un problema en producción y descubrí que las vulnerabilidades en las imágenes se dividen en varias categorías, cada una con su complicación.
Vulnerabilidades en paquetes del sistema operativo — la más común. En las imágenes base Alpine o Ubuntu que usas, bibliotecas del sistema como OpenSSL, glibc o curl sacan nuevas vulnerabilidades de vez en cuando. Por ejemplo, la vulnerabilidad de alta severidad en OpenSSL 3.0.x de 2022 afectó a un gran número de imágenes.
Vulnerabilidades en dependencias de aplicaciones — más ocultas. Tu proyecto Python depende de Flask, Flask depende de Werkzeug, y una versión concreta de Werkzeug tiene una vulnerabilidad de ejecución de código. ¿Crees que actualizar Python ya te hace seguro? No necesariamente; las vulnerabilidades ocultas en el árbol de dependencias pueden pasar desapercibidas. Log4j es el caso típico: cuántos proyectos Java ni siquiera sabían que usaban Log4j.
Errores de configuración y filtración de información sensible — algunos desarrolladores, por comodidad, escriben la contraseña de la base de datos directamente en el Dockerfile, o se olvidan de eliminar el directorio .git antes de empaquetar. Otros ejecutan contenedores con el usuario root, concediendo permisos con más generosidad de la debida.
Riesgos de la cadena de suministro — lo más difícil de prevenir. Descargas una imagen de Docker Hub que parece normal, y un día resulta que alguien le implantó un minero o una puerta trasera. Un estudio de 2018 encontró bastantes «imágenes maliciosas» en Docker Hub, dirigidas a quienes hacen pull directamente por comodidad.
¿Por qué no se pueden confiar ciegamente en las imágenes de Docker Hub?
La cifra del 76% me dejó realmente impactado la primera vez que la vi.
Puede que pienses que los datos son algo antiguos. Pero el problema es que esas imágenes antiguas siguen en uso. Y muchas «imágenes oficiales» tampoco se actualizan en tiempo real. La etiqueta python:3.9 que ves puede haberse construido hace seis meses, con paquetes del sistema ya obsoletos.
Lo peor es que la calidad de las imágenes en Docker Hub es muy desigual. Algunas las mantiene un desarrollador individual y pueden llevar seis meses sin actualizarse; otras llevan la etiqueta «oficial» pero en realidad las subió una empresa concreta. Sin un estándar unificado de auditoría de seguridad, usarlas es cuestión de suerte.
Un compañero mío, por comodidad, descargó de Docker Hub una imagen con entorno Node.js. Más tarde el escaneo reveló más de 30 vulnerabilidades de alta severidad. Cuando preguntó al autor de la imagen, la respuesta fue: «Lleva dos años sin mantenimiento, arréglalo tú». Para reír y para llorar.
Por eso mi principio actual es: cualquier imagen descargada de Docker Hub debe escanearse antes de usarse, incluso las que llevan etiqueta «oficial».
Comparación y elección de herramientas de escaneo de imágenes
Trivy: mi herramienta open source más recomendada
Hablando de herramientas de escaneo de seguridad de imágenes Docker, hay bastantes opciones en el mercado, pero ahora casi solo uso Trivy. No es que las demás sean malas, sino que Trivy equilibra realmente muy bien «facilidad de uso» y «funcionalidad».
La primera vez que usé Trivy, me sorprendió la velocidad. Escanear una imagen de varios cientos de MB tarda unos 10 segundos la primera vez, y luego solo unos segundos. Lo clave es que no hay que mantener una base de datos local ni configurar servicios adicionales: instalas y listo.
¿Qué puede detectar Trivy? Sinceramente, más de lo que esperaba:
- Detección de vulnerabilidades: soporta paquetes de diversos sistemas operativos (Alpine, Ubuntu, Debian, CentOS, etc.) y dependencias de aplicaciones (npm, pip, Maven, Go Modules, etc.)
- Escaneo de configuraciones incorrectas: puede revisar problemas de seguridad en Dockerfiles y configuraciones de Kubernetes
- Detección de secretos: te avisa si la imagen empaquetó accidentalmente claves, contraseñas u otra información sensible
- Cumplimiento de licencias: también puede revisar las licencias open source de los paquetes de dependencias para evitar riesgos legales
Lo que más me satisface es que Trivy ya está integrado en plataformas principales como GitHub Actions y Harbor. Es decir, no tienes que inventar la integración: las plataformas ya te lo facilitan.
Otras herramientas en breve
Snyk — producto comercial con funciones realmente completas. Se integra directamente en el IDE y te avisa en tiempo real si las dependencias tienen vulnerabilidades. También soporta generación automática de PR de corrección, muy inteligente. Pero la versión gratuita tiene bastantes limitaciones; para un uso profundo hay que pagar. Adecuado para grandes empresas con presupuesto.
Clair — motor de escaneo del registro Quay, open source y altamente personalizable. Pero la configuración es bastante compleja. Funciona obteniendo información CVE de los equipos de seguridad de diversas distribuciones Linux, centrándose en la detección de amenazas. Si tu equipo tiene ingenieros de seguridad dedicados y quieres una solución altamente personalizable, Clair es buena opción. Para equipos de desarrollo normales, la curva de aprendizaje es algo alta.
Anchore — solución empresarial con gestión de políticas. Por ejemplo, puedes definir reglas: «bloquear el despliegue si se detecta una vulnerabilidad CRITICAL». Adecuado para escenarios con requisitos estrictos de cumplimiento, como finanzas o sanidad. Pero igualmente, la configuración y el mantenimiento son pesados.
Docker Scout / Hardened Images (DHI) — nuevo producto oficial de Docker lanzado en mayo de 2025, que promete CVE casi cero y puede reducir el volumen de la imagen un 95%. Revisé el enfoque técnico: usa runtime distroless y tiene mucho potencial. Pero al ser reciente, el ecosistema aún está en construcción; conviene seguirlo de cerca.
Mi recomendación
Si eres un equipo pequeño o un desarrollador individual, usa Trivy directamente: gratuito, fácil y con funciones suficientes. Un comando para instalar, otro para escanear; en 10 minutos lo dominas.
Si eres una gran empresa con altos requisitos de seguridad y cumplimiento, y presupuesto suficiente, considera Snyk. Su base de datos de vulnerabilidades se actualiza con rapidez, el soporte es profesional y se integra profundamente con diversas herramientas de desarrollo.
Si tu equipo tiene ingenieros de seguridad dedicados y quieres una solución open source altamente personalizable, Clair merece la pena. Pero prepárate para dedicar tiempo a la configuración.
Si buscas seguridad extrema e imágenes minimalistas, sigue la evolución de Docker Hardened Images; quizá sea el estándar del futuro.
Mi práctica personal: Trivy para desarrollo diario y CI/CD, con feedback rápido; antes del despliegue en producción, un segundo escaneo con Clair integrado en Harbor, doble seguro.
Tutorial práctico con Trivy
Instalación y uso básico
La instalación de Trivy es tan sencilla que la primera vez me pareció poco creíble. Si usas macOS:
brew install trivy
Los usuarios de Linux pueden descargar el binario directamente o usar el gestor de paquetes; en la página de releases de GitHub hay instrucciones detalladas: https://github.com/aquasecurity/trivy/releases
Una vez instalado, prueba a escanear una imagen:
# Escanear imagen de Docker Hub
trivy image python:3.9
# Escanear imagen construida localmente
trivy image myapp:latest
# Escanear imagen guardada como archivo tar
trivy image --input ruby-3.1.tar
En la primera ejecución, Trivy descargará automáticamente la base de datos de vulnerabilidades (trivy-db), unas decenas de MB; hay que esperar un momento. Una vez descargada, el escaneo es muy rápido.
Los resultados se muestran clasificados por severidad:
- CRITICAL (crítica): debe corregirse de inmediato; puede permitir el control total del sistema
- HIGH (alta): debe corregirse lo antes posible; puede ser explotada para ataques
- MEDIUM (media): se recomienda corregir; con cierto riesgo de seguridad
- LOW (baja): prioridad baja; puede programarse
Cada vulnerabilidad muestra el número CVE, el paquete afectado, la versión actual y la versión de corrección (si existe).
Opciones avanzadas de escaneo: sacar más partido a Trivy
En el trabajo real, puede que no quieras ver todas las vulnerabilidades, especialmente las de baja severidad que «no se pueden corregir» y resultan molestas. Ahí entran las opciones avanzadas:
Mostrar solo vulnerabilidades de alta y crítica severidad:
trivy image --severity HIGH,CRITICAL nginx:latest
La uso mucho en CI/CD. Exigir corregir todas las vulnerabilidades no es realista; lo urgente es resolver primero las de alta severidad.
Ignorar vulnerabilidades sin parche:
trivy image --ignore-unfixed redis:latest
Algunas vulnerabilidades aún no tienen parche oficial; no sirve de nada preocuparse. Con este parámetro, Trivy solo muestra vulnerabilidades con solución disponible, para que concentres el esfuerzo en lo que puedes resolver.
Hacer que el comando devuelva código de salida distinto de cero al detectar vulnerabilidades graves:
trivy image --exit-code 1 --severity CRITICAL myapp:latest
¡Muy útil! En un pipeline CI/CD, si se detectan vulnerabilidades graves, el comando devuelve un código de salida distinto de cero y el build falla. Es como una barrera de seguridad para tu imagen: las imágenes vulnerables no llegan a producción.
Salida en formato JSON para integrar con otras herramientas:
trivy image -f json -o results.json myapp:latest
Si quieres importar los resultados a una plataforma de seguridad o hacer procesamiento automatizado adicional, el formato JSON es muy práctico.
Escaneo en entorno sin conexión:
trivy image --skip-db-update myapp:latest
En algunas empresas la red interna no tiene acceso a internet. Puedes descargar la base de datos de vulnerabilidades en una máquina con conexión, copiarla a la red interna y usar este parámetro para evitar intentos de actualización.
Interpretar los resultados del escaneo: en qué centrarse
La primera vez que escaneé una imagen de producción, los resultados llenaron toda la pantalla: más de 100 vulnerabilidades. En ese momento pensé: ¿cuánto tardaré en corregir todo esto?
Con la experiencia, aprendí que hay trucos para leer los resultados:
Priorizar vulnerabilidades con versión de corrección. Si la columna «Fixed Version» muestra «none» o está vacía, aún no hay parche y no puedes hacer mucho. Resuelve primero las que tienen solución.
Centrarse en CRITICAL y HIGH. Las vulnerabilidades LOW y MEDIUM, si el servicio no está expuesto a internet, pueden posponerse. Pero CRITICAL debe corregirse de inmediato; a menudo tienen código exploit público que los atacantes pueden usar directamente.
Consultar detalles del CVE. Si no estás seguro de una vulnerabilidad, busca el número CVE en https://cve.mitre.org/ para ver el problema concreto, el alcance y la dificultad de explotación. A veces una vulnerabilidad que parece aterradora requiere condiciones muy específicas para explotarse.
Entender cómo funciona Trivy. Trivy descarga una base de datos de vulnerabilidades (básicamente un archivo JSON con vulnerabilidades conocidas de diversos paquetes de software) y compara la lista de paquetes de tu imagen (obtenida analizando la base de datos del gestor de paquetes). Si el nombre y la versión del paquete coinciden con una vulnerabilidad conocida, alerta.
Por eso a veces hay falsos positivos. Si tu imagen tiene un paquete vulnerable pero el código real no llama a la función problemática, Trivy también alertará. En esos casos debes evaluar el riesgo según el código real.
Métodos sistemáticos para corregir vulnerabilidades
Empezar por elegir la imagen base correcta
Corregir vulnerabilidades, muchas veces, no es «reparar» sino «cambiar». ¿Detectas decenas de vulnerabilidades en paquetes del sistema? No las actualices una por una; cambiar a una imagen base más segura es mucho más eficiente.
Mi equipo solía usar Alpine Linux como imagen base porque solo pesa 5.87 MB, muy compacta. Pero luego descubrimos que Alpine también tiene sus problemas: usa la biblioteca estándar musl en lugar de glibc, lo que a veces causa problemas de compatibilidad. Y aunque sea pequeña, las vulnerabilidades siguen apareciendo.
Ahora prefiero las imágenes Distroless. Solo pesan 3.06 MB, más pequeñas que Alpine, y están extremadamente simplificadas: sin shell, sin gestor de paquetes, sin herramientas innecesarias.
¿Por qué es más seguro? Muy simple: aunque un atacante encuentre una vulnerabilidad en tu aplicación, no puede ejecutar comandos shell en el contenedor porque no hay shell. La superficie de ataque queda al mínimo.
Las imágenes Distroless de Google tienen versiones para varios lenguajes:
# Aplicación Python
FROM gcr.io/distroless/python3
# Aplicación Node.js
FROM gcr.io/distroless/nodejs
# Aplicación Go (si compilas estáticamente, puedes usar la versión static)
FROM gcr.io/distroless/static
Distroless también tiene inconvenientes: depurar es complicado porque ni siquiera tiene comandos básicos como ls o cat. Mi enfoque: en desarrollo uso imágenes normales para depurar fácilmente; en producción cambio a Distroless para garantizar la seguridad.
Las Hardened Images (DHI) que Docker lanzó oficialmente en 2025 van más allá, prometiendo CVE casi cero y reducción del tamaño de imagen hasta un 95%. Aunque el ecosistema aún no está maduro, merece la pena seguirlas; quizá sean el estándar de la próxima generación.
Métodos prácticos para actualizar dependencias y corregir vulnerabilidades
Cambiar la imagen base no basta; las dependencias a nivel de aplicación también hay que gestionarlas. Aquí van algunos trucos prácticos:
Método 1: actualizar la versión de la imagen base
# No uses latest, es demasiado vago
FROM python:3.9
# Usa un número de versión menor concreto y actualízalo periódicamente
FROM python:3.11.7
Mucha gente usa la etiqueta latest por comodidad, pero es un mal hábito. latest puede llevar meses sin actualizarse y los paquetes del sistema quedan obsoletos. Usa números de versión concretos y revisa mensualmente si hay nuevas versiones menores.
Método 2: actualizar paquetes del sistema en el Dockerfile
FROM ubuntu:22.04
# Actualizar todos los paquetes del sistema al construir la imagen
RUN apt-get update && \
apt-get upgrade -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
Nota el truco: poner update, upgrade y clean en una sola instrucción RUN reduce el número de capas de imagen. Eliminar la caché de apt al final ahorra decenas de MB adicionales.
Método 3: actualizar versiones de dependencias de la aplicación
El escenario más común. Trivy detecta una vulnerabilidad en Flask y vas a requirements.txt a cambiar la versión:
# Antes
Flask==2.0.1
# Después (suponiendo que 2.3.0 corrige la vulnerabilidad)
Flask==2.3.0
Pero hay un riesgo: actualizar Flask directamente puede causar problemas de compatibilidad. Mejor probar primero en entorno de pruebas y confirmar que todo funciona antes de desplegar en producción.
Un enfoque más prudente es actualizar solo la versión de parche. Si Flask 2.0.1 tiene vulnerabilidad, prueba primero la última versión 2.0.x en lugar de saltar directamente a 2.3.0.
Mejores prácticas que no debes ignorar
Además de corregir vulnerabilidades concretas, algunos buenos hábitos mantienen tus imágenes seguras a largo plazo:
Usar builds multi-etapa:
# Etapa de build
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# Etapa de ejecución (solo el binario compilado)
FROM gcr.io/distroless/static
COPY --from=builder /app/myapp /
CMD ["/myapp"]
Así la imagen final no incluye el compilador Go, el código fuente ni archivos intermedios. Mucho más limpia, con superficie de ataque mucho menor.
No ejecutar como usuario root:
RUN useradd -m myuser
USER myuser
Muchas imágenes ejecutan aplicaciones como root por defecto, lo cual es peligroso. Si un atacante compromete la aplicación, obtiene permisos root y puede hacer lo que quiera. Crear un usuario normal y ejecutar la aplicación con esa identidad es mucho más seguro.
Reconstruir imágenes periódicamente:
Esto se pasa por alto con facilidad. Tu código puede no haber cambiado en seis meses, pero los paquetes del sistema de la imagen base siguen recibiendo parches. Reconstruye al menos una vez al mes para incorporar los últimos parches de seguridad.
Nuestro equipo tiene una tarea programada que reconstruye automáticamente todas las imágenes de producción cada domingo, las escanea, y si hay problemas los detectamos y corregimos el lunes.
Usar .dockerignore para evitar empaquetar archivos sensibles:
.git
.env
*.log
secrets/
Si empaquetas accidentalmente un archivo .env, la contraseña de la base de datos queda expuesta. .dockerignore funciona como .gitignore para evitar que archivos sensibles entren en la imagen.
Nunca usar la etiqueta latest:
Lo repito porque es importante. FROM python:latest es una bomba de relojería: no sabes qué versión descargas ni si tiene vulnerabilidades. Usa etiquetas explícitas como FROM python:3.11.7-slim, predecibles y trazables.
Construir un flujo CI/CD de escaneo de seguridad automatizado
Integración en GitHub Actions: listo en cinco minutos
Escanear imágenes manualmente es tedioso y fácil de olvidar. La forma más fiable es integrar el escaneo en CI/CD para que se ejecute automáticamente en cada commit o construcción de imagen.
Integrar Trivy en GitHub Actions es sorprendentemente sencillo. Crea .github/workflows/docker-scan.yml en tu repositorio:
name: Docker Security Scan
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'table'
severity: 'CRITICAL,HIGH'
exit-code: '1' # Fallar el build al detectar vulnerabilidades graves
- name: Upload scan results
if: always()
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
¿Qué hace esta configuración?
- Se activa automáticamente en cada push a main o develop, o en PR
- Construye la imagen Docker (usando el SHA del commit como etiqueta, garantizando unicidad en cada build)
- Escanea con Trivy, revisando solo vulnerabilidades CRITICAL y HIGH
- Si detecta vulnerabilidades graves,
exit-code: '1'hace fallar el workflow y bloquea el merge - Sube los resultados a la pestaña Security de GitHub para consulta
Después de configurarlo, haz un push de prueba. Verás los resultados en la pestaña GitHub Actions. Si hay vulnerabilidades, el build se marca en rojo y no se fusionará en la rama principal. Es una barrera de seguridad automática para tu repositorio.
Integración en GitLab CI/CD: igual de sencilla
Si usas GitLab, la integración es similar. Crea o modifica .gitlab-ci.yml en la raíz del repositorio:
stages:
- build
- test
- security
build_image:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
security_scan:
stage: security
image: aquasec/trivy:latest
script:
- trivy image --exit-code 1 --severity HIGH,CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
allow_failure: false
dependencies:
- build_image
Fíjate en allow_failure: false: significa que si el escaneo de seguridad falla, todo el pipeline falla. Si no quieres ser tan estricto, puedes cambiarlo a allow_failure: true para que las vulnerabilidades solo generen advertencias sin bloquear el despliegue.
Pero recomiendo que en pipelines de producción sea siempre false. En desarrollo puedes ser más flexible, pero en producción no hay que ceder.
Doble seguro con el registro de imágenes Harbor
Si tu empresa usa Harbor como registro privado de imágenes (muchas grandes empresas lo hacen), aún más sencillo. Harbor integra Trivy y Clair desde la v1.2 y puede escanear automáticamente las imágenes que se suben.
En la configuración del proyecto en Harbor puedes definir políticas de escaneo:
- Escaneo automático al hacer push de imagen
- Escaneo programado diario de todas las imágenes (por si se descubren nuevas vulnerabilidades)
- Umbrales de vulnerabilidades: por ejemplo, prohibir la descarga de imágenes con vulnerabilidades CRITICAL
La estrategia de nuestro equipo:
- En desarrollo, al hacer push a Harbor se dispara automáticamente el escaneo con Trivy
- Si hay vulnerabilidades HIGH o superiores, Harbor etiqueta la imagen como «con vulnerabilidades»
- En producción, el clúster K8s configura un admission webhook que rechaza el despliegue de imágenes con esa etiqueta
Así, aunque alguien evite CI/CD y despliegue directamente, Harbor actúa como última barrera.
Recomendación de flujo completo de escaneo de seguridad
Juntando todo lo anterior, un flujo completo de seguridad de imágenes debería ser así:
Fase de desarrollo:
- Integrar plugins de Snyk o Trivy en el IDE para ver vulnerabilidades en dependencias mientras escribes código
- Después de construir la imagen localmente, ejecutar manualmente
trivy image
Fase de build:
- GitHub Actions / GitLab CI escanean automáticamente las imágenes recién construidas
- Fallo inmediato ante vulnerabilidades CRITICAL para bloquear el merge
- Subir resultados al Security Dashboard para que el equipo vea tendencias
Fase de repositorio:
- Segundo escaneo en Harbor u otros registros (por si CI/CD se lo pierde o se divulgan nuevas vulnerabilidades)
- Configurar políticas de vulnerabilidades para bloquear la descarga de imágenes de alto riesgo
Tiempo de ejecución:
- Escanear periódicamente las imágenes en ejecución en producción (una vez por semana)
- Disparar alertas al detectar nuevas vulnerabilidades y programar correcciones
Revisión periódica:
- Revisar mensualmente el estado de corrección de vulnerabilidades
- Actualizar estrategias de escaneo y umbrales de vulnerabilidades
Este flujo parece complejo, pero una vez configurado funciona de forma totalmente automática. Nuestro equipo tardó aproximadamente un Sprint (dos semanas) desde la configuración hasta la operación estable, a cambio de una seguridad a largo plazo.
Sinceramente, desde que configuramos este flujo duermo mucho más tranquilo. Al menos no me preocupa despertarme un día con una vulnerabilidad grave y descubrir que nuestras imágenes ya estaban afectadas.
Conclusión
Volvamos a la historia de Log4Shell del principio. Si hubiéramos tenido este flujo de escaneo de seguridad de imágenes, la vulnerabilidad se habría detectado en la fase CI/CD y nunca habría llegado a producción. No habría habido esa madrugada de tensión ni la pregunta incómoda del jefe.
La seguridad de imágenes Docker no es tecnología de otro mundo. El núcleo son tres cosas:
- Escanear vulnerabilidades con herramientas como Trivy (instalación sencilla, rápida y suficiente)
- Corregir vulnerabilidades de forma sistemática (elegir imágenes base seguras, actualizar dependencias, seguir mejores prácticas)
- Automatizar el escaneo en CI/CD (integración en GitHub Actions / GitLab CI en cinco minutos)
Sinceramente, la cifra del 76% de imágenes vulnerables en Docker Hub me asustó al principio. Pero pensándolo bien, también demuestra que la mayoría de equipos aún no le presta atención. Si empiezas ahora, al menos estarás por delante del 76%. ¿No es motivo de satisfacción?
Mi recomendación: no intentes corregir todas las vulnerabilidades de golpe, no es realista. Empieza por lo más sencillo:
- Antes de salir hoy: instala Trivy, escanea la imagen Docker de tu proyecto y mira cuántas vulnerabilidades tiene
- Esta semana: corrige las vulnerabilidades CRITICAL; puede ser tan simple como actualizar la versión de la imagen base
- Próximo Sprint: integra Trivy en CI/CD y configúralo para bloquear el despliegue al detectar vulnerabilidades graves
- Este mes: define una línea base de seguridad de imágenes y revisa y actualiza periódicamente
La seguridad de contenedores es un proceso continuo, no algo que se resuelve de una vez. Pero una vez establecido el flujo, el mantenimiento posterior es realmente sencillo. Nuestro equipo escanea automáticamente cada semana; si hay problemas, los revisamos en la reunión semanal y normalmente se resuelven en media hora.
Una última insistencia: ¡las imágenes de producción deben escanearse! ¡Las imágenes descargadas de Docker Hub deben escanearse! No esperes a que ocurra un incidente para arrepentirte; entonces será demasiado tarde.
Si tienes experiencias prácticas o historias de tropiezos con la seguridad Docker, compártelas en los comentarios. Avancemos juntos hacia aplicaciones contenedorizadas más seguras.
Flujo completo de escaneo y corrección de seguridad de imágenes Docker
Pasos completos desde la instalación de Trivy hasta la integración en CI/CD, cubriendo escaneo, corrección y automatización
⏱️ Estimated time: 2 hr
- 1
Step 1: Instalar la herramienta de escaneo Trivy
Instalar la herramienta de escaneo Trivy:
• Usuarios de macOS: brew install trivy
• Usuarios de Linux: descargar el binario desde la página de releases de GitHub o usar el gestor de paquetes
• URL de descarga: https://github.com/aquasecurity/trivy/releases
• La primera ejecución descargará automáticamente la base de datos de vulnerabilidades (trivy-db, unas decenas de MB) - 2
Step 2: Escaneo básico de vulnerabilidades en imágenes
Escaneo básico de vulnerabilidades en imágenes:
• Escanear imagen de Docker Hub: trivy image python:3.9
• Escanear imagen local: trivy image myapp:latest
• Escanear archivo tar: trivy image --input ruby-3.1.tar
Los resultados se clasifican por severidad:
• CRITICAL (debe corregirse de inmediato)
• HIGH (debe corregirse lo antes posible)
• MEDIUM (se recomienda corregir)
• LOW (puede programarse) - 3
Step 3: Configurar opciones avanzadas de escaneo
Configurar opciones avanzadas de escaneo:
• Mostrar solo vulnerabilidades de alta y crítica severidad: trivy image --severity HIGH,CRITICAL nginx:latest
• Ignorar vulnerabilidades sin parche: trivy image --ignore-unfixed redis:latest
• Hacer que el comando devuelva código de salida distinto de cero al detectar vulnerabilidades graves (para CI/CD):
trivy image --exit-code 1 --severity CRITICAL myapp:latest
• Salida en formato JSON: trivy image -f json -o results.json myapp:latest - 4
Step 4: Corregir vulnerabilidades de forma sistemática
Corregir vulnerabilidades de forma sistemática:
Elegir una imagen base segura:
• Usar imágenes Distroless (gcr.io/distroless/python3/nodejs/static, solo 3.06 MB, sin shell ni gestor de paquetes)
• O Docker Hardened Images de 2025 (CVE casi cero)
Actualizar la versión de la imagen base:
• Usar números de versión concretos (python:3.11.7) en lugar de latest
Actualizar paquetes del sistema en el Dockerfile:
• RUN apt-get update && apt-get upgrade -y && apt-get clean && rm -rf /var/lib/apt/lists/*
Actualizar versiones de dependencias de la aplicación:
• Modificar requirements.txt y otros archivos de dependencias, priorizando actualizaciones de parches - 5
Step 5: Integrar escaneo automatizado en GitHub Actions
Crear el archivo .github/workflows/docker-scan.yml con la configuración:
• Activación en push/pull_request
• Construir la imagen Docker
• Escanear con aquasecurity/trivy-action
• Configurar severity: 'CRITICAL,HIGH' y exit-code: '1' (fallar el build al detectar vulnerabilidades graves)
• Subir los resultados del escaneo a la pestaña Security de GitHub - 6
Step 6: Integración en GitLab CI/CD
Crear o modificar .gitlab-ci.yml con la configuración:
• stages incluye build, test, security
• La etapa security usa la imagen aquasec/trivy:latest
• Ejecutar trivy image --exit-code 1 --severity HIGH,CRITICAL
• Configurar allow_failure: false (el fallo del escaneo de seguridad hace fallar todo el pipeline) - 7
Step 7: Establecer un flujo completo de escaneo de seguridad
Fase de desarrollo:
• Integrar plugins de Snyk/Trivy en el IDE
• Escanear manualmente después de construir la imagen localmente
Fase de build:
• Escaneo automático en CI/CD
• Fallo inmediato ante vulnerabilidades CRITICAL para bloquear el merge
• Subir resultados al Security Dashboard
Fase de repositorio:
• Segundo escaneo en Harbor u otros registros de imágenes
• Configurar políticas de vulnerabilidades para bloquear la descarga de imágenes de alto riesgo
Tiempo de ejecución:
• Escanear periódicamente las imágenes en producción (una vez por semana)
• Disparar alertas al detectar nuevas vulnerabilidades
Revisión periódica:
• Revisar mensualmente el estado de corrección de vulnerabilidades
• Actualizar estrategias de escaneo y umbrales de vulnerabilidades
FAQ
¿Qué problemas de seguridad pueden tener las imágenes Docker?
1) Vulnerabilidades en paquetes del sistema operativo:
• Bibliotecas del sistema como OpenSSL, glibc, curl en imágenes base Alpine, Ubuntu
• Por ejemplo, la vulnerabilidad de alta severidad en OpenSSL 3.0.x de 2022
2) Vulnerabilidades en dependencias de aplicaciones:
• Vulnerabilidades ocultas en el árbol de dependencias, como el caso de Log4j
• Muchos proyectos Java ni siquiera sabían que usaban Log4j
3) Errores de configuración y filtración de información sensible:
• Contraseñas de base de datos escritas en el Dockerfile
• Olvidar eliminar el directorio .git
• Ejecutar contenedores con el usuario root
4) Riesgos de la cadena de suministro:
• Imágenes maliciosas en Docker Hub
• Un estudio de 2018 encontró imágenes maliciosas diseñadas para engañar a los usuarios
¿Por qué no se pueden confiar ciegamente en las imágenes de Docker Hub? ¿Es exacta la cifra del 76%?
Aunque los datos son algo antiguos, esas imágenes antiguas siguen en uso. Muchas "imágenes oficiales" tampoco se actualizan en tiempo real; la etiqueta python:3.9 puede haberse construido hace seis meses, con paquetes del sistema ya obsoletos.
La calidad de las imágenes en Docker Hub es muy desigual:
• Algunas las mantiene un desarrollador individual y pueden llevar seis meses sin actualizarse
• Algunas llevan la etiqueta "oficial" pero en realidad las subió una empresa concreta
• No hay un estándar unificado de auditoría de seguridad
Principio: cualquier imagen descargada de Docker Hub debe escanearse antes de usarse, incluso las que llevan etiqueta "oficial".
¿En qué se diferencia Trivy de otras herramientas de escaneo (Snyk, Clair, Anchore)? ¿Cuál elegir?
• La herramienta open source más recomendada, gratuita, fácil de usar y con funciones suficientes
• Instalación sencilla (brew install trivy)
• Escaneo rápido (unos 10 segundos la primera vez, luego unos segundos)
• Soporta detección de vulnerabilidades, escaneo de configuraciones incorrectas, detección de secretos y cumplimiento de licencias
• Integrado en GitHub Actions y Harbor
• Se domina en 10 minutos, ideal para equipos pequeños o desarrolladores individuales
Snyk:
• Producto comercial con funciones completas
• Se integra en el IDE con alertas en tiempo real
• Soporta generación automática de PR de corrección
• Pero la versión gratuita tiene muchas limitaciones, adecuada para grandes empresas con presupuesto
Clair:
• Motor de escaneo del registro Quay, open source y altamente personalizable
• Pero la configuración es compleja y tiene curva de aprendizaje alta
• Adecuado para equipos con ingenieros de seguridad dedicados
Anchore:
• Solución empresarial con gestión de políticas
• Adecuada para sectores financiero y sanitario con requisitos estrictos de cumplimiento
Recomendación: equipos pequeños usen Trivy; grandes empresas consideren Snyk; equipos con ingenieros de seguridad investiguen Clair.
¿Cómo interpretar los resultados del escaneo de Trivy? ¿En qué centrarse?
• CRITICAL (debe corregirse de inmediato, puede permitir el control total del sistema)
• HIGH (debe corregirse lo antes posible, puede ser explotada para ataques)
• MEDIUM (se recomienda corregir, con cierto riesgo de seguridad)
• LOW (prioridad baja, puede programarse)
Consejos para leer los resultados:
1) Priorizar vulnerabilidades con versión de corrección (si Fixed Version muestra none o está vacío, aún no hay parche; resolver primero las que tienen solución)
2) Centrarse en CRITICAL y HIGH (CRITICAL debe corregirse de inmediato, a menudo con código exploit público que los atacantes pueden usar directamente)
3) Consultar detalles del CVE (en https://cve.mitre.org/ buscar el número CVE para ver el problema concreto, alcance e impacto)
4) Entender cómo funciona Trivy (descarga un archivo JSON de base de datos de vulnerabilidades, compara con la lista de paquetes de la imagen; si el nombre y la versión del paquete coinciden con una vulnerabilidad conocida, alerta; puede haber falsos positivos, evaluar el riesgo según el código real)
¿Cómo corregir vulnerabilidades en imágenes Docker de forma sistemática?
1) Elegir una imagen base segura:
• Imágenes Distroless de solo 3.06 MB, más pequeñas que Alpine, sin shell ni gestor de paquetes, superficie de ataque mínima
• Distroless de Google tiene versiones python3/nodejs/static
• Docker Hardened Images de 2025 promete CVE casi cero y puede reducir el tamaño de la imagen un 95%
2) Actualizar la versión de la imagen base:
• Usar números de versión concretos python:3.11.7 en lugar de latest
• latest puede llevar meses sin actualizarse y los paquetes del sistema quedan obsoletos
• Revisar mensualmente si hay nuevas versiones menores
3) Actualizar paquetes del sistema en el Dockerfile:
• RUN apt-get update && apt-get upgrade -y && apt-get clean && rm -rf /var/lib/apt/lists/*
• Poner update/upgrade/clean en una sola instrucción RUN para reducir capas de imagen
4) Actualizar versiones de dependencias de la aplicación:
• Modificar requirements.txt, etc.
• Priorizar actualizaciones de parches: si Flask 2.0.1 tiene vulnerabilidad, probar primero la última versión 2.0.x en lugar de saltar directamente a 2.3.0
• Probar primero en entorno de pruebas antes de desplegar en producción
Mejores prácticas: usar builds multi-etapa, no ejecutar como root, reconstruir imágenes periódicamente (al menos una vez al mes), usar .dockerignore para evitar empaquetar archivos sensibles, nunca usar la etiqueta latest.
¿Cómo integrar el escaneo de seguridad automatizado en CI/CD?
• Crear .github/workflows/docker-scan.yml
• Configurar activación en push/pull_request
• Construir la imagen Docker, escanear con aquasecurity/trivy-action
• Configurar severity: 'CRITICAL,HIGH' y exit-code: '1' (fallar el build al detectar vulnerabilidades graves)
• Subir resultados a la pestaña Security de GitHub
Integración en GitLab CI:
• Crear o modificar .gitlab-ci.yml
• Configurar stages incluyendo build/test/security
• La etapa security usa la imagen aquasec/trivy:latest
• Ejecutar trivy image --exit-code 1 --severity HIGH,CRITICAL
• Configurar allow_failure: false (el fallo del escaneo hace fallar todo el pipeline; en producción debe ser false)
Registro de imágenes Harbor:
• Desde v1.2 integra Trivy y Clair
• Puede configurar escaneo automático al hacer push, escaneo programado diario de todas las imágenes
• Configurar umbrales de vulnerabilidades (por ejemplo, prohibir la descarga de imágenes con vulnerabilidades CRITICAL)
• En desarrollo, el push de imagen dispara escaneo automático; si hay vulnerabilidades HIGH o superiores, se etiqueta como "con vulnerabilidades"
• En producción, el clúster K8s configura admission webhook para rechazar el despliegue de imágenes con esa etiqueta
¿Cómo debería ser un flujo completo de escaneo de seguridad de imágenes Docker?
Fase de desarrollo:
• Integrar plugins de Snyk o Trivy en el IDE para ver vulnerabilidades en dependencias mientras escribes código
• Después de construir la imagen localmente, ejecutar manualmente trivy image
Fase de build:
• GitHub Actions/GitLab CI escanean automáticamente las imágenes recién construidas
• Fallo inmediato ante vulnerabilidades CRITICAL para bloquear el merge
• Subir resultados al Security Dashboard para que el equipo vea tendencias
Fase de repositorio:
• Segundo escaneo en Harbor u otros registros de imágenes
• A veces CI/CD se lo pierde o se divulgan nuevas vulnerabilidades
• Configurar políticas de vulnerabilidades para bloquear la descarga de imágenes de alto riesgo
Tiempo de ejecución:
• Escanear periódicamente las imágenes en ejecución en producción, una vez por semana
• Disparar alertas al detectar nuevas vulnerabilidades y programar correcciones
Revisión periódica:
• Revisar mensualmente el estado de corrección de vulnerabilidades
• Actualizar estrategias de escaneo y umbrales de vulnerabilidades
Este flujo, una vez configurado, funciona de forma totalmente automática. El equipo tarda aproximadamente un Sprint (dos semanas) desde la configuración hasta la operación estable, a cambio de una seguridad a largo plazo.
20 min de lectura · Publicado el: 18 dic 2025 · Actualizado el: 21 ago 2026
Guía práctica de Docker
Si llegaste desde búsqueda, lo más rápido es ir al artículo anterior o siguiente de esta misma serie.
Anterior
Guía completa para desplegar Nginx con Docker: montaje de configuración, HTTPS y proxy inverso
Tutorial completo: montaje de archivos de configuración, certificados HTTPS y proxy inverso al desplegar Nginx con Docker. Soluciona problemas habituales como configuración que no se aplica y comunicación entre contenedores, con renovación automática de Let's Encrypt y mejores prácticas para producción.
Parte 28 de 38
Siguiente
Seguridad en Docker: guía completa para evitar ejecutar contenedores como root
Los contenedores Docker ejecutados por defecto como root suponen un riesgo grave. Este artículo explica el escape de contenedores y ofrece soluciones completas: instrucción USER en Dockerfile, parámetro --user, control fino con Capabilities y configuración de AppArmor para construir contenedores seguros en producción.
Parte 30 de 38



Comentarios
Inicia sesión con GitHub para dejar un comentario