El escaneo de seguridad de contenedores con Trivy se ha convertido en el estándar de facto para detectar vulnerabilidades en imágenes Docker antes de que lleguen a producción. Si alguna vez te has preguntado cómo los atacantes explotan CVEs conocidos en imágenes base como ubuntu:20.04 o node:18, o si tu Dockerfile expone secretos, Trivy te da la respuesta en segundos. Esta guía cubre instalación, estrategias de escaneo, integración CI/CD y cómo interpretar y actuar sobre los hallazgos sin ahogarse en falsos positivos.

Requisitos Previos

  • Docker instalado y en ejecución (Docker 20.10+)
  • Estación de trabajo Linux, macOS o Windows (WSL2)
  • Familiaridad básica con imágenes Docker y Dockerfiles
  • Una plataforma CI/CD (GitHub Actions, GitLab CI o Jenkins) para integración de pipelines
  • Acceso root o sudo para instalación de Trivy a nivel del sistema (o usar la instalación del binario)

Instalación de Trivy

Trivy se distribuye como un binario estático único sin dependencias externas. La forma más rápida en Linux:

curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
trivy --version

En Ubuntu/Debian puedes agregar el repositorio apt de Aqua Security para actualizaciones gestionadas:

sudo apt-get install wget apt-transport-https gnupg lsb-release -y
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/trivy.list
sudo apt-get update && sudo apt-get install trivy -y

En macOS con Homebrew: brew install trivy

Trivy descarga su base de datos de vulnerabilidades en la primera ejecución. Fuerza una actualización en cualquier momento con trivy image --download-db-only.

Escaneo de Imágenes Docker en Busca de Vulnerabilidades

El comando principal es sencillo:

trivy image nginx:latest

Trivy descarga la imagen si no está en caché local, descomprime las capas y verifica cada paquete del SO instalado y dependencia de lenguaje contra su base de datos de vulnerabilidades (NVD, GitHub Advisory, Alpine secdb y otros). La salida muestra IDs de CVE, severidad, versión instalada y la versión corregida cuando está disponible.

Filtrado por Severidad

Por defecto Trivy muestra todas las severidades de UNKNOWN a CRITICAL. En la práctica, conviene centrarse en hallazgos accionables:

trivy image --severity HIGH,CRITICAL nginx:latest

Ignorar Vulnerabilidades Sin Corrección

Muchos CVEs no tienen corrección disponible aún. Usa --ignore-unfixed para omitirlos y enfocarte en lo que realmente puedes remediar:

trivy image --severity HIGH,CRITICAL --ignore-unfixed nginx:latest

Formatos de Salida

Trivy admite múltiples formatos de salida para diferentes consumidores:

# Tabla legible por humanos (predeterminado)
trivy image nginx:latest

# JSON para procesamiento programático
trivy image --format json --output results.json nginx:latest

# SARIF para integración con la pestaña de Seguridad de GitHub
trivy image --format sarif --output results.sarif nginx:latest

# SBOM CycloneDX
trivy image --format cyclonedx --output sbom.json nginx:latest

El formato SARIF se integra directamente con la pestaña de Seguridad de GitHub, mostrando anotaciones de vulnerabilidades en línea en las pull requests.

Escaneo de Dockerfiles y Errores de Configuración IaC

El escáner config de Trivy verifica Dockerfiles, manifiestos de Kubernetes, Terraform y Helm charts en busca de configuraciones de seguridad incorrectas antes de que se desplieguen:

# Escanear un Dockerfile
trivy config ./Dockerfile

# Escanear un directorio completo (manifiestos Kubernetes, Terraform)
trivy config ./k8s/

# Escanear charts de Helm
trivy config --helm-values values.yaml ./charts/myapp

Los hallazgos comunes en Dockerfiles incluyen: ejecutar como root, usar ADD en lugar de COPY, falta de HEALTHCHECK, exposición de puertos sensibles y no anclar los digests de imagen base.

Detección de Secretos y Datos Sensibles

Trivy puede escanear capas de imagen y sistemas de archivos en busca de secretos incorporados accidentalmente:

# Habilitar escaneo de secretos en una imagen
trivy image --scanners secret nginx:latest

# Escanear un directorio local en busca de secretos
trivy fs --scanners secret ./src/

Trivy detecta claves AWS, tokens de GitHub, claves SSH privadas, cadenas de conexión de bases de datos y cientos de otros patrones de secretos. Esto es particularmente valioso para detectar secretos comprometidos en el código fuente que terminaron en una capa de Docker.

Comparativa con Alternativas

CaracterísticaTrivyGrypeSnykClair
CVEs de paquetes del SO
Dependencias de lenguajeNo
Errores de configuración IaCNoNo
Escaneo de secretosNoNo
Generación de SBOMNo
LicenciaApache 2.0Apache 2.0PropietariaApache 2.0
Integración CI/CDNativaNativaNativaLimitada
Modo sin conexiónNoParcial

La ventaja de Trivy es su amplitud: combina escaneo de vulnerabilidades, detección de configuraciones incorrectas, escaneo de secretos y generación de SBOM en un único binario sin requerir un servidor en ejecución o una base de datos.

Integración de Trivy en Pipelines CI/CD

GitHub Actions

name: Escaneo de Seguridad de Contenedores

on:
  push:
    branches: [main]
  pull_request:

