Lab: Construcción de un Pipeline de SBOM — Generar, Atestar y Verificar con Syft y Cosign

Descripción General

Los Software Bills of Materials (SBOMs) se están convirtiendo rápidamente en un componente obligatorio de la transparencia en la cadena de suministro de software. Órdenes ejecutivas, marcos regulatorios como NIST SSDF y estándares de la industria ahora requieren que las organizaciones produzcan, distribuyan y verifiquen SBOMs para cada lanzamiento de software. Un SBOM enumera cada componente, biblioteca y dependencia dentro de tu software — brindando a los consumidores la capacidad de evaluar riesgos, rastrear vulnerabilidades y verificar la procedencia.

En este laboratorio práctico, construirás un pipeline completo de SBOM desde cero. Al finalizar, serás capaz de:

  • Generar SBOMs en formatos SPDX y CycloneDX usando Syft
  • Escanear SBOMs en busca de vulnerabilidades conocidas usando Grype
  • Adjuntar SBOMs como attestations firmadas a imágenes de contenedores usando Cosign
  • Automatizar todo el flujo de trabajo en GitHub Actions y GitLab CI
  • Aplicar requisitos de attestation de SBOM en el despliegue usando Kyverno
  • Comparar SBOMs entre versiones para detectar cambios en las dependencias

Este laboratorio refleja flujos de trabajo de producción reales utilizados por equipos que adoptan SLSA, in-toto y seguridad de cadena de suministro basada en Sigstore.

Prerrequisitos

Antes de comenzar, asegúrate de tener las siguientes herramientas instaladas y configuradas:

Herramienta Propósito Instalación
Syft Generación de SBOM curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
Grype Escaneo de vulnerabilidades curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
Cosign Firma y attestation go install github.com/sigstore/cosign/v2/cmd/cosign@latest
Docker Construcción de contenedores docs.docker.com
GitHub CLI (gh) Acceso al repositorio y GHCR brew install gh o cli.github.com

También necesitas una cuenta de GitHub con acceso a GitHub Container Registry (GHCR), y una aplicación básica con un Dockerfile.

Configuración del Entorno

Crearemos una aplicación mínima de Node.js, la contenedorizaremos y la subiremos a GHCR. Esta imagen se convierte en el objetivo de todos los ejercicios posteriores de SBOM.

Paso 1: Crear el repositorio de prueba

mkdir sbom-pipeline-lab && cd sbom-pipeline-lab
git init

Paso 2: Crear una aplicación simple de Node.js

cat > package.json <<'EOF'
{
  "name": "sbom-lab-app",
  "version": "1.0.0",
  "description": "SBOM pipeline lab application",
  "main": "server.js",
  "dependencies": {
    "express": "^4.18.2",
    "lodash": "^4.17.21",
    "axios": "^1.6.0"
  }
}
EOF
cat > server.js <<'EOF'
const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.json({ status: 'ok', message: 'SBOM Pipeline Lab' });
});

app.listen(3000, () => console.log('Listening on port 3000'));
EOF

Paso 3: Crear el Dockerfile

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Paso 4: Construir y subir la imagen del contenedor

# Authenticate to GHCR
echo $GITHUB_TOKEN | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin

# Build the image
docker build -t ghcr.io/YOUR_GITHUB_USERNAME/sbom-lab-app:v1.0.0 .

# Push to GHCR
docker push ghcr.io/YOUR_GITHUB_USERNAME/sbom-lab-app:v1.0.0

Reemplaza YOUR_GITHUB_USERNAME con tu nombre de usuario real de GitHub a lo largo de este laboratorio. Una vez completada la subida, anota el digest completo de la imagen — lo necesitarás para las operaciones de firma.

# Capture the image digest
export IMAGE=$(docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/YOUR_GITHUB_USERNAME/sbom-lab-app:v1.0.0)
echo $IMAGE
# Output: ghcr.io/YOUR_GITHUB_USERNAME/sbom-lab-app@sha256:abc123...

