Descripción General
SLSA (Supply-chain Levels for Software Artifacts) provenance es un registro verificable que describe cómo se construyó un artefacto: el repositorio fuente, la plataforma de compilación, el punto de entrada y los materiales de entrada. Cuando se adjunta a una imagen de contenedor, el provenance permite a los consumidores responder una pregunta crítica antes del despliegue: «¿Esta imagen fue realmente construida a partir del código fuente que espero, en una plataforma en la que confío?»
En este laboratorio práctico usted:
- Construirá y publicará una imagen de contenedor en GitHub Container Registry (GHCR).
- Generará provenance de SLSA Level 3 utilizando el reusable workflow oficial
slsa-github-generator. - Generará provenance utilizando las artifact attestations nativas de GitHub (
actions/attest-build-provenance). - Verificará el provenance con
slsa-verifier,cosignygh attestation verify. - Aplicará el provenance en tiempo de despliegue con una política de admisión de Kubernetes.
Al finalizar este laboratorio, tendrá un pipeline completo y reproducible que demuestra la integridad de cada imagen de contenedor que distribuye.
Requisitos Previos
Antes de comenzar, asegúrese de tener lo siguiente:
- Cuenta de GitHub con un repositorio de prueba (público o privado con GitHub Pro/Team/Enterprise).
- Acceso a GHCR — su cuenta de GitHub puede publicar en
ghcr.iopor defecto; confírmelo navegando a Settings → Packages. - Cosign CLI instalado localmente:
# macOS brew install cosign # Linux / other go install github.com/sigstore/cosign/v2/cmd/cosign@latest - slsa-verifier CLI instalado:
go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@latest - GitHub CLI (
gh) versión 2.49 o posterior (para los comandosgh attestation). - Docker instalado y en ejecución.
- kubectl con acceso a un clúster de Kubernetes de prueba (para el ejercicio de aplicación de políticas).
Configuración del Entorno
Paso 1 — Crear el Repositorio de Prueba
Cree un nuevo repositorio de GitHub llamado slsa-provenance-lab. Clónelo localmente y agregue los siguientes archivos.
main.go
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from SLSA provenance lab!")
})
fmt.Println("Server starting on :8080")
http.ListenAndServe(":8080", nil)
}
go.mod
module github.com/YOUR_USER/slsa-provenance-lab
go 1.22
Dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod ./
COPY main.go ./
RUN go build -o server .
FROM alpine:3.19
RUN apk --no-cache add ca-certificates
COPY --from=builder /app/server /server
ENTRYPOINT ["/server"]
Paso 2 — Confirmar el Acceso a GHCR
Autentique Docker con GHCR para poder publicar imágenes:
echo $GITHUB_TOKEN | docker login ghcr.io -u YOUR_USER --password-stdin
Reemplace YOUR_USER con su nombre de usuario de GitHub y GITHUB_TOKEN con un token de acceso personal que tenga el alcance write:packages.
Paso 3 — Workflow Base de Build-and-Push (Sin Provenance)
Cree .github/workflows/build.yml para verificar que la imagen se construye y publica correctamente antes de agregar provenance:
name: Build and Push (baseline)
on:
push:
tags:
- "v*"
env:
IMAGE: ghcr.io/${{ github.repository_owner }}/slsa-provenance-lab
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
${{ env.IMAGE }}:${{ github.ref_name }}
${{ env.IMAGE }}:latest
Publique un tag de prueba para verificar:
git add -A
git commit -m "baseline build workflow"
git tag v0.1.0
git push origin main --tags
Confirme que la imagen aparece en ghcr.io/YOUR_USER/slsa-provenance-lab:v0.1.0 antes de continuar.
Ejercicio 1: Generar SLSA Provenance con slsa-github-generator
Por Qué slsa-github-generator Alcanza SLSA Level 3
La propiedad clave de SLSA Build Level 3 es que el provenance es generado por una plataforma de compilación que el desarrollador no puede influenciar. El slsa-github-generator logra esto ejecutándose como un reusable workflow alojado en un repositorio separado. Dado que GitHub Actions aísla las ejecuciones de reusable workflows del workflow que los invoca, el paso de generación de provenance está protegido contra manipulaciones — incluso un job de compilación comprometido no puede alterar la salida del provenance.
El Workflow
Cree .github/workflows/slsa-provenance.yml:
name: Build + SLSA Provenance (slsa-github-generator)
on:
push:
tags:
- "v*"
env:
IMAGE: ghcr.io/${{ github.repository_owner }}/slsa-provenance-lab
jobs:
# --- Job 1: Build and push the container image ---
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
image: ${{ env.IMAGE }}
digest: ${{ steps.push.outputs.digest }}
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
${{ env.IMAGE }}:${{ github.ref_name }}
${{ env.IMAGE }}:latest
# --- Job 2: Generate SLSA Level 3 provenance ---
provenance:
needs: build
permissions:
actions: read
id-token: write
packages: write
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0
with:
image: ${{ needs.build.outputs.image }}
digest: ${{ needs.build.outputs.digest }}
secrets:
registry-username: ${{ github.actor }}
registry-password: ${{ secrets.GITHUB_TOKEN }}
Comprensión del Workflow
- El job build construye la imagen, la publica en GHCR y produce como salida la referencia de la imagen y el digest.
- El job provenance invoca el reusable workflow del repositorio
slsa-framework/slsa-github-generatoren un tag fijado (@v2.1.0). Dado que este workflow se ejecuta en un entorno aislado controlado por los mantenedores del framework SLSA, cumple con el requisito de SLSA Level 3 de una plataforma de compilación reforzada y no falsificable. - El provenance se firma utilizando la firma sin claves de Sigstore (certificado Fulcio + registro de transparencia Rekor) y se adjunta a la imagen en GHCR como una attestation de cosign.
Ejecutar el Workflow
git add .github/workflows/slsa-provenance.yml
git commit -m "add SLSA provenance workflow"
git tag v1.0.0
git push origin main --tags
En la pestaña Actions verá dos jobs: build y provenance. El job de provenance genera una attestation in-toto, la firma mediante Sigstore y publica la attestation en GHCR junto con la imagen. Cuando ambos jobs se completan exitosamente, su imagen en ghcr.io/YOUR_USER/slsa-provenance-lab@sha256:<digest> ahora porta una attestation de provenance SLSA Level 3 firmada.
Ejercicio 2: Generar Provenance con GitHub Artifact Attestations
El Enfoque Nativo de GitHub
GitHub proporciona un mecanismo integrado para generar build provenance a través de la action actions/attest-build-provenance. Este enfoque es más sencillo de configurar y almacena las attestations en el almacenamiento de attestations propio de GitHub, haciéndolas verificables con el CLI gh. La contrapartida es que estas attestations siguen la ruta de verificación propia de GitHub en lugar de las herramientas del framework SLSA.
El Workflow
Cree .github/workflows/github-attestation.yml:
name: Build + GitHub Artifact Attestation
on:
push:
tags:
- "v*"
env:
IMAGE: ghcr.io/${{ github.repository_owner }}/slsa-provenance-lab
jobs:
build-and-attest:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
${{ env.IMAGE }}:${{ github.ref_name }}
${{ env.IMAGE }}:latest
- name: Generate artifact attestation
uses: actions/attest-build-provenance@v2
with:
subject-name: ${{ env.IMAGE }}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true
Comparación de los Dos Enfoques
| Aspecto | slsa-github-generator | GitHub Artifact Attestations |
|---|---|---|
| Nivel SLSA | Level 3 (reusable workflow aislado) | Level 2–3 (gestionado por GitHub, workflow único) |
| Herramienta de verificación | slsa-verifier, cosign |
gh attestation verify, cosign |
| Almacenamiento de attestations | Registro OCI (junto a la imagen) | API de attestation de GitHub + publicación OCI opcional |
| Complejidad de configuración | Workflow de dos jobs con llamada a reusable workflow | Workflow de un solo job con un paso adicional |
| Firma | Sigstore (Fulcio + Rekor) | Sigstore (Fulcio + Rekor vía GitHub) |
Ambos enfoques son válidos. Use slsa-github-generator cuando necesite cumplimiento estricto de SLSA Level 3 con verificación multiplataforma. Use GitHub artifact attestations cuando desee una configuración más sencilla y sus consumidores ya utilicen el ecosistema de GitHub.
Ejercicio 3: Verificar Provenance con slsa-verifier
El CLI slsa-verifier es la herramienta oficial para verificar el SLSA provenance generado por slsa-github-generator. Verifica la firma criptográfica, la identidad del builder, el repositorio fuente y el digest del artefacto en un solo comando.
Paso 1 — Obtener el Digest de la Imagen
Obtenga el digest de la imagen que publicó:
IMAGE=ghcr.io/YOUR_USER/slsa-provenance-lab
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE:v1.0.0" | cut -d@ -f2)
echo "$DIGEST"
También puede encontrar el digest en la salida del workflow de Actions o en la página del paquete en GHCR.
Paso 2 — Verificación Exitosa
slsa-verifier verify-image "ghcr.io/YOUR_USER/slsa-provenance-lab@$DIGEST" \
--source-uri github.com/YOUR_USER/slsa-provenance-lab \
--source-tag v1.0.0
Salida esperada:
Verified build using builder "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v2.1.0" at commit abc123def456
VERIFIED: SLSA verification passed
Paso 3 — Fallo de Verificación: URI de Origen Incorrecto
Intente verificar contra un repositorio fuente incorrecto:
slsa-verifier verify-image "ghcr.io/YOUR_USER/slsa-provenance-lab@$DIGEST" \
--source-uri github.com/YOUR_USER/wrong-repo \
--source-tag v1.0.0
Salida esperada:
FAILED: SLSA verification failed: source used to generate the binary does not match provenance
Paso 4 — Fallo de Verificación: Tag Incorrecto
slsa-verifier verify-image "ghcr.io/YOUR_USER/slsa-provenance-lab@$DIGEST" \
--source-uri github.com/YOUR_USER/slsa-provenance-lab \
--source-tag v9.9.9
Salida esperada:
FAILED: SLSA verification failed: tag "v9.9.9" does not match provenance
Qué Verifica slsa-verifier
- Identidad del builder — confirma que el provenance fue creado por el reusable workflow oficial
slsa-github-generatoren la referencia esperada. - Repositorio fuente — el provenance debe hacer referencia al URI fuente que usted especifica.
- Tag/branch fuente — opcionalmente verifica la referencia Git que desencadenó la compilación.
- Digest del artefacto — el digest SHA-256 registrado en el provenance debe coincidir con la imagen que está verificando.
- Firma y registro de transparencia — la firma de Sigstore se verifica contra el registro de transparencia Rekor.
Ejercicio 4: Verificar con cosign verify-attestation
Cosign proporciona una forma de verificar attestations adjuntas a imágenes de contenedores que es de nivel más bajo pero más flexible. Esto es útil cuando necesita inspeccionar el payload de provenance sin procesar o cuando integra en pipelines de verificación personalizados.
Verificar la Attestation
cosign verify-attestation \
--type slsaprovenance \
--certificate-identity-regexp "https://github.com/slsa-framework/slsa-github-generator/" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/YOUR_USER/slsa-provenance-lab@$DIGEST
En caso de éxito, cosign imprime el payload de la attestation en formato JSON. Un ejemplo truncado:
Verification for ghcr.io/YOUR_USER/slsa-provenance-lab@sha256:abc123... --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- Existence of the claims in the transparency log was verified offline
- The code-signing certificate was verified using trusted certificate authority
{
"payloadType": "application/vnd.in-toto+json",
"payload": "eyJfdHlwZSI6Imh0dHBz...",
"signatures": [{ "sig": "MEUCIQD..." }]
}
Inspeccionar el Payload de Provenance
Decodifique el payload en base64 para inspeccionar los campos de provenance:
cosign verify-attestation \
--type slsaprovenance \
--certificate-identity-regexp "https://github.com/slsa-framework/slsa-github-generator/" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/YOUR_USER/slsa-provenance-lab@$DIGEST \
| jq -r '.payload' | base64 -d | jq .
Campos clave en la salida:
buildDefinition.buildType— identifica el sistema de compilación (por ejemplo,https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1).buildDefinition.externalParameters.workflow— el archivo de workflow y la referencia que ejecutó la compilación.buildDefinition.resolvedDependencies— el commit de Git, el repositorio y otras entradas.runDetails.builder.id— el URI del builder de confianza que generó el provenance.
Ejercicio 5: Verificar con gh attestation verify
Para imágenes atestadas utilizando las artifact attestations nativas de GitHub (Ejercicio 2), el CLI gh proporciona la ruta de verificación más sencilla.
Verificar la Attestation
gh attestation verify oci://ghcr.io/YOUR_USER/slsa-provenance-lab@$DIGEST \
--owner YOUR_USER
Salida esperada:
Loaded digest sha256:abc123def456... for oci://ghcr.io/YOUR_USER/slsa-provenance-lab@sha256:abc123...
Loaded 1 attestation from GitHub API
✓ Verification succeeded!
PredicateType: https://slsa.dev/provenance/v1
SubjectName: ghcr.io/YOUR_USER/slsa-provenance-lab
SubjectDigest: sha256:abc123def456...
SignerRepo: YOUR_USER/slsa-provenance-lab
SignerWorkflow: .github/workflows/github-attestation.yml
RunnerEnv: github-hosted
Descargar e Inspeccionar la Attestation
Para descargar el bundle de attestation sin procesar para inspección offline:
gh attestation download oci://ghcr.io/YOUR_USER/slsa-provenance-lab@$DIGEST \
--owner YOUR_USER \
--output attestation-bundle.json
# Inspect the provenance predicate
cat attestation-bundle.json | jq '.dsseEnvelope.payload' -r | base64 -d | jq .
Esto le proporciona el predicado completo de SLSA provenance, que puede almacenar junto con sus registros de despliegue para fines de auditoría.
Ejercicio 6: Aplicar Provenance en el Despliegue
Generar y verificar provenance manualmente es valioso, pero el verdadero beneficio de seguridad proviene de la aplicación automatizada en tiempo de despliegue. En este ejercicio, configurará una política de admisión de Kubernetes que rechaza cualquier imagen de contenedor que carezca de SLSA provenance válido.
Opción A: Sigstore Policy Controller
El Sigstore policy-controller es un webhook de admisión de Kubernetes que verifica firmas de imágenes y attestations antes de que los pods sean admitidos.
Instalar el Policy Controller
helm repo add sigstore https://sigstore.github.io/helm-charts
helm repo update
helm install policy-controller sigstore/policy-controller \
--namespace cosign-system \
--create-namespace
Crear una ClusterImagePolicy
Cree slsa-policy.yml:
apiVersion: policy.sigstore.dev/v1beta1
kind: ClusterImagePolicy
metadata:
name: require-slsa-provenance
spec:
images:
- glob: "ghcr.io/YOUR_USER/**"
authorities:
- keyless:
url: https://fulcio.sigstore.dev
identities:
- issuer: https://token.actions.githubusercontent.com
subjectRegExp: "https://github.com/slsa-framework/slsa-github-generator/.*"
attestations:
- name: must-have-slsa-provenance
predicateType: https://slsa.dev/provenance/v1
policy:
type: cue
data: |
predicateType: "https://slsa.dev/provenance/v1"
Aplíquelo:
kubectl apply -f slsa-policy.yml
Etiquetar el Namespace para la Aplicación de Políticas
kubectl label namespace default policy.sigstore.dev/include=true
Opción B: Política Kyverno
Si utiliza Kyverno como su motor de políticas, cree kyverno-slsa-policy.yml:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-slsa-provenance
spec:
validationFailureAction: Enforce
webhookTimeoutSeconds: 30
rules:
- name: check-slsa-provenance
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "ghcr.io/YOUR_USER/*"
attestations:
- type: https://slsa.dev/provenance/v1
attestors:
- entries:
- keyless:
issuer: https://token.actions.githubusercontent.com
subjectRegExp: "https://github.com/slsa-framework/slsa-github-generator/.*"
rekor:
url: https://rekor.sigstore.dev
Aplíquelo:
kubectl apply -f kyverno-slsa-policy.yml
Prueba: Imagen Con Provenance (Admitida)
kubectl run test-allowed \
--image=ghcr.io/YOUR_USER/slsa-provenance-lab@$DIGEST \
--restart=Never
Resultado esperado: el pod se crea exitosamente.
Prueba: Imagen Sin Provenance (Rechazada)
Publique una imagen rápida sin provenance:
docker build -t ghcr.io/YOUR_USER/slsa-provenance-lab:no-provenance .
docker push ghcr.io/YOUR_USER/slsa-provenance-lab:no-provenance
NO_PROV_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' \
ghcr.io/YOUR_USER/slsa-provenance-lab:no-provenance | cut -d@ -f2)
kubectl run test-rejected \
--image=ghcr.io/YOUR_USER/slsa-provenance-lab@$NO_PROV_DIGEST \
--restart=Never
Resultado esperado:
Error from server: admission webhook denied the request:
image ghcr.io/YOUR_USER/slsa-provenance-lab@sha256:...
failed to verify: no matching attestations found
Esto confirma que la política de admisión está bloqueando correctamente las imágenes que carecen de SLSA provenance.
Inspección del Documento de Provenance
Comprender el documento de provenance es esencial para la auditoría y para construir automatización sobre él. A continuación se muestra un documento de provenance representativo generado por slsa-github-generator, seguido de una explicación campo por campo.
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [
{
"name": "ghcr.io/YOUR_USER/slsa-provenance-lab",
"digest": {
"sha256": "abc123def456789..."
}
}
],
"predicateType": "https://slsa.dev/provenance/v1",
"predicate": {
"buildDefinition": {
"buildType": "https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1",
"externalParameters": {
"workflow": {
"ref": "refs/tags/v1.0.0",
"repository": "https://github.com/YOUR_USER/slsa-provenance-lab",
"path": ".github/workflows/slsa-provenance.yml"
}
},
"resolvedDependencies": [
{
"uri": "git+https://github.com/YOUR_USER/slsa-provenance-lab@refs/tags/v1.0.0",
"digest": {
"gitCommit": "a1b2c3d4e5f6..."
}
}
]
},
"runDetails": {
"builder": {
"id": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v2.1.0"
},
"metadata": {
"invocationId": "https://github.com/YOUR_USER/slsa-provenance-lab/actions/runs/1234567890/attempts/1",
"startedOn": "2026-03-23T10:15:30Z",
"finishedOn": "2026-03-23T10:17:45Z"
}
}
}
}
Desglose Campo por Campo
_type— identifica esto como un Statement v1 de in-toto, el formato de sobre utilizado por SLSA.subject— el artefacto que este provenance describe. Contiene el nombre de la imagen y su digest SHA-256. Esto es lo que se compara con la imagen que está verificando.predicateType— declara que esta attestation es SLSA provenance v1. Las herramientas de verificación usan esto para determinar cómo interpretar el predicado.buildDefinition.buildType— especifica el sistema de compilación. Para GitHub Actions, esto indica a los verificadores que esperen campos específicos de GitHub.buildDefinition.externalParameters.workflow— el archivo de workflow, el repositorio y la referencia Git que desencadenaron la compilación. Debe verificar que esto coincida con el origen esperado.buildDefinition.resolvedDependencies— lista las entradas resueltas incluyendo el commit exacto de Git. Esta es la lista de «materiales» — proporciona un registro completo de lo que se incluyó en la compilación.runDetails.builder.id— el URI del builder que generó el provenance. Para SLSA Level 3, este debe ser un builder de confianza y aislado como el reusable workflowslsa-github-generatoren un tag fijado.runDetails.metadata— marcas de tiempo y un enlace a la ejecución específica de GitHub Actions, permitiendo trazabilidad completa desde el artefacto hasta la compilación.
Al construir verificación automatizada, siempre compruebe: (1) el digest del sujeto coincide, (2) el ID del builder está en su lista de permitidos, (3) el repositorio fuente y la referencia coinciden con sus expectativas, y (4) la firma es válida.
Limpieza
Elimine los recursos creados durante este laboratorio:
# Delete Kubernetes test pods
kubectl delete pod test-allowed test-rejected --ignore-not-found
# Remove the admission policy (Sigstore)
kubectl delete clusterimagepolicy require-slsa-provenance --ignore-not-found
# Or remove the Kyverno policy
kubectl delete clusterpolicy require-slsa-provenance --ignore-not-found
# Remove the namespace label
kubectl label namespace default policy.sigstore.dev/include-
# Delete GHCR images (via GitHub UI or CLI)
gh api -X DELETE /user/packages/container/slsa-provenance-lab/versions/PACKAGE_VERSION_ID
# Delete the test repository if desired
# gh repo delete YOUR_USER/slsa-provenance-lab --yes
Conclusiones Clave
- SLSA provenance es un registro firmado y a prueba de manipulaciones de cómo se construyó una imagen de contenedor. Captura el origen, el builder y los parámetros de compilación.
- SLSA Level 3 requiere aislamiento de la compilación —
slsa-github-generatorlogra esto ejecutando la generación de provenance en un reusable workflow separado que el desarrollador no puede modificar en tiempo de ejecución. - GitHub artifact attestations proporcionan una alternativa más sencilla que se integra estrechamente con el ecosistema de GitHub, con contrapartidas en la portabilidad multiplataforma.
- La verificación debe ser automatizada — use
slsa-verifieren puertas de CI,cosign verify-attestationen scripts, o controladores de admisión de Kubernetes para aplicar provenance antes del despliegue. - La verificación de provenance comprueba múltiples declaraciones: identidad del builder, repositorio fuente, referencia fuente, digest del artefacto y validez de la firma criptográfica.
- Inspeccione los documentos de provenance para entender exactamente qué se construyó, desde qué commit, por cuál builder. Este es su registro de auditoría para incidentes en la cadena de suministro.
Próximos Pasos
Continúe fortaleciendo la seguridad de su cadena de suministro de software:
- Artifact Provenance and Attestations: From SLSA to in-toto — profundice en el framework SLSA, los formatos de attestation in-toto y cómo construir una estrategia integral de provenance en todo su pipeline de compilación.
- Signing and Verifying Container Images with Sigstore and Cosign — aprenda a firmar imágenes de contenedores con firma sin claves de Sigstore, verificar firmas en CI/CD y aplicar políticas de firma en Kubernetes.