{"id":701,"date":"2026-03-05T18:31:45","date_gmt":"2026-03-05T17:31:45","guid":{"rendered":"https:\/\/secure-pipelines.com\/ci-cd-security\/lab-generating-verifying-slsa-provenance-container-images-2\/"},"modified":"2026-03-25T05:20:31","modified_gmt":"2026-03-25T04:20:31","slug":"lab-generating-verifying-slsa-provenance-container-images-2","status":"publish","type":"post","link":"https:\/\/secure-pipelines.com\/es\/ci-cd-security\/lab-generating-verifying-slsa-provenance-container-images-2\/","title":{"rendered":"Lab: Generaci\u00f3n y Verificaci\u00f3n de SLSA Provenance para Im\u00e1genes de Contenedores"},"content":{"rendered":"<h2>Descripci\u00f3n General<\/h2>\n<p>SLSA (Supply-chain Levels for Software Artifacts) provenance es un registro verificable que describe <em>c\u00f3mo<\/em> se construy\u00f3 un artefacto: el repositorio fuente, la plataforma de compilaci\u00f3n, 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\u00edtica antes del despliegue: <strong>\u00ab\u00bfEsta imagen fue realmente construida a partir del c\u00f3digo fuente que espero, en una plataforma en la que conf\u00edo?\u00bb<\/strong><\/p>\n<p>En este laboratorio pr\u00e1ctico usted:<\/p>\n<ul>\n<li>Construir\u00e1 y publicar\u00e1 una imagen de contenedor en GitHub Container Registry (GHCR).<\/li>\n<li>Generar\u00e1 provenance de <strong>SLSA Level 3<\/strong> utilizando el reusable workflow oficial <code>slsa-github-generator<\/code>.<\/li>\n<li>Generar\u00e1 provenance utilizando las <strong>artifact attestations<\/strong> nativas de GitHub (<code>actions\/attest-build-provenance<\/code>).<\/li>\n<li>Verificar\u00e1 el provenance con <code>slsa-verifier<\/code>, <code>cosign<\/code> y <code>gh attestation verify<\/code>.<\/li>\n<li>Aplicar\u00e1 el provenance en tiempo de despliegue con una pol\u00edtica de admisi\u00f3n de Kubernetes.<\/li>\n<\/ul>\n<p>Al finalizar este laboratorio, tendr\u00e1 un pipeline completo y reproducible que demuestra la integridad de cada imagen de contenedor que distribuye.<\/p>\n<h2>Requisitos Previos<\/h2>\n<p>Antes de comenzar, aseg\u00farese de tener lo siguiente:<\/p>\n<ul>\n<li><strong>Cuenta de GitHub<\/strong> con un repositorio de prueba (p\u00fablico o privado con GitHub Pro\/Team\/Enterprise).<\/li>\n<li><strong>Acceso a GHCR<\/strong> &mdash; su cuenta de GitHub puede publicar en <code>ghcr.io<\/code> por defecto; conf\u00edrmelo navegando a <em>Settings &rarr; Packages<\/em>.<\/li>\n<li><strong>Cosign CLI<\/strong> instalado localmente:\n<pre><code># macOS\nbrew install cosign\n\n# Linux \/ other\ngo install github.com\/sigstore\/cosign\/v2\/cmd\/cosign@latest<\/code><\/pre>\n<\/li>\n<li><strong>slsa-verifier CLI<\/strong> instalado:\n<pre><code>go install github.com\/slsa-framework\/slsa-verifier\/v2\/cli\/slsa-verifier@latest<\/code><\/pre>\n<\/li>\n<li><strong>GitHub CLI<\/strong> (<code>gh<\/code>) versi\u00f3n 2.49 o posterior (para los comandos <code>gh attestation<\/code>).<\/li>\n<li><strong>Docker<\/strong> instalado y en ejecuci\u00f3n.<\/li>\n<li><strong>kubectl<\/strong> con acceso a un cl\u00faster de Kubernetes de prueba (para el ejercicio de aplicaci\u00f3n de pol\u00edticas).<\/li>\n<\/ul>\n<h2>Configuraci\u00f3n del Entorno<\/h2>\n<h3>Paso 1 &mdash; Crear el Repositorio de Prueba<\/h3>\n<p>Cree un nuevo repositorio de GitHub llamado <code>slsa-provenance-lab<\/code>. Cl\u00f3nelo localmente y agregue los siguientes archivos.<\/p>\n<h4>main.go<\/h4>\n<pre><code>package main\n\nimport (\n\t\"fmt\"\n\t\"net\/http\"\n)\n\nfunc main() {\n\thttp.HandleFunc(\"\/\", func(w http.ResponseWriter, r *http.Request) {\n\t\tfmt.Fprintf(w, \"Hello from SLSA provenance lab!\")\n\t})\n\tfmt.Println(\"Server starting on :8080\")\n\thttp.ListenAndServe(\":8080\", nil)\n}<\/code><\/pre>\n<h4>go.mod<\/h4>\n<pre><code>module github.com\/YOUR_USER\/slsa-provenance-lab\n\ngo 1.22<\/code><\/pre>\n<h4>Dockerfile<\/h4>\n<pre><code>FROM golang:1.22-alpine AS builder\nWORKDIR \/app\nCOPY go.mod .\/\nCOPY main.go .\/\nRUN go build -o server .\n\nFROM alpine:3.19\nRUN apk --no-cache add ca-certificates\nCOPY --from=builder \/app\/server \/server\nENTRYPOINT [\"\/server\"]<\/code><\/pre>\n<h3>Paso 2 &mdash; Confirmar el Acceso a GHCR<\/h3>\n<p>Autentique Docker con GHCR para poder publicar im\u00e1genes:<\/p>\n<pre><code>echo $GITHUB_TOKEN | docker login ghcr.io -u YOUR_USER --password-stdin<\/code><\/pre>\n<p>Reemplace <code>YOUR_USER<\/code> con su nombre de usuario de GitHub y <code>GITHUB_TOKEN<\/code> con un token de acceso personal que tenga el alcance <code>write:packages<\/code>.<\/p>\n<h3>Paso 3 &mdash; Workflow Base de Build-and-Push (Sin Provenance)<\/h3>\n<p>Cree <code>.github\/workflows\/build.yml<\/code> para verificar que la imagen se construye y publica correctamente antes de agregar provenance:<\/p>\n<pre><code>name: Build and Push (baseline)\n\non:\n  push:\n    tags:\n      - \"v*\"\n\nenv:\n  IMAGE: ghcr.io\/${{ github.repository_owner }}\/slsa-provenance-lab\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n      packages: write\n    steps:\n      - uses: actions\/checkout@v4\n\n      - uses: docker\/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - uses: docker\/build-push-action@v6\n        with:\n          context: .\n          push: true\n          tags: |\n            ${{ env.IMAGE }}:${{ github.ref_name }}\n            ${{ env.IMAGE }}:latest<\/code><\/pre>\n<p>Publique un tag de prueba para verificar:<\/p>\n<pre><code>git add -A\ngit commit -m \"baseline build workflow\"\ngit tag v0.1.0\ngit push origin main --tags<\/code><\/pre>\n<p>Confirme que la imagen aparece en <code>ghcr.io\/YOUR_USER\/slsa-provenance-lab:v0.1.0<\/code> antes de continuar.<\/p>\n<h2>Ejercicio 1: Generar SLSA Provenance con slsa-github-generator<\/h2>\n<h3>Por Qu\u00e9 slsa-github-generator Alcanza SLSA Level 3<\/h3>\n<p>La propiedad clave de SLSA Build Level 3 es que el provenance es generado por una plataforma de compilaci\u00f3n que el desarrollador <strong>no puede<\/strong> influenciar. El <code>slsa-github-generator<\/code> logra esto ejecut\u00e1ndose como un <strong>reusable workflow alojado en un repositorio separado<\/strong>. Dado que GitHub Actions a\u00edsla las ejecuciones de reusable workflows del workflow que los invoca, el paso de generaci\u00f3n de provenance est\u00e1 protegido contra manipulaciones &mdash; incluso un job de compilaci\u00f3n comprometido no puede alterar la salida del provenance.<\/p>\n<h3>El Workflow<\/h3>\n<p>Cree <code>.github\/workflows\/slsa-provenance.yml<\/code>:<\/p>\n<pre><code>name: Build + SLSA Provenance (slsa-github-generator)\n\non:\n  push:\n    tags:\n      - \"v*\"\n\nenv:\n  IMAGE: ghcr.io\/${{ github.repository_owner }}\/slsa-provenance-lab\n\njobs:\n  # --- Job 1: Build and push the container image ---\n  build:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n      packages: write\n    outputs:\n      image: ${{ env.IMAGE }}\n      digest: ${{ steps.push.outputs.digest }}\n    steps:\n      - uses: actions\/checkout@v4\n\n      - uses: docker\/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - id: push\n        uses: docker\/build-push-action@v6\n        with:\n          context: .\n          push: true\n          tags: |\n            ${{ env.IMAGE }}:${{ github.ref_name }}\n            ${{ env.IMAGE }}:latest\n\n  # --- Job 2: Generate SLSA Level 3 provenance ---\n  provenance:\n    needs: build\n    permissions:\n      actions: read\n      id-token: write\n      packages: write\n    uses: slsa-framework\/slsa-github-generator\/.github\/workflows\/generator_container_slsa3.yml@v2.1.0\n    with:\n      image: ${{ needs.build.outputs.image }}\n      digest: ${{ needs.build.outputs.digest }}\n    secrets:\n      registry-username: ${{ github.actor }}\n      registry-password: ${{ secrets.GITHUB_TOKEN }}<\/code><\/pre>\n<h3>Comprensi\u00f3n del Workflow<\/h3>\n<ul>\n<li>El job <strong>build<\/strong> construye la imagen, la publica en GHCR y produce como salida la referencia de la imagen y el digest.<\/li>\n<li>El job <strong>provenance<\/strong> invoca el reusable workflow del repositorio <code>slsa-framework\/slsa-github-generator<\/code> en un tag fijado (<code>@v2.1.0<\/code>). 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\u00f3n reforzada y no falsificable.<\/li>\n<li>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.<\/li>\n<\/ul>\n<h3>Ejecutar el Workflow<\/h3>\n<pre><code>git add .github\/workflows\/slsa-provenance.yml\ngit commit -m \"add SLSA provenance workflow\"\ngit tag v1.0.0\ngit push origin main --tags<\/code><\/pre>\n<p>En la pesta\u00f1a Actions ver\u00e1 dos jobs: <strong>build<\/strong> y <strong>provenance<\/strong>. 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 <code>ghcr.io\/YOUR_USER\/slsa-provenance-lab@sha256:&lt;digest&gt;<\/code> ahora porta una attestation de provenance SLSA Level 3 firmada.<\/p>\n<h2>Ejercicio 2: Generar Provenance con GitHub Artifact Attestations<\/h2>\n<h3>El Enfoque Nativo de GitHub<\/h3>\n<p>GitHub proporciona un mecanismo integrado para generar build provenance a trav\u00e9s de la action <code>actions\/attest-build-provenance<\/code>. Este enfoque es m\u00e1s sencillo de configurar y almacena las attestations en el almacenamiento de attestations propio de GitHub, haci\u00e9ndolas verificables con el CLI <code>gh<\/code>. La contrapartida es que estas attestations siguen la ruta de verificaci\u00f3n propia de GitHub en lugar de las herramientas del framework SLSA.<\/p>\n<h3>El Workflow<\/h3>\n<p>Cree <code>.github\/workflows\/github-attestation.yml<\/code>:<\/p>\n<pre><code>name: Build + GitHub Artifact Attestation\n\non:\n  push:\n    tags:\n      - \"v*\"\n\nenv:\n  IMAGE: ghcr.io\/${{ github.repository_owner }}\/slsa-provenance-lab\n\njobs:\n  build-and-attest:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n      packages: write\n      attestations: write\n      id-token: write\n    steps:\n      - uses: actions\/checkout@v4\n\n      - uses: docker\/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - id: push\n        uses: docker\/build-push-action@v6\n        with:\n          context: .\n          push: true\n          tags: |\n            ${{ env.IMAGE }}:${{ github.ref_name }}\n            ${{ env.IMAGE }}:latest\n\n      - name: Generate artifact attestation\n        uses: actions\/attest-build-provenance@v2\n        with:\n          subject-name: ${{ env.IMAGE }}\n          subject-digest: ${{ steps.push.outputs.digest }}\n          push-to-registry: true<\/code><\/pre>\n<h3>Comparaci\u00f3n de los Dos Enfoques<\/h3>\n<table>\n<thead>\n<tr>\n<th>Aspecto<\/th>\n<th>slsa-github-generator<\/th>\n<th>GitHub Artifact Attestations<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Nivel SLSA<\/td>\n<td>Level 3 (reusable workflow aislado)<\/td>\n<td>Level 2&ndash;3 (gestionado por GitHub, workflow \u00fanico)<\/td>\n<\/tr>\n<tr>\n<td>Herramienta de verificaci\u00f3n<\/td>\n<td><code>slsa-verifier<\/code>, <code>cosign<\/code><\/td>\n<td><code>gh attestation verify<\/code>, <code>cosign<\/code><\/td>\n<\/tr>\n<tr>\n<td>Almacenamiento de attestations<\/td>\n<td>Registro OCI (junto a la imagen)<\/td>\n<td>API de attestation de GitHub + publicaci\u00f3n OCI opcional<\/td>\n<\/tr>\n<tr>\n<td>Complejidad de configuraci\u00f3n<\/td>\n<td>Workflow de dos jobs con llamada a reusable workflow<\/td>\n<td>Workflow de un solo job con un paso adicional<\/td>\n<\/tr>\n<tr>\n<td>Firma<\/td>\n<td>Sigstore (Fulcio + Rekor)<\/td>\n<td>Sigstore (Fulcio + Rekor v\u00eda GitHub)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Ambos enfoques son v\u00e1lidos. Use <code>slsa-github-generator<\/code> cuando necesite cumplimiento estricto de SLSA Level 3 con verificaci\u00f3n multiplataforma. Use GitHub artifact attestations cuando desee una configuraci\u00f3n m\u00e1s sencilla y sus consumidores ya utilicen el ecosistema de GitHub.<\/p>\n<h2>Ejercicio 3: Verificar Provenance con slsa-verifier<\/h2>\n<p>El CLI <code>slsa-verifier<\/code> es la herramienta oficial para verificar el SLSA provenance generado por <code>slsa-github-generator<\/code>. Verifica la firma criptogr\u00e1fica, la identidad del builder, el repositorio fuente y el digest del artefacto en un solo comando.<\/p>\n<h3>Paso 1 &mdash; Obtener el Digest de la Imagen<\/h3>\n<p>Obtenga el digest de la imagen que public\u00f3:<\/p>\n<pre><code>IMAGE=ghcr.io\/YOUR_USER\/slsa-provenance-lab\nDIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' \"$IMAGE:v1.0.0\" | cut -d@ -f2)\necho \"$DIGEST\"<\/code><\/pre>\n<p>Tambi\u00e9n puede encontrar el digest en la salida del workflow de Actions o en la p\u00e1gina del paquete en GHCR.<\/p>\n<h3>Paso 2 &mdash; Verificaci\u00f3n Exitosa<\/h3>\n<pre><code>slsa-verifier verify-image \"ghcr.io\/YOUR_USER\/slsa-provenance-lab@$DIGEST\" \\\n  --source-uri github.com\/YOUR_USER\/slsa-provenance-lab \\\n  --source-tag v1.0.0<\/code><\/pre>\n<p>Salida esperada:<\/p>\n<pre><code>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\nVERIFIED: SLSA verification passed<\/code><\/pre>\n<h3>Paso 3 &mdash; Fallo de Verificaci\u00f3n: URI de Origen Incorrecto<\/h3>\n<p>Intente verificar contra un repositorio fuente incorrecto:<\/p>\n<pre><code>slsa-verifier verify-image \"ghcr.io\/YOUR_USER\/slsa-provenance-lab@$DIGEST\" \\\n  --source-uri github.com\/YOUR_USER\/wrong-repo \\\n  --source-tag v1.0.0<\/code><\/pre>\n<p>Salida esperada:<\/p>\n<pre><code>FAILED: SLSA verification failed: source used to generate the binary does not match provenance<\/code><\/pre>\n<h3>Paso 4 &mdash; Fallo de Verificaci\u00f3n: Tag Incorrecto<\/h3>\n<pre><code>slsa-verifier verify-image \"ghcr.io\/YOUR_USER\/slsa-provenance-lab@$DIGEST\" \\\n  --source-uri github.com\/YOUR_USER\/slsa-provenance-lab \\\n  --source-tag v9.9.9<\/code><\/pre>\n<p>Salida esperada:<\/p>\n<pre><code>FAILED: SLSA verification failed: tag \"v9.9.9\" does not match provenance<\/code><\/pre>\n<h3>Qu\u00e9 Verifica slsa-verifier<\/h3>\n<ul>\n<li><strong>Identidad del builder<\/strong> &mdash; confirma que el provenance fue creado por el reusable workflow oficial <code>slsa-github-generator<\/code> en la referencia esperada.<\/li>\n<li><strong>Repositorio fuente<\/strong> &mdash; el provenance debe hacer referencia al URI fuente que usted especifica.<\/li>\n<li><strong>Tag\/branch fuente<\/strong> &mdash; opcionalmente verifica la referencia Git que desencaden\u00f3 la compilaci\u00f3n.<\/li>\n<li><strong>Digest del artefacto<\/strong> &mdash; el digest SHA-256 registrado en el provenance debe coincidir con la imagen que est\u00e1 verificando.<\/li>\n<li><strong>Firma y registro de transparencia<\/strong> &mdash; la firma de Sigstore se verifica contra el registro de transparencia Rekor.<\/li>\n<\/ul>\n<h2>Ejercicio 4: Verificar con cosign verify-attestation<\/h2>\n<p>Cosign proporciona una forma de verificar attestations adjuntas a im\u00e1genes de contenedores que es de nivel m\u00e1s bajo pero m\u00e1s flexible. Esto es \u00fatil cuando necesita inspeccionar el payload de provenance sin procesar o cuando integra en pipelines de verificaci\u00f3n personalizados.<\/p>\n<h3>Verificar la Attestation<\/h3>\n<pre><code>cosign verify-attestation \\\n  --type slsaprovenance \\\n  --certificate-identity-regexp \"https:\/\/github.com\/slsa-framework\/slsa-github-generator\/\" \\\n  --certificate-oidc-issuer \"https:\/\/token.actions.githubusercontent.com\" \\\n  ghcr.io\/YOUR_USER\/slsa-provenance-lab@$DIGEST<\/code><\/pre>\n<p>En caso de \u00e9xito, cosign imprime el payload de la attestation en formato JSON. Un ejemplo truncado:<\/p>\n<pre><code>Verification for ghcr.io\/YOUR_USER\/slsa-provenance-lab@sha256:abc123... --\nThe following checks were performed on each of these signatures:\n  - The cosign claims were validated\n  - Existence of the claims in the transparency log was verified offline\n  - The code-signing certificate was verified using trusted certificate authority\n\n{\n  \"payloadType\": \"application\/vnd.in-toto+json\",\n  \"payload\": \"eyJfdHlwZSI6Imh0dHBz...\",\n  \"signatures\": [{ \"sig\": \"MEUCIQD...\" }]\n}<\/code><\/pre>\n<h3>Inspeccionar el Payload de Provenance<\/h3>\n<p>Decodifique el payload en base64 para inspeccionar los campos de provenance:<\/p>\n<pre><code>cosign verify-attestation \\\n  --type slsaprovenance \\\n  --certificate-identity-regexp \"https:\/\/github.com\/slsa-framework\/slsa-github-generator\/\" \\\n  --certificate-oidc-issuer \"https:\/\/token.actions.githubusercontent.com\" \\\n  ghcr.io\/YOUR_USER\/slsa-provenance-lab@$DIGEST \\\n  | jq -r '.payload' | base64 -d | jq .<\/code><\/pre>\n<p>Campos clave en la salida:<\/p>\n<ul>\n<li><strong><code>buildDefinition.buildType<\/code><\/strong> &mdash; identifica el sistema de compilaci\u00f3n (por ejemplo, <code>https:\/\/slsa-framework.github.io\/github-actions-buildtypes\/workflow\/v1<\/code>).<\/li>\n<li><strong><code>buildDefinition.externalParameters.workflow<\/code><\/strong> &mdash; el archivo de workflow y la referencia que ejecut\u00f3 la compilaci\u00f3n.<\/li>\n<li><strong><code>buildDefinition.resolvedDependencies<\/code><\/strong> &mdash; el commit de Git, el repositorio y otras entradas.<\/li>\n<li><strong><code>runDetails.builder.id<\/code><\/strong> &mdash; el URI del builder de confianza que gener\u00f3 el provenance.<\/li>\n<\/ul>\n<h2>Ejercicio 5: Verificar con gh attestation verify<\/h2>\n<p>Para im\u00e1genes atestadas utilizando las artifact attestations nativas de GitHub (Ejercicio 2), el CLI <code>gh<\/code> proporciona la ruta de verificaci\u00f3n m\u00e1s sencilla.<\/p>\n<h3>Verificar la Attestation<\/h3>\n<pre><code>gh attestation verify oci:\/\/ghcr.io\/YOUR_USER\/slsa-provenance-lab@$DIGEST \\\n  --owner YOUR_USER<\/code><\/pre>\n<p>Salida esperada:<\/p>\n<pre><code>Loaded digest sha256:abc123def456... for oci:\/\/ghcr.io\/YOUR_USER\/slsa-provenance-lab@sha256:abc123...\nLoaded 1 attestation from GitHub API\n\n\u2713 Verification succeeded!\n\nPredicateType: https:\/\/slsa.dev\/provenance\/v1\nSubjectName:   ghcr.io\/YOUR_USER\/slsa-provenance-lab\nSubjectDigest: sha256:abc123def456...\nSignerRepo:    YOUR_USER\/slsa-provenance-lab\nSignerWorkflow: .github\/workflows\/github-attestation.yml\nRunnerEnv:     github-hosted<\/code><\/pre>\n<h3>Descargar e Inspeccionar la Attestation<\/h3>\n<p>Para descargar el bundle de attestation sin procesar para inspecci\u00f3n offline:<\/p>\n<pre><code>gh attestation download oci:\/\/ghcr.io\/YOUR_USER\/slsa-provenance-lab@$DIGEST \\\n  --owner YOUR_USER \\\n  --output attestation-bundle.json\n\n# Inspect the provenance predicate\ncat attestation-bundle.json | jq '.dsseEnvelope.payload' -r | base64 -d | jq .<\/code><\/pre>\n<p>Esto le proporciona el predicado completo de SLSA provenance, que puede almacenar junto con sus registros de despliegue para fines de auditor\u00eda.<\/p>\n<h2>Ejercicio 6: Aplicar Provenance en el Despliegue<\/h2>\n<p>Generar y verificar provenance manualmente es valioso, pero el verdadero beneficio de seguridad proviene de la <strong>aplicaci\u00f3n automatizada<\/strong> en tiempo de despliegue. En este ejercicio, configurar\u00e1 una pol\u00edtica de admisi\u00f3n de Kubernetes que rechaza cualquier imagen de contenedor que carezca de SLSA provenance v\u00e1lido.<\/p>\n<h3>Opci\u00f3n A: Sigstore Policy Controller<\/h3>\n<p>El <a href=\"https:\/\/docs.sigstore.dev\/policy-controller\/overview\/\" target=\"_blank\" rel=\"noopener\">Sigstore policy-controller<\/a> es un webhook de admisi\u00f3n de Kubernetes que verifica firmas de im\u00e1genes y attestations antes de que los pods sean admitidos.<\/p>\n<h4>Instalar el Policy Controller<\/h4>\n<pre><code>helm repo add sigstore https:\/\/sigstore.github.io\/helm-charts\nhelm repo update\nhelm install policy-controller sigstore\/policy-controller \\\n  --namespace cosign-system \\\n  --create-namespace<\/code><\/pre>\n<h4>Crear una ClusterImagePolicy<\/h4>\n<p>Cree <code>slsa-policy.yml<\/code>:<\/p>\n<pre><code>apiVersion: policy.sigstore.dev\/v1beta1\nkind: ClusterImagePolicy\nmetadata:\n  name: require-slsa-provenance\nspec:\n  images:\n    - glob: \"ghcr.io\/YOUR_USER\/**\"\n  authorities:\n    - keyless:\n        url: https:\/\/fulcio.sigstore.dev\n        identities:\n          - issuer: https:\/\/token.actions.githubusercontent.com\n            subjectRegExp: \"https:\/\/github.com\/slsa-framework\/slsa-github-generator\/.*\"\n      attestations:\n        - name: must-have-slsa-provenance\n          predicateType: https:\/\/slsa.dev\/provenance\/v1\n          policy:\n            type: cue\n            data: |\n              predicateType: \"https:\/\/slsa.dev\/provenance\/v1\"<\/code><\/pre>\n<p>Apl\u00edquelo:<\/p>\n<pre><code>kubectl apply -f slsa-policy.yml<\/code><\/pre>\n<h4>Etiquetar el Namespace para la Aplicaci\u00f3n de Pol\u00edticas<\/h4>\n<pre><code>kubectl label namespace default policy.sigstore.dev\/include=true<\/code><\/pre>\n<h3>Opci\u00f3n B: Pol\u00edtica Kyverno<\/h3>\n<p>Si utiliza Kyverno como su motor de pol\u00edticas, cree <code>kyverno-slsa-policy.yml<\/code>:<\/p>\n<pre><code>apiVersion: kyverno.io\/v1\nkind: ClusterPolicy\nmetadata:\n  name: require-slsa-provenance\nspec:\n  validationFailureAction: Enforce\n  webhookTimeoutSeconds: 30\n  rules:\n    - name: check-slsa-provenance\n      match:\n        any:\n          - resources:\n              kinds:\n                - Pod\n      verifyImages:\n        - imageReferences:\n            - \"ghcr.io\/YOUR_USER\/*\"\n          attestations:\n            - type: https:\/\/slsa.dev\/provenance\/v1\n              attestors:\n                - entries:\n                    - keyless:\n                        issuer: https:\/\/token.actions.githubusercontent.com\n                        subjectRegExp: \"https:\/\/github.com\/slsa-framework\/slsa-github-generator\/.*\"\n                        rekor:\n                          url: https:\/\/rekor.sigstore.dev<\/code><\/pre>\n<p>Apl\u00edquelo:<\/p>\n<pre><code>kubectl apply -f kyverno-slsa-policy.yml<\/code><\/pre>\n<h3>Prueba: Imagen Con Provenance (Admitida)<\/h3>\n<pre><code>kubectl run test-allowed \\\n  --image=ghcr.io\/YOUR_USER\/slsa-provenance-lab@$DIGEST \\\n  --restart=Never<\/code><\/pre>\n<p>Resultado esperado: el pod se crea exitosamente.<\/p>\n<h3>Prueba: Imagen Sin Provenance (Rechazada)<\/h3>\n<p>Publique una imagen r\u00e1pida sin provenance:<\/p>\n<pre><code>docker build -t ghcr.io\/YOUR_USER\/slsa-provenance-lab:no-provenance .\ndocker push ghcr.io\/YOUR_USER\/slsa-provenance-lab:no-provenance\n\nNO_PROV_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' \\\n  ghcr.io\/YOUR_USER\/slsa-provenance-lab:no-provenance | cut -d@ -f2)\n\nkubectl run test-rejected \\\n  --image=ghcr.io\/YOUR_USER\/slsa-provenance-lab@$NO_PROV_DIGEST \\\n  --restart=Never<\/code><\/pre>\n<p>Resultado esperado:<\/p>\n<pre><code>Error from server: admission webhook denied the request:\nimage ghcr.io\/YOUR_USER\/slsa-provenance-lab@sha256:... \nfailed to verify: no matching attestations found<\/code><\/pre>\n<p>Esto confirma que la pol\u00edtica de admisi\u00f3n est\u00e1 bloqueando correctamente las im\u00e1genes que carecen de SLSA provenance.<\/p>\n<h2>Inspecci\u00f3n del Documento de Provenance<\/h2>\n<p>Comprender el documento de provenance es esencial para la auditor\u00eda y para construir automatizaci\u00f3n sobre \u00e9l. A continuaci\u00f3n se muestra un documento de provenance representativo generado por <code>slsa-github-generator<\/code>, seguido de una explicaci\u00f3n campo por campo.<\/p>\n<pre><code>{\n  \"_type\": \"https:\/\/in-toto.io\/Statement\/v1\",\n  \"subject\": [\n    {\n      \"name\": \"ghcr.io\/YOUR_USER\/slsa-provenance-lab\",\n      \"digest\": {\n        \"sha256\": \"abc123def456789...\"\n      }\n    }\n  ],\n  \"predicateType\": \"https:\/\/slsa.dev\/provenance\/v1\",\n  \"predicate\": {\n    \"buildDefinition\": {\n      \"buildType\": \"https:\/\/slsa-framework.github.io\/github-actions-buildtypes\/workflow\/v1\",\n      \"externalParameters\": {\n        \"workflow\": {\n          \"ref\": \"refs\/tags\/v1.0.0\",\n          \"repository\": \"https:\/\/github.com\/YOUR_USER\/slsa-provenance-lab\",\n          \"path\": \".github\/workflows\/slsa-provenance.yml\"\n        }\n      },\n      \"resolvedDependencies\": [\n        {\n          \"uri\": \"git+https:\/\/github.com\/YOUR_USER\/slsa-provenance-lab@refs\/tags\/v1.0.0\",\n          \"digest\": {\n            \"gitCommit\": \"a1b2c3d4e5f6...\"\n          }\n        }\n      ]\n    },\n    \"runDetails\": {\n      \"builder\": {\n        \"id\": \"https:\/\/github.com\/slsa-framework\/slsa-github-generator\/.github\/workflows\/generator_container_slsa3.yml@refs\/tags\/v2.1.0\"\n      },\n      \"metadata\": {\n        \"invocationId\": \"https:\/\/github.com\/YOUR_USER\/slsa-provenance-lab\/actions\/runs\/1234567890\/attempts\/1\",\n        \"startedOn\": \"2026-03-23T10:15:30Z\",\n        \"finishedOn\": \"2026-03-23T10:17:45Z\"\n      }\n    }\n  }\n}<\/code><\/pre>\n<h3>Desglose Campo por Campo<\/h3>\n<ul>\n<li><strong><code>_type<\/code><\/strong> &mdash; identifica esto como un Statement v1 de <a href=\"https:\/\/in-toto.io\" target=\"_blank\" rel=\"noopener\">in-toto<\/a>, el formato de sobre utilizado por SLSA.<\/li>\n<li><strong><code>subject<\/code><\/strong> &mdash; 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\u00e1 verificando.<\/li>\n<li><strong><code>predicateType<\/code><\/strong> &mdash; declara que esta attestation es SLSA provenance v1. Las herramientas de verificaci\u00f3n usan esto para determinar c\u00f3mo interpretar el predicado.<\/li>\n<li><strong><code>buildDefinition.buildType<\/code><\/strong> &mdash; especifica el sistema de compilaci\u00f3n. Para GitHub Actions, esto indica a los verificadores que esperen campos espec\u00edficos de GitHub.<\/li>\n<li><strong><code>buildDefinition.externalParameters.workflow<\/code><\/strong> &mdash; el archivo de workflow, el repositorio y la referencia Git que desencadenaron la compilaci\u00f3n. Debe verificar que esto coincida con el origen esperado.<\/li>\n<li><strong><code>buildDefinition.resolvedDependencies<\/code><\/strong> &mdash; lista las entradas resueltas incluyendo el commit exacto de Git. Esta es la lista de \u00abmateriales\u00bb &mdash; proporciona un registro completo de lo que se incluy\u00f3 en la compilaci\u00f3n.<\/li>\n<li><strong><code>runDetails.builder.id<\/code><\/strong> &mdash; el URI del builder que gener\u00f3 el provenance. Para SLSA Level 3, este debe ser un builder de confianza y aislado como el reusable workflow <code>slsa-github-generator<\/code> en un tag fijado.<\/li>\n<li><strong><code>runDetails.metadata<\/code><\/strong> &mdash; marcas de tiempo y un enlace a la ejecuci\u00f3n espec\u00edfica de GitHub Actions, permitiendo trazabilidad completa desde el artefacto hasta la compilaci\u00f3n.<\/li>\n<\/ul>\n<p>Al construir verificaci\u00f3n automatizada, siempre compruebe: (1) el digest del sujeto coincide, (2) el ID del builder est\u00e1 en su lista de permitidos, (3) el repositorio fuente y la referencia coinciden con sus expectativas, y (4) la firma es v\u00e1lida.<\/p>\n<h2>Limpieza<\/h2>\n<p>Elimine los recursos creados durante este laboratorio:<\/p>\n<pre><code># Delete Kubernetes test pods\nkubectl delete pod test-allowed test-rejected --ignore-not-found\n\n# Remove the admission policy (Sigstore)\nkubectl delete clusterimagepolicy require-slsa-provenance --ignore-not-found\n\n# Or remove the Kyverno policy\nkubectl delete clusterpolicy require-slsa-provenance --ignore-not-found\n\n# Remove the namespace label\nkubectl label namespace default policy.sigstore.dev\/include-\n\n# Delete GHCR images (via GitHub UI or CLI)\ngh api -X DELETE \/user\/packages\/container\/slsa-provenance-lab\/versions\/PACKAGE_VERSION_ID\n\n# Delete the test repository if desired\n# gh repo delete YOUR_USER\/slsa-provenance-lab --yes<\/code><\/pre>\n<h2>Conclusiones Clave<\/h2>\n<ul>\n<li><strong>SLSA provenance es un registro firmado y a prueba de manipulaciones<\/strong> de c\u00f3mo se construy\u00f3 una imagen de contenedor. Captura el origen, el builder y los par\u00e1metros de compilaci\u00f3n.<\/li>\n<li><strong>SLSA Level 3 requiere aislamiento de la compilaci\u00f3n<\/strong> &mdash; <code>slsa-github-generator<\/code> logra esto ejecutando la generaci\u00f3n de provenance en un reusable workflow separado que el desarrollador no puede modificar en tiempo de ejecuci\u00f3n.<\/li>\n<li><strong>GitHub artifact attestations<\/strong> proporcionan una alternativa m\u00e1s sencilla que se integra estrechamente con el ecosistema de GitHub, con contrapartidas en la portabilidad multiplataforma.<\/li>\n<li><strong>La verificaci\u00f3n debe ser automatizada<\/strong> &mdash; use <code>slsa-verifier<\/code> en puertas de CI, <code>cosign verify-attestation<\/code> en scripts, o controladores de admisi\u00f3n de Kubernetes para aplicar provenance antes del despliegue.<\/li>\n<li><strong>La verificaci\u00f3n de provenance comprueba m\u00faltiples declaraciones<\/strong>: identidad del builder, repositorio fuente, referencia fuente, digest del artefacto y validez de la firma criptogr\u00e1fica.<\/li>\n<li><strong>Inspeccione los documentos de provenance<\/strong> para entender exactamente qu\u00e9 se construy\u00f3, desde qu\u00e9 commit, por cu\u00e1l builder. Este es su registro de auditor\u00eda para incidentes en la cadena de suministro.<\/li>\n<\/ul>\n<h2>Pr\u00f3ximos Pasos<\/h2>\n<p>Contin\u00fae fortaleciendo la seguridad de su cadena de suministro de software:<\/p>\n<ul>\n<li><a href=\"\/es\/ci-cd-security\/artifact-provenance-attestations-slsa-in-toto\/\">Artifact Provenance and Attestations: From SLSA to in-toto<\/a> &mdash; profundice en el framework SLSA, los formatos de attestation in-toto y c\u00f3mo construir una estrategia integral de provenance en todo su pipeline de compilaci\u00f3n.<\/li>\n<li><a href=\"\/es\/ci-cd-security\/signing-verifying-container-images-sigstore-cosign\/\">Signing and Verifying Container Images with Sigstore and Cosign<\/a> &mdash; aprenda a firmar im\u00e1genes de contenedores con firma sin claves de Sigstore, verificar firmas en CI\/CD y aplicar pol\u00edticas de firma en Kubernetes.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Descripci\u00f3n General SLSA (Supply-chain Levels for Software Artifacts) provenance es un registro verificable que describe c\u00f3mo se construy\u00f3 un artefacto: el repositorio fuente, la plataforma de compilaci\u00f3n, 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\u00edtica antes &#8230; <a title=\"Lab: Generaci\u00f3n y Verificaci\u00f3n de SLSA Provenance para Im\u00e1genes de Contenedores\" class=\"read-more\" href=\"https:\/\/secure-pipelines.com\/es\/ci-cd-security\/lab-generating-verifying-slsa-provenance-container-images-2\/\" aria-label=\"Leer m\u00e1s sobre Lab: Generaci\u00f3n y Verificaci\u00f3n de SLSA Provenance para Im\u00e1genes de Contenedores\">Leer m\u00e1s<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[55,59],"tags":[],"post_folder":[],"class_list":["post-701","post","type-post","status-publish","format-standard","hentry","category-ci-cd-security","category-software-supply-chain"],"_links":{"self":[{"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/posts\/701","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/comments?post=701"}],"version-history":[{"count":0,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/posts\/701\/revisions"}],"wp:attachment":[{"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/media?parent=701"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/categories?post=701"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/tags?post=701"},{"taxonomy":"post_folder","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/post_folder?post=701"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}