Ejercicio 1: Generar SBOM con Syft

Syft es una herramienta de código abierto de Anchore que genera SBOMs analizando imágenes de contenedores, sistemas de archivos y archivos comprimidos. Soporta múltiples formatos de salida incluyendo SPDX y CycloneDX — los dos estándares de SBOM dominantes.

Generar un SBOM en formato SPDX

syft $IMAGE -o spdx-json=sbom.spdx.json

Inspecciona la salida:

cat sbom.spdx.json | jq '.packages | length'
# Output: 287 (count varies based on image content)

# View detected packages
cat sbom.spdx.json | jq '.packages[] | {name: .name, version: .versionInfo, license: .licenseDeclared}' | head -40

Generar un SBOM en formato CycloneDX

syft $IMAGE -o cyclonedx-json=sbom.cyclonedx.json

Inspecciona la salida de CycloneDX:

cat sbom.cyclonedx.json | jq '.components | length'

# View components with licenses
cat sbom.cyclonedx.json | jq '.components[] | {name: .name, version: .version, type: .type}' | head -40

SPDX vs. CycloneDX: Diferencias Clave

Característica SPDX CycloneDX
Origen Linux Foundation OWASP
Enfoque Principal Cumplimiento de licencias y PI Seguridad y análisis de riesgos
Estándar ISO ISO/IEC 5962:2021 ECMA-424
Datos de Vulnerabilidades Soporte nativo limitado Campo vulnerabilities de primera clase
Formatos JSON, RDF, XML, YAML, tag-value JSON, XML, Protobuf
Mejor Para Cumplimiento regulatorio, auditorías de licencias DevSecOps, seguimiento de vulnerabilidades

Para este laboratorio, usamos principalmente SPDX JSON porque es el formato requerido por muchos estándares de adquisición gubernamental y se integra bien con las attestations de Cosign. Sin embargo, ambos formatos son compatibles con Grype y Cosign.

Generar un resumen legible por humanos

syft $IMAGE -o syft-table

Esto imprime una tabla de todos los paquetes con nombre, versión y tipo — útil para una revisión rápida durante el desarrollo.

Ejercicio 2: Escanear SBOM en Busca de Vulnerabilidades con Grype

Grype es el escáner de vulnerabilidades de Anchore. Puede escanear imágenes de contenedores directamente, pero también puede escanear un archivo SBOM — lo cual es significativamente más rápido porque omite el paso de análisis de la imagen.

Escanear el SBOM

grype sbom:./sbom.spdx.json

Salida de ejemplo:

NAME          INSTALLED  FIXED-IN   TYPE  VULNERABILITY   SEVERITY
lodash        4.17.21               npm   CVE-2025-XXXXX  Medium
node          20.10.0    20.11.1    apk   CVE-2024-22019  High
libcrypto3    3.1.4-r1   3.1.4-r3   apk   CVE-2024-0727   Medium

Filtrar por severidad

# Show only Critical and High vulnerabilities
grype sbom:./sbom.spdx.json --fail-on critical

# Output results in JSON for CI processing
grype sbom:./sbom.spdx.json -o json > vulnerabilities.json

# Count vulnerabilities by severity
cat vulnerabilities.json | jq '[.matches[].vulnerability.severity] | group_by(.) | map({severity: .[0], count: length})'

Escaneo de imagen vs. escaneo de SBOM

Existe una distinción importante entre escanear la imagen directamente y escanear el SBOM:

# Direct image scan — Grype pulls and analyzes the image layers
grype $IMAGE

# SBOM scan — Grype reads the pre-generated package list
grype sbom:./sbom.spdx.json
Enfoque Velocidad Precisión Caso de Uso
Escaneo directo de imagen Más lento (descarga capas) Descubre todos los paquetes Primer análisis, desarrollo local
Escaneo de SBOM Rápido (lee archivo JSON) Limitado al contenido del SBOM Pipelines de CI, escaneos repetidos, auditoría

