Trivy y Grype un año después: cuál ha madurado mejor

Trivy y Grype llevan ya un par de años instalados como los dos escáneres de contenedores open-source de referencia. Trivy viene de Aqua Security, Grype de Anchore, y aunque sobre el papel hacen lo mismo —leer capas de una imagen Docker, enumerar paquetes y cruzarlos con bases de datos de CVE— en la práctica han evolucionado hacia filosofías distintas. Después de un año largo integrando ambos en pipelines de CI reales, con imágenes que van desde node:20 pelado hasta bases Python con cien dependencias transitivas, tengo bastante claro dónde gana cada uno.

Superficie común

Lo que comparten es fácil de resumir: escanean imágenes de contenedor, generan SBOM en formatos SPDX y CycloneDX, se integran con GitHub Actions y GitLab CI, devuelven códigos de salida útiles para romper builds, ambos son Apache 2.0 y ambos soportan modo offline para entornos air-gapped. Si el requisito es simplemente “queremos un escáner de CVE en el pipeline antes de publicar la imagen”, los dos lo hacen y punto. La discusión interesante empieza cuando el alcance crece.

Trivy: el escáner que se convirtió en navaja suiza

Trivy nació como escáner de imágenes, pero Aqua fue ampliando el target hasta cubrir sistemas de ficheros, repositorios Git, manifests de Kubernetes, charts de Helm, módulos Terraform y plantillas de CloudFormation. La invocación típica se resume en cuatro verbos —image, fs, config, repo— y todos aceptan los mismos flags de severidad, formato de salida y política de exit code. Esta uniformidad es lo que más se agradece cuando toca meterlo en un pipeline: un solo binario cubre desde “escanea esta imagen” hasta “revisa el Dockerfile y los manifests que la despliegan”.

El operador de Kubernetes (Trivy Operator) es el otro diferencial fuerte. Instalado con Helm, observa el cluster y genera cuatro tipos de Custom Resource: VulnerabilityReports por pod, ConfigAuditReports con chequeos de CIS Benchmark sobre los manifests en vivo, RbacAssessmentReports con problemas de RBAC y ExposedSecretReports que detectan credenciales embebidas en imágenes. Todo queda como recursos nativos de Kubernetes, consultables con kubectl get y exportables a Prometheus. Para un equipo ya metido en el ecosistema K8s, eso es lo que empuja la balanza.

Grype: foco estrecho, acabado limpio

Grype hace menos cosas pero las hace con una ergonomía más cuidada. Acepta una imagen, un directorio o un SBOM previamente generado por Syft, y devuelve una lista de CVEs sin pretender opinar sobre IaC o misconfigs. La integración con Syft es el punto clave: Syft genera el SBOM una vez, y ese SBOM se escanea con Grype, se firma con cosign, se guarda como attestation y se re-escanea más adelante sin tener que bajarse la imagen otra vez. Es una separación de responsabilidades que encaja muy bien en flujos de supply-chain security formales, tipo SLSA.

En un pipeline que ya genera SBOM como entregable independiente —algo cada vez más común porque se pide a nivel regulatorio—, Grype se convierte en “el verificador del SBOM”, y eso permite que la generación y el escaneo vivan en fases distintas del pipeline, incluso en máquinas distintas. Trivy también puede escanear SBOMs, pero el flujo no está tan pulido.

SBOM-based vs file-based en la práctica

La diferencia técnica de fondo es cómo se descubren los paquetes. Grype, apoyado en Syft, construye primero un SBOM detallado y luego lo cruza con la base de vulnerabilidades. Trivy hace ambas cosas internamente pero está más optimizado para el escaneo directo de la imagen, parseando metadatos de gestores de paquetes (dpkg, apk, rpm, pip, npm, go.mod, Cargo.lock) sobre la marcha. En términos de resultados, para imágenes con paquetes de sistema bien etiquetados son prácticamente equivalentes. La diferencia aparece en lenguajes interpretados con dependencias vendoreadas o en binarios estáticos de Go: Syft suele reconocer más paquetes porque su lógica de descubrimiento es más agresiva, y eso se traduce en más vulnerabilidades encontradas —no siempre reales, pero sí más.

Falsos positivos en producción

Este es el punto donde hay que tener cuidado. Ambas herramientas reportan CVEs que técnicamente están en el paquete pero no son explotables en el contexto real: la función vulnerable no se llama, la versión del sistema operativo ya lo parcheó vía backport (caso típico en Debian y Ubuntu), o la CVE requiere un vector de red que no aplica. Tras un año midiéndolo, Trivy tiende a beneficiarse algo más de los parches distro-specific porque su base de datos (Aqua + NVD + fuentes distro) se cruza con metadatos de la distribución, mientras que Grype tira más de NVD directo. El resultado neto es que en imágenes Debian y Alpine, Trivy suele dar menos ruido; en imágenes basadas en distroless o en binarios estáticos, la diferencia se diluye.

La estrategia que ha funcionado es filtrar por severidad HIGH y CRITICAL en CI como política de fallo, y dejar MEDIUM y por debajo para review humano semanal. Romper el build cada vez que aparece un CVE LOW en una librería transitiva solo enseña al equipo a ignorar el escáner.

Dónde Trivy gana claramente

El único terreno donde Trivy gana sin discusión es el escaneo de misconfiguraciones. Revisa Dockerfiles contra buenas prácticas, chequea módulos Terraform contra más de cincuenta reglas, valida manifests de Kubernetes contra CIS Benchmark y renderiza charts de Helm antes de analizarlos. Grype, sencillamente, no hace nada de esto —su alcance es vulnerabilidades, no configuraciones—. Si el equipo quiere una única herramienta que cubra “¿este contenedor es seguro?” incluyendo la definición del contenedor y no solo su contenido, Trivy es la respuesta.

Integración en CI y admisión en K8s

En GitHub Actions, ambos tienen acciones mantenidas por los respectivos fabricantes. La de Aqua para Trivy acepta referencias de imagen, formato de salida SARIF (que GitHub interpreta nativamente en la pestaña de Security), umbral de severidad y exit code configurable. La de Anchore para Grype es más escueta pero igual de funcional. La fricción de integración es la misma.

Para admisión en Kubernetes, Trivy se combina bien con Kyverno mediante políticas que verifican imágenes firmadas y sin CVEs críticos antes de permitir el despliegue:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-no-critical-cves
spec:
  rules:
    - name: check-critical-cves
      verifyImages:
        - imageReferences:
            - "*"
          required: true

El operador de Trivy puede alimentar esta política con sus VulnerabilityReports, cerrando el bucle entre escaneo y control de admisión.

Veredicto

Si solo pudiera tener uno, Trivy. Cubre más superficie, tiene mejor historia de falsos positivos en distros mainstream, y el operador de Kubernetes es una pieza que no tiene equivalente en el lado de Anchore. Si el pipeline gira en torno a SBOMs como entregable independiente, firmados y verificados por separado, Grype con Syft encaja mejor en esa arquitectura. Y muchos equipos acaban ejecutando los dos como defense-in-depth: el coste de correr ambos en CI es trivial comparado con pillar un CVE que uno de los dos se saltó. Tras un año, esa es la conclusión honesta —no hay ganador absoluto, hay encajes buenos y encajes tibios.

Entradas relacionadas