jobs:
  trivy-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Construir imagen Docker
        run: docker build -t myapp:${{ github.sha }} .

      - name: Ejecutar escáner de vulnerabilidades Trivy
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: myapp:${{ github.sha }}
          format: sarif
          output: trivy-results.sarif
          severity: HIGH,CRITICAL
          exit-code: 1
          ignore-unfixed: true

      - name: Subir resultados de Trivy a la pestaña de Seguridad de GitHub
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: trivy-results.sarif

El ajuste exit-code: 1 falla el pipeline cuando se encuentran CVEs críticos o altos. if: always() en la carga del SARIF garantiza que los resultados sean visibles incluso cuando el paso de escaneo falla.

GitLab CI

trivy-scan:
  image: aquasec/trivy:latest
  stage: test
  script:
    - trivy image --exit-code 1 --severity CRITICAL --ignore-unfixed $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  allow_failure: false

Escenario del Mundo Real

Tienes una aplicación en producción que usa node:16 como imagen base. Tu equipo de seguridad detecta que el pipeline CI/CD nunca valida las imágenes de contenedor antes del despliegue. Tienes 48 horas para implementar una puerta de escaneo.

Paso 1 — Auditar la imagen actual:

trivy image node:16 --severity HIGH,CRITICAL --ignore-unfixed

Esto revela 47 CVEs HIGH y 12 CRITICAL en la imagen base, la mayoría solucionados actualizando a node:18-alpine.

Paso 2 — Actualizar el Dockerfile:

# Antes
FROM node:16

# Después
FROM node:18-alpine

Paso 3 — Volver a escanear para confirmar la corrección:

trivy image node:18-alpine --severity HIGH,CRITICAL --ignore-unfixed

La variante alpine reduce el conteo de CVEs de 59 a 3 (todos sin corrección).

Paso 4 — Agregar la puerta CI:

Agrega el workflow de GitHub Actions mencionado antes. Todas las PRs futuras se bloquearán si se introducen CVEs CRITICAL.

Paso 5 — Escanear también IaC:

trivy config ./k8s/ --severity HIGH,CRITICAL

Esto descubre dos problemas: un deployment ejecutándose como root y una configuración de contexto de seguridad readOnlyRootFilesystem faltante.

Errores Comunes y Casos Especiales

Desactualización de la base de datos de vulnerabilidades: Trivy guarda en caché su base de datos localmente. En entornos CI, ejecuta trivy image --download-db-only como paso de caché separado para evitar descargas redundantes.

Autenticación en registros privados: Exporta las credenciales como variables de entorno antes de escanear:

export TRIVY_USERNAME=miusuario
export TRIVY_PASSWORD=micontraseña
trivy image miregistro.ejemplo.com/miapp:latest

Falsos positivos: Algunos CVEs se marcan en bibliotecas que tu aplicación nunca llama. Usa .trivyignore para suprimir falsos positivos conocidos:

# .trivyignore
CVE-2022-12345  # No explotable — biblioteca no utilizada en tiempo de ejecución

Alpine musl vs glibc: Las imágenes basadas en Alpine reportan menos CVEs porque Alpine usa musl libc y el equipo de seguridad de Alpine parchea de forma agresiva. Esto no es cobertura “faltante” — refleja diferencias genuinas en el ecosistema de bibliotecas.

Imágenes multi-arquitectura: Siempre especifica la plataforma al escanear imágenes multi-arch para obtener resultados correctos: trivy image --platform linux/amd64 myapp:latest.

Trivy vs seguridad en tiempo de ejecución: Trivy encuentra vulnerabilidades en tiempo de compilación. No reemplaza a herramientas de seguridad en tiempo de ejecución como Falco que detectan comportamiento inesperado en contenedores en ejecución.

Solución de Problemas

Error “No such image”: Trivy no puede encontrar la imagen localmente y no puede descargarla. Confirma el nombre de la imagen, el tag y las credenciales del registro.

Fallos de descarga de base de datos en entornos sin internet: Descarga el paquete de base de datos en una máquina con conexión a internet con trivy image --download-db-only, luego transfiere el directorio ~/.cache/trivy/ al host aislado.

Alto uso de memoria en imágenes grandes: Usa --parallel 1 para reducir el procesamiento concurrente de capas: trivy image --parallel 1 myapp:latest.

Código de salida 1 pero sin CVEs críticos mostrados: Verifica si --ignore-unfixed está omitido — los CVEs críticos sin corrección pueden activar el código de salida aunque esperaras ver solo problemas corregibles.

Timeout de escaneo en CI: Configura TRIVY_TIMEOUT=10m para extender el timeout predeterminado de 5 minutos para imágenes grandes.

Resumen

  • Trivy es un escáner de binario único que cubre CVEs, configuraciones incorrectas, secretos y generación de SBOM
  • Ejecuta trivy image --severity HIGH,CRITICAL --ignore-unfixed myapp:latest como escaneo base
  • Usa --exit-code 1 en CI/CD para bloquear despliegues con vulnerabilidades críticas
  • Combina trivy image (runtime) con trivy config (Dockerfile/IaC) para cobertura completa
  • Las imágenes basadas en Alpine reducen drásticamente la superficie de CVEs
  • Usa .trivyignore para suprimir falsos positivos confirmados y reducir la fatiga de alertas
  • Sube resultados SARIF a la pestaña de Seguridad de GitHub para anotaciones en línea en PRs
  • Trivy no reemplaza la seguridad en tiempo de ejecución — combínalo con Falco para defensa en profundidad

Artículos Relacionados