El escaneo de SBOM es tan completo como el propio SBOM. Si Syft omitió un paquete (por ejemplo, un binario compilado estáticamente), Grype no encontrará vulnerabilidades para él. Para máxima cobertura, genera el SBOM con la opción --catalogers all de Syft.

Ejercicio 3: Adjuntar SBOM como Attestation de Cosign

Una attestation es una declaración firmada sobre un artefacto de software. Al adjuntar el SBOM como attestation, vinculas criptográficamente el SBOM al digest específico de la imagen — cualquiera puede verificar que el SBOM fue producido para esa imagen exacta y no ha sido alterado.

Adjuntar la attestation del SBOM

Usando el flujo keyless (Sigstore Fulcio) de Cosign:

cosign attest --predicate sbom.spdx.json \
  --type spdxjson \
  --yes \
  $IMAGE

Este comando:

  1. Abre un navegador para autenticación OIDC (firma keyless vía Fulcio)
  2. Crea una attestation in-toto con tu SBOM como predicado
  3. Firma la attestation y la registra en el log de transparencia Rekor
  4. Sube la attestation al registry junto con la imagen

Verificar la attestation

cosign verify-attestation \
  --type spdxjson \
  --certificate-identity=YOUR_EMAIL@example.com \
  --certificate-oidc-issuer=https://accounts.google.com \
  $IMAGE | jq '.payload | @base64d | fromjson | .predicate'

Reemplaza la identidad del certificado y el emisor OIDC con los valores que correspondan a tu identidad de Sigstore. En entornos de CI (GitHub Actions), estos serían:

--certificate-identity=https://github.com/YOUR_ORG/YOUR_REPO/.github/workflows/build.yml@refs/heads/main
--certificate-oidc-issuer=https://token.actions.githubusercontent.com

Inspeccionar la attestation en el registry

# List referrers (OCI 1.1 registries)
cosign tree $IMAGE

Deberías ver la attestation listada como un referrer adjunto al manifiesto de la imagen. La attestation se almacena como un artefacto OCI en el mismo repositorio, etiquetada con la convención sha256-<digest>.att.

Ejercicio 4: Construir el Pipeline Completo en GitHub Actions

Ahora automatizamos todo en un único flujo de trabajo de CI/CD. Este pipeline construye la imagen, genera el SBOM, escanea vulnerabilidades y adjunta el SBOM como una attestation firmada.

Crea .github/workflows/sbom-pipeline.yml:

name: SBOM Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

permissions:
  contents: read
  packages: write
  id-token: write  # Required for Cosign keyless signing
  attestations: write

jobs:
  build-and-attest:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to GHCR
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push image
        id: build
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

      - name: Get image digest
        id: digest
        run: |
          echo "image=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}" >> $GITHUB_OUTPUT

      - name: Install Syft
        uses: anchore/sbom-action/download-syft@v0

      - name: Generate SPDX SBOM
        run: |
          syft ${{ steps.digest.outputs.image }} -o spdx-json=sbom.spdx.json
          echo "### SBOM Summary" >> $GITHUB_STEP_SUMMARY
          echo "Package count: $(cat sbom.spdx.json | jq '.packages | length')" >> $GITHUB_STEP_SUMMARY

      - name: Install Grype
        uses: anchore/scan-action/download-grype@v4

      - name: Scan SBOM for vulnerabilities
        run: |
          grype sbom:./sbom.spdx.json -o json > vulnerabilities.json
          grype sbom:./sbom.spdx.json -o table >> $GITHUB_STEP_SUMMARY

          # Fail if critical vulnerabilities are found
          CRITICAL_COUNT=$(cat vulnerabilities.json | jq '[.matches[] | select(.vulnerability.severity=="Critical")] | length')
          echo "Critical vulnerabilities: $CRITICAL_COUNT"
          if [ "$CRITICAL_COUNT" -gt 0 ]; then
            echo "::error::Found $CRITICAL_COUNT critical vulnerabilities. Failing pipeline."
            exit 1
          fi

      - name: Install Cosign
        uses: sigstore/cosign-installer@v3

      - name: Attest SBOM
        run: |
          cosign attest --predicate sbom.spdx.json \
            --type spdxjson \
            --yes \
            ${{ steps.digest.outputs.image }}

      - name: Verify attestation
        run: |
          cosign verify-attestation \
            --type spdxjson \
            --certificate-identity-regexp="https://github.com/${{ github.repository }}/" \
            --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
            ${{ steps.digest.outputs.image }}

      - name: Upload SBOM as artifact
        uses: actions/upload-artifact@v4
        with:
          name: sbom-spdx
          path: sbom.spdx.json
          retention-days: 90

      - name: Upload vulnerability report
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: vulnerability-report
          path: vulnerabilities.json
          retention-days: 90

