Trivy y Grype: que el escaneo de contenedores produzca correcciones y no números

Todo escaneo de imagen devuelve cientos de CVE y casi ninguno es alcanzable. Cómo recortamos la lista a lo explotable, dónde es más fuerte cada herramienta y por qué la imagen base lo es todo.

Escanea cualquier imagen de contenedor en producción y obtendrás varios cientos de vulnerabilidades, de las cuales importa un puñado. Si el pipeline bloquea con "ninguna crítica", el equipo acaba con una lista permanente de excepciones y ningún beneficio de seguridad. Si no bloquea por nada, el informe es decorativo.

Sacarle valor a Trivy y a Grype va sobre todo de decidir qué hacer con la salida.

Dos herramientas porque las bases de datos difieren

Ambos escáneres funcionan igual: construyen una lista de materiales de software a partir de las capas de la imagen, casan versiones de componentes contra bases de datos de vulnerabilidades e informan. La diferencia está en el emparejamiento.

Trivy tira de los rastreadores de seguridad de las distribuciones, de la GitHub Advisory Database y de fuentes de fabricantes; es amplio, rápido y cubre paquetes de sistema operativo, dependencias de lenguaje, IaC y secretos en un solo binario. Grype usa la base curada por Anchore y se empareja con Syft para generar SBOM, con un emparejamiento a menudo más conservador en los ecosistemas de lenguaje.

Ejecuta los dos una vez contra la misma imagen y compara. En nuestra experiencia el solape ronda el 80 por ciento, y las diferencias son informativas: algo que uno reporta y el otro no suele significar un CVE en disputa, un parche retroportado que el otro rastreador conoce, o un componente que la otra herramienta no identificó.

Elige uno para la puerta del pipeline después de esa comparación. Ejecutar los dos en cada compilación es fricción con poco beneficio marginal; ejecutar los dos cuando estás evaluando o cuando un hallazgo huele raro es barato.

La distribución importa más que la aplicación

El reparto típico de 400 hallazgos en una imagen: 380 en paquetes del sistema operativo que vienen de la imagen base, 20 en dependencias de la aplicación.

Esa proporción te dice dónde va el esfuerzo. Pasar de python:3.12 a python:3.12-slim elimina la mayor parte de la lista. Pasar a una base mínima tipo distroless o Chainguard la elimina casi entera, porque los paquetes no están: curl, git, bash, perl y el resto del entorno de shell son el origen de la mayoría de tu recuento de CVE y ninguno está en la ruta de ejecución de tu aplicación.

Este es el cambio con más palanca disponible y es una línea del Dockerfile. Hazlo antes de afinar ninguna configuración del escáner.

Filtra a lo corregible y a lo alcanzable

Dos opciones cambian el carácter de la salida.

trivy image --ignore-unfixed --severity HIGH,CRITICAL \
  --scanners vuln,secret --format sarif -o salida.sarif miimagen:sha256-...

--ignore-unfixed descarta las vulnerabilidades sin parche disponible. Siguen siendo reales, pero no son accionables este sprint y mezclarlas impide que nadie actúe sobre las que sí lo son. Sigue esas por separado y revísalas cuando aparezca la corrección.

La alcanzabilidad es el siguiente filtro y el más potente. Un CVE en una biblioteca que viaja en la imagen pero nunca se importa, o en una ruta de código que tu aplicación no llama, no es una vulnerabilidad explotable. Trivy no hace alcanzabilidad por grafo de llamadas, pero puedes aproximarla bien: un CVE en una dependencia transitiva de una herramienta de compilación que no está en la imagen de ejecución es ruido, y las compilaciones multietapa eliminan esa categoría entera de forma automática.

Escanea el digest que corre, no la etiqueta que compiló

La imagen que tu pipeline escaneó el martes pasado y la imagen que corre hoy en el clúster son a menudo distintas, porque :latest se movió o una recompilación reutilizó una capa cacheada.

Saca los digests que están corriendo de verdad:

kubectl get pods -A -o jsonpath='{range .items[*].status.containerStatuses[*]}{.imageID}{"\n"}{end}' \
  | sort -u > corriendo.txt

y escanea esos. La diferencia entre esa lista y la de imágenes que produce tu pipeline suele ser un hallazgo en sí misma: imágenes corriendo que ningún pipeline actual compila, lo que significa que nadie las está parcheando.

Genera el SBOM una vez, escanéalo muchas

Los datos de vulnerabilidades cambian a diario; la imagen no. Generar un SBOM en tiempo de compilación y guardarlo junto a la imagen te permite reevaluar, en segundos y sin descargar nada, todas las imágenes que has publicado contra la base de datos de hoy.

syft miimagen:etiqueta -o spdx-json > sbom.json
grype sbom:sbom.json

Así es como respondes a "¿nos afecta?" en una hora tras el siguiente fallo de biblioteca ampliamente explotado, en vez de en una semana. Es además el artefacto que satisface las expectativas de SBOM que ya aparecen en los cuestionarios de clientes y en regulación como NIS2.

La puerta que funciona

Bloquea la compilación por: severidad crítica, con corrección disponible, en la imagen de ejecución, en un paquete que la aplicación carga de verdad. Eso es un número pequeño, normalmente cero, y cuando no es cero merece la pena parar.

Todo lo demás va a un informe con responsable y fecha. Lo que mantiene sana la higiene de imágenes no es la puerta; es recompilar cada imagen semanalmente sobre una base fresca, de forma automática. Un equipo que recompila cada semana tiene una lista corta de vulnerabilidades sin esforzarse. Un equipo que recompila cuando algo se rompe la tiene larga, esté como esté configurado el escáner.

ConsultorIA

¿Quieres esto en tu nube?

El diagnóstico de diez días en solo lectura es gratuito, y con Skyline puedes ver tu entorno en un mapa antes de escribirnos.

Artículos relacionados