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ística | Trivy | Grype | Snyk | Clair |
|---|---|---|---|---|
| CVEs de paquetes del SO | Sí | Sí | Sí | Sí |
| Dependencias de lenguaje | Sí | Sí | Sí | No |
| Errores de configuración IaC | Sí | No | Sí | No |
| Escaneo de secretos | Sí | No | Sí | No |
| Generación de SBOM | Sí | Sí | Sí | No |
| Licencia | Apache 2.0 | Apache 2.0 | Propietaria | Apache 2.0 |
| Integración CI/CD | Nativa | Nativa | Nativa | Limitada |
| Modo sin conexión | Sí | Sí | No | Parcial |
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:latestcomo escaneo base - Usa
--exit-code 1en CI/CD para bloquear despliegues con vulnerabilidades críticas - Combina
trivy image(runtime) contrivy config(Dockerfile/IaC) para cobertura completa - Las imágenes basadas en Alpine reducen drásticamente la superficie de CVEs
- Usa
.trivyignorepara 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