Este flujo de trabajo utiliza firma keyless mediante la identidad OIDC de GitHub Actions. No se almacenan claves privadas en los secrets — Cosign obtiene un certificado de corta duración de la CA Fulcio de Sigstore, y el evento de firma se registra en el log de transparencia Rekor.

El pipeline falla si se detectan vulnerabilidades críticas. Ajusta el umbral cambiando el filtro de severidad en el paso de escaneo de Grype.

Ejercicio 5: Construir el Pipeline en GitLab CI

El pipeline equivalente en GitLab CI utiliza las mismas herramientas pero se adapta al modelo basado en stages de GitLab y su registry de contenedores integrado.

Crea .gitlab-ci.yml:

stages:
  - build
  - sbom
  - scan
  - attest

variables:
  IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  IMAGE_DIGEST: ""

build:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $IMAGE .
    - docker push $IMAGE
    - |
      DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' $IMAGE)
      echo "IMAGE_DIGEST=$DIGEST" >> build.env
  artifacts:
    reports:
      dotenv: build.env

generate-sbom:
  stage: sbom
  image: alpine:3.19
  needs: [build]
  before_script:
    - apk add --no-cache curl jq
    - curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
  script:
    - syft $IMAGE_DIGEST -o spdx-json=sbom.spdx.json
    - echo "Package count:" $(cat sbom.spdx.json | jq '.packages | length')
  artifacts:
    paths:
      - sbom.spdx.json
    expire_in: 90 days

scan-vulnerabilities:
  stage: scan
  image: alpine:3.19
  needs: [generate-sbom]
  before_script:
    - apk add --no-cache curl jq
    - curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
  script:
    - grype sbom:./sbom.spdx.json -o json > vulnerabilities.json
    - grype sbom:./sbom.spdx.json -o table
    - |
      CRITICAL_COUNT=$(cat vulnerabilities.json | jq '[.matches[] | select(.vulnerability.severity=="Critical")] | length')
      echo "Critical vulnerabilities found: $CRITICAL_COUNT"
      if [ "$CRITICAL_COUNT" -gt 0 ]; then
        echo "ERROR: Critical vulnerabilities detected. Failing pipeline."
        exit 1
      fi
  artifacts:
    paths:
      - vulnerabilities.json
    expire_in: 90 days
    when: always

attest-sbom:
  stage: attest
  image: alpine:3.19
  needs: [build, generate-sbom, scan-vulnerabilities]
  id_tokens:
    SIGSTORE_ID_TOKEN:
      aud: sigstore
  before_script:
    - apk add --no-cache curl
    - curl -sSfL https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64 -o /usr/local/bin/cosign
    - chmod +x /usr/local/bin/cosign
  script:
    - cosign attest --predicate sbom.spdx.json
        --type spdxjson
        --yes
        $IMAGE_DIGEST
    - cosign verify-attestation
        --type spdxjson
        --certificate-identity-regexp="https://gitlab.com/$CI_PROJECT_PATH//"
        --certificate-oidc-issuer=https://gitlab.com
        $IMAGE_DIGEST

Diferencias clave con respecto a la versión de GitHub Actions:

  • GitLab utiliza stages en lugar de un solo job con steps
  • El digest de la imagen se pasa entre stages mediante artefactos dotenv
  • El token OIDC de GitLab se expone a través de id_tokens y la variable SIGSTORE_ID_TOKEN
  • El emisor OIDC para verificación es https://gitlab.com

