SBOM con Trivy

Sin un Software Bill of Materials (SBOM), resulta difícil determinar qué paquetes quedaron realmente incluidos en cada release. Esto ralentiza la respuesta ante una vulnerabilidad nueva, especialmente cuando existen múltiples imágenes, plataformas o lenguajes.

Trivy puede analizar una imagen y generar un inventario en CycloneDX o SPDX. Ese documento debe vincularse con el digest inmutable de la imagen, validarse y conservarse como evidencia del release.

Cuándo conviene aplicarlo

Este flujo resulta útil para:

  • Contenedores desplegados en producción.
  • Auditorías de componentes y dependencias.
  • Investigación y respuesta ante CVEs.
  • Repositorios con varios lenguajes o servicios.
  • Imágenes publicadas para múltiples arquitecturas.

Requisitos previos

Necesitarás:

  • Una imagen construida y un Dockerfile reproducible.
  • Trivy, Docker Buildx y jq.
  • Permisos para publicar y consultar el registry.
  • Una política de severidades, excepciones y retención.
  • Espacio de almacenamiento para los SBOM históricos.
  • Una versión fijada de Trivy para reducir diferencias entre ejecuciones.

Arquitectura del flujo

La secuencia recomendada es:

  1. Construir y publicar la imagen.
  2. Resolver su digest inmutable.
  3. Generar el SBOM desde ese digest.
  4. Validar y escanear el documento.
  5. Conservarlo junto al release o como artefacto OCI.
  6. Reescanearlo cuando se actualice la información de vulnerabilidades.

Una etiqueta como app:latest o app:abc123 puede moverse. El digest sha256:..., en cambio, identifica el manifiesto publicado y permite demostrar qué imagen se analizó.

Paso 1: construir una imagen trazable

Utiliza el commit como etiqueta operativa, publica la imagen y consulta después el digest registrado:

export IMAGE_REPO="registry.ejemplo.com/equipo/app"
export IMAGE_TAG="${IMAGE_REPO}:${GIT_SHA}"

docker buildx build \
 --push \
 --tag "$IMAGE_TAG" \.

Resuelve el digest desde el registry:

IMAGE_DIGEST="$(
 docker buildx imagetools inspect "$IMAGE_TAG" \
 --format '{{json.Manifest}}' |
 jq -r '.digest'
)"

case "$IMAGE_DIGEST" in
 sha256:*);;
 *) echo "No se pudo resolver el digest" >&2; exit 1;;
esac

IMAGE_REF="${IMAGE_REPO}@${IMAGE_DIGEST}"
printf '%s\n' "$IMAGE_REF" > image-reference.txt

docker buildx imagetools inspect permite consultar el manifiesto publicado y formatear sus datos como JSON. Documentación de Docker.

En imágenes multiarch, el digest superior puede representar un índice con varios manifiestos. Genera y conserva un SBOM por plataforma, usando por ejemplo --platform linux/amd64, o documenta claramente qué manifiesto se analizó.

Paso 2: generar el SBOM en CycloneDX

Crea un nombre que incorpore el digest:

DIGEST_ID="${IMAGE_DIGEST#sha256:}"
SBOM_FILE="sbom-${DIGEST_ID}.cdx.json"

trivy image \
 --format cyclonedx \
 --output "$SBOM_FILE" \
 "$IMAGE_REF"

El formato CycloneDX generado de esta manera contiene el inventario, pero no incluye vulnerabilidades de forma predeterminada. Trivy separa así el SBOM estable de los resultados que cambian con cada actualización de su base de datos. Generación de SBOM con Trivy.

Para SPDX en JSON, utiliza:

trivy image \
 --format spdx-json \
 --output "sbom-${DIGEST_ID}.spdx.json" \
 "$IMAGE_REF"

No es necesario publicar ambos formatos salvo que exista un requisito de interoperabilidad o auditoría.

Paso 3: validar el documento antes de publicarlo

Comprueba que el archivo sea CycloneDX, contenga componentes y haga referencia al digest esperado:

jq -e \
 --arg digest "$IMAGE_DIGEST" '.bomFormat == "CycloneDX"
 and ((.components // []) | length > 0)
 and ([.. | strings] | any(contains($digest)))
 ' "$SBOM_FILE"

Genera además un checksum para detectar modificaciones posteriores:

sha256sum "$SBOM_FILE" > "${SBOM_FILE}.sha256"
sha256sum --check "${SBOM_FILE}.sha256"

Una validación satisfactoria demuestra que el archivo es legible y está asociado a la imagen, pero no garantiza que Trivy haya reconocido todos los componentes.

Paso 4: escanear el SBOM y aplicar la política

Trivy detecta automáticamente SBOM CycloneDX y SPDX. El escaneo de vulnerabilidades se activa de forma predeterminada para el subcomando sbom. Formatos de entrada admitidos.

El siguiente ejemplo genera un informe JSON y bloquea el pipeline si encuentra vulnerabilidades HIGH o CRITICAL:

trivy sbom \
 --scanners vuln \
 --severity HIGH,CRITICAL \
 --exit-code 1 \
 --format json \
 --output trivy-results.json \
 "$SBOM_FILE"

Sin --exit-code 1, Trivy puede informar vulnerabilidades y finalizar correctamente, por lo que el pipeline continuaría. La opción está documentada como el código que debe devolverse cuando se encuentran problemas de seguridad. Referencia de la CLI de Trivy.

Define explícitamente en la política:

  • Qué severidades bloquean el release.
  • Si se consideran vulnerabilidades sin corrección disponible.
  • Qué fuente de severidad tiene prioridad.
  • Cómo se documentan excepciones, responsables y vencimientos.

No agregues --ignore-unfixed de forma automática: reduce ruido, pero también puede ocultar riesgos que todavía requieren mitigaciones.

Paso 5: conservar la evidencia del release

En GitHub Actions, sube el SBOM, su checksum, la referencia de imagen y el resultado del escaneo incluso cuando la política bloquee el job:

- name: Publicar evidencia SBOM
 if: always()
 uses: actions/upload-artifact@v7
 with:
 name: sbom-${{ github.sha }}
 path: |
 sbom-*.cdx.json
 sbom-*.cdx.json.sha256
 image-reference.txt
 trivy-results.json
 if-no-files-found: error
 retention-days: 90

upload-artifact también calcula un SHA-256 del artefacto subido. Su documentación expone ese valor mediante artifact-digest. Acción oficial de GitHub.

Los artefactos de Actions no deben considerarse almacenamiento permanente. GitHub utiliza 90 días de forma predeterminada; los repositorios públicos admiten hasta 90 días y los privados hasta 400, sujetos a las restricciones de la organización. Política de retención de GitHub.

Para una conservación más duradera, adjunta el SBOM al release o publícalo en un registro OCI compatible con referrers y firmas. Trivy puede descubrir SBOM asociados a imágenes mediante un registro OCI. SBOM en registros OCI.

Paso 6: reescanear ante nuevas vulnerabilidades

El valor del SBOM histórico es que puede reevaluarse con datos de vulnerabilidades nuevos sin volver a descargar y analizar todas las capas.

Actualiza la base una vez:

trivy image --download-db-only

Después recorre los SBOM conservados:

status=0

while IFS= read -r -d '' file; do
 trivy sbom \
 --skip-db-update \
 --scanners vuln \
 --severity CRITICAL \
 --exit-code 1 \
 "$file" || status=1
done < <(
 find sboms -type f \
 \( -name '*.cdx.json' -o -name '*.spdx.json' \) \
 -print0
)

exit "$status"

Trivy descarga y mantiene automáticamente sus bases de vulnerabilidades. --skip-db-update es apropiado aquí porque la base ya se actualizó antes del bucle. Gestión de bases de datos de Trivy.

Registra como resultado, al menos:

  • Digest y release afectados.
  • CVE detectada y severidad utilizada.
  • Paquete y versión instalada.
  • Versión corregida, cuando exista.
  • Decisión: corregir, mitigar, aceptar temporalmente o descartar.

Pruebas de funcionamiento

Antes de aplicar el bloqueo en producción:

  1. Genera un SBOM de una imagen conocida.
  2. Confirma que contiene paquetes del sistema y dependencias del lenguaje esperadas.
  3. Verifica que el digest aparezca en el documento.
  4. Ejecuta una prueba que encuentre una vulnerabilidad conocida.
  5. Confirma que --exit-code 1 bloquee el job.
  6. Comprueba que if: always() conserve la evidencia.
  7. Descarga el artefacto y valida su checksum.
  8. Ensaya el reescaneo con una copia archivada.

Activa primero el escaneo en modo informativo. Aplica el bloqueo cuando el equipo haya definido responsables, excepciones y tiempos de corrección.

Problemas frecuentes

El SBOM está incompleto

Trivy detecta paquetes del sistema, gestores conocidos y determinados binarios con metadatos incorporados. Los componentes compilados manualmente o copiados sin información de versión pueden no aparecer.

Revisa también los archivos de bloqueo y conserva un inventario separado de componentes propios. Las dependencias presentes solo en etapas intermedias del Dockerfile no forman parte necesariamente de la imagen final.

El digest del SBOM no coincide

Probablemente la etiqueta fue actualizada entre la publicación y el análisis. Resuelve el digest inmediatamente después del push y utiliza repositorio@sha256:... en todos los pasos posteriores.

El escaneo no bloquea el pipeline

Agrega --exit-code 1 y verifica que la severidad filtrada coincida con la vulnerabilidad encontrada.

El reescaneo produce resultados diferentes

Es esperable cuando cambia la base de vulnerabilidades o la fuente de severidad. Registra la versión de Trivy, la fecha del análisis y las fuentes utilizadas para reproducir la decisión.

Aparecen demasiados hallazgos

Prioriza por severidad, exposición, disponibilidad de corrección y alcance real. Las excepciones deben incluir motivo, responsable y fecha de vencimiento; evita listas de ignorados permanentes sin contexto.

Buenas prácticas para producción

  • Publica un SBOM por imagen, digest y plataforma.
  • No uses etiquetas mutables como identidad del análisis.
  • Fija la versión de Trivy y las acciones del pipeline.
  • Conserva SBOM, checksum, referencia de imagen y resultado del escaneo.
  • Firma o atestigua los SBOM utilizados como evidencia.
  • Restringe el acceso si el documento revela nombres de paquetes, rutas o componentes internos.
  • Automatiza el reescaneo periódico con una base actualizada.
  • Documenta excepciones mediante una política revisable o VEX
  • Reconstruye la imagen corregida; no modifiques el SBOM para ocultar componentes.

Cloud Serversby Donweb

Todo el poder de la nube a tus proyectos y aplicaciones.
Alojamiento ultra rápido, escalable y con alta disponibilidad.

  • Performance que te sorprenderá
  • Rápida escalabilidad y sin limitaciones
  • Arquitectura de alta disponibilidad
  • Soporte experto y ejecutivos de cuenta
  • Pagos en tu moneda y facturación local

Descubre la mejor solución de Cloud Hosting