Ejercicio 6: Verificar SBOM en el Despliegue

Generar y atestar SBOMs es solo la mitad de la historia. El verdadero beneficio de seguridad viene de aplicar la verificación en el momento del despliegue — rechazando cualquier imagen que carezca de una attestation de SBOM válida.

Opción A: Verificar en un script de despliegue

#!/bin/bash
# deploy.sh — Verify SBOM attestation before deploying
set -euo pipefail

IMAGE="$1"

echo "Verifying SBOM attestation for: $IMAGE"

cosign verify-attestation \
  --type spdxjson \
  --certificate-identity-regexp="https://github.com/YOUR_ORG/YOUR_REPO/" \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
  "$IMAGE" > /dev/null 2>&1

if [ $? -eq 0 ]; then
  echo "SBOM attestation verified successfully."
  kubectl set image deployment/myapp myapp="$IMAGE"
else
  echo "ERROR: SBOM attestation verification failed. Deployment blocked."
  exit 1
fi

Opción B: Aplicar con Kyverno en Kubernetes

Kyverno es un motor de políticas nativo de Kubernetes que puede verificar firmas de imágenes y attestations en el momento de admisión. La siguiente política rechaza cualquier pod cuya imagen carezca de una attestation de SBOM válida.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-sbom-attestation
spec:
  validationFailureAction: Enforce
  webhookTimeoutSeconds: 30
  rules:
    - name: check-sbom-attestation
      match:
        any:
          - resources:
              kinds:
                - Pod
      verifyImages:
        - imageReferences:
            - "ghcr.io/YOUR_ORG/*"
          attestations:
            - type: spdxjson
              attestors:
                - entries:
                    - keyless:
                        subject: "https://github.com/YOUR_ORG/YOUR_REPO/.github/workflows/sbom-pipeline.yml@refs/heads/main"
                        issuer: "https://token.actions.githubusercontent.com"
                        rekor:
                          url: https://rekor.sigstore.dev
              conditions:
                - all:
                    - key: "{{ len(spdxVersion) }}"
                      operator: GreaterThan
                      value: "0"

Aplica la política:

kubectl apply -f require-sbom-attestation.yaml

Prueba de admisión: imagen con attestation

# This should be ADMITTED
kubectl run test-admitted \
  --image=ghcr.io/YOUR_ORG/sbom-lab-app@sha256:abc123... \
  --restart=Never

# Expected output:
# pod/test-admitted created

Prueba de admisión: imagen sin attestation

# This should be REJECTED
kubectl run test-rejected \
  --image=ghcr.io/YOUR_ORG/sbom-lab-app:unattested \
  --restart=Never

# Expected output:
# Error from server: admission webhook "mutate.kyverno.svc-fail" denied the request:
# resource Pod/default/test-rejected was blocked due to the following policies:
# require-sbom-attestation:
#   check-sbom-attestation: 'image verification failed for ghcr.io/YOUR_ORG/sbom-lab-app:unattested:
#     attestation spdxjson not found'

Este es el bucle de aplicación que hace que los SBOMs sean operacionalmente significativos — sin verificación en el despliegue, la generación de SBOM es solo documentación.

Ejercicio 7: Diferencias de SBOM Entre Versiones

Cuando lanzas una nueva versión, necesitas entender qué cambió en tu árbol de dependencias. Comparar SBOMs entre versiones revela paquetes añadidos, eliminados y actualizados — información crítica para evaluar nuevos riesgos.

Paso 1: Generar SBOMs para dos versiones

# Generate SBOM for v1.0.0
syft ghcr.io/YOUR_GITHUB_USERNAME/sbom-lab-app:v1.0.0 -o spdx-json=sbom-v1.spdx.json

# Generate SBOM for v1.1.0 (after updating dependencies)
syft ghcr.io/YOUR_GITHUB_USERNAME/sbom-lab-app:v1.1.0 -o spdx-json=sbom-v2.spdx.json

Paso 2: Extraer listas de paquetes

# Extract sorted package lists
cat sbom-v1.spdx.json | jq -r '.packages[] | "\(.name)@\(.versionInfo)"' | sort > packages-v1.txt
cat sbom-v2.spdx.json | jq -r '.packages[] | "\(.name)@\(.versionInfo)"' | sort > packages-v2.txt

Paso 3: Comparar las listas de paquetes

diff --unified packages-v1.txt packages-v2.txt

Salida de ejemplo:

--- packages-v1.txt
+++ packages-v2.txt
@@ -12,7 +12,8 @@
  express@4.18.2
  lodash@4.17.21
- axios@1.6.0
+ axios@1.7.2
+ helmet@7.1.0
  mime-types@2.1.35

Paso 4: Identificar vulnerabilidades recién introducidas

# Scan only the new/changed packages
grype sbom:./sbom-v2.spdx.json -o json > vulns-v2.json
grype sbom:./sbom-v1.spdx.json -o json > vulns-v1.json

# Compare vulnerability counts
echo "v1.0.0 vulnerabilities: $(cat vulns-v1.json | jq '.matches | length')"
echo "v1.1.0 vulnerabilities: $(cat vulns-v2.json | jq '.matches | length')"

# Find NEW vulnerabilities in v1.1.0
comm -13 \
  <(cat vulns-v1.json | jq -r '.matches[].vulnerability.id' | sort -u) \
  <(cat vulns-v2.json | jq -r '.matches[].vulnerability.id' | sort -u)

Este proceso de comparación se puede automatizar en CI para comentar en pull requests con los cambios de dependencias, dando a los revisores visibilidad sobre el impacto en la cadena de suministro antes de fusionar.

Limpieza

Elimina los recursos creados durante este laboratorio:

# Delete local files
rm -f sbom.spdx.json sbom.cyclonedx.json vulnerabilities.json
rm -f sbom-v1.spdx.json sbom-v2.spdx.json packages-v1.txt packages-v2.txt
rm -f vulns-v1.json vulns-v2.json

# Remove the test image from GHCR (requires gh CLI)
gh api -X DELETE /user/packages/container/sbom-lab-app/versions/PACKAGE_VERSION_ID

# Remove the Kyverno policy
kubectl delete clusterpolicy require-sbom-attestation

# Remove the test pods
kubectl delete pod test-admitted test-rejected --ignore-not-found

# Remove the local repository
cd .. && rm -rf sbom-pipeline-lab

Conclusiones Clave

  • Los SBOMs son una base para la seguridad de la cadena de suministro — proporcionan el inventario que permite el escaneo de vulnerabilidades, el cumplimiento de licencias y la verificación de procedencia.
  • Syft genera SBOMs en todos los formatos principales — SPDX para cumplimiento regulatorio, CycloneDX para flujos de trabajo de seguridad, ambos compatibles en todo el ecosistema.
  • Escanear el SBOM es más rápido que escanear la imagen — usa Grype con el prefijo sbom: en pipelines de CI para ciclos de retroalimentación rápidos sin descargar capas de imagen.
  • Las attestations de Cosign vinculan criptográficamente los SBOMs a las imágenes — las attestations firmadas demuestran que un SBOM específico fue producido para un digest de imagen específico, almacenado en el registry junto a la imagen.
  • La verificación en el despliegue es lo que hace que los SBOMs sean aplicables — sin control de admisión (Kyverno, OPA Gatekeeper o scripts de despliegue), los SBOMs permanecen como documentación sin fuerza.
  • Las comparaciones de SBOM revelan cambios en la cadena de suministro entre versiones — automatizar la comparación de dependencias en CI da a los equipos visibilidad sobre nuevos riesgos antes de que el código llegue a producción.

Próximos Pasos

Continúa construyendo tu práctica de seguridad de cadena de suministro con estas guías relacionadas: