{"id":530,"date":"2026-03-05T18:31:45","date_gmt":"2026-03-05T17:31:45","guid":{"rendered":"https:\/\/secure-pipelines.com\/?p=530"},"modified":"2026-03-24T12:57:53","modified_gmt":"2026-03-24T11:57:53","slug":"lab-generating-verifying-slsa-provenance-container-images","status":"publish","type":"post","link":"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/lab-generating-verifying-slsa-provenance-container-images\/","title":{"rendered":"Lab : G\u00e9n\u00e9ration et V\u00e9rification de la Provenance SLSA pour les Images Container"},"content":{"rendered":"<h2>Pr\u00e9sentation<\/h2>\n<p>La provenance SLSA (Supply-chain Levels for Software Artifacts) est un enregistrement v\u00e9rifiable qui d\u00e9crit <em>comment<\/em> un artefact a \u00e9t\u00e9 construit : le d\u00e9p\u00f4t source, la plateforme de build, le point d&rsquo;entr\u00e9e et les mat\u00e9riaux d&rsquo;entr\u00e9e. Lorsqu&rsquo;elle est associ\u00e9e \u00e0 une image container, la provenance permet aux consommateurs de r\u00e9pondre \u00e0 une question critique avant le d\u00e9ploiement : <strong>\u00ab Cette image a-t-elle r\u00e9ellement \u00e9t\u00e9 construite \u00e0 partir du source que j&rsquo;attends, sur une plateforme en laquelle j&rsquo;ai confiance ? \u00bb<\/strong><\/p>\n<p>Dans ce lab pratique, vous allez :<\/p>\n<ul>\n<li>Construire et pousser une image container vers GitHub Container Registry (GHCR).<\/li>\n<li>G\u00e9n\u00e9rer une provenance <strong>SLSA Level 3<\/strong> en utilisant le workflow r\u00e9utilisable officiel <code>slsa-github-generator<\/code>.<\/li>\n<li>G\u00e9n\u00e9rer une provenance en utilisant les <strong>artifact attestations<\/strong> natifs de GitHub (<code>actions\/attest-build-provenance<\/code>).<\/li>\n<li>V\u00e9rifier la provenance avec <code>slsa-verifier<\/code>, <code>cosign<\/code> et <code>gh attestation verify<\/code>.<\/li>\n<li>Appliquer la provenance au moment du d\u00e9ploiement avec une politique d&rsquo;admission Kubernetes.<\/li>\n<\/ul>\n<p>\u00c0 la fin de ce lab, vous disposerez d&rsquo;un pipeline complet et reproductible qui prouve l&rsquo;int\u00e9grit\u00e9 de chaque image container que vous livrez.<\/p>\n<h2>Pr\u00e9requis<\/h2>\n<p>Avant de commencer, assurez-vous de disposer des \u00e9l\u00e9ments suivants :<\/p>\n<ul>\n<li><strong>Compte GitHub<\/strong> avec un d\u00e9p\u00f4t de test (public ou priv\u00e9 avec GitHub Pro\/Team\/Enterprise).<\/li>\n<li><strong>Acc\u00e8s GHCR<\/strong> &mdash; votre compte GitHub peut pousser vers <code>ghcr.io<\/code> par d\u00e9faut ; confirmez en naviguant vers <em>Settings &rarr; Packages<\/em>.<\/li>\n<li><strong>Cosign CLI<\/strong> install\u00e9 localement :\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> install\u00e9 :\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>) version 2.49 ou ult\u00e9rieure (pour les commandes <code>gh attestation<\/code>).<\/li>\n<li><strong>Docker<\/strong> install\u00e9 et en cours d&rsquo;ex\u00e9cution.<\/li>\n<li><strong>kubectl<\/strong> avec acc\u00e8s \u00e0 un cluster Kubernetes de test (pour l&rsquo;exercice d&rsquo;application des politiques).<\/li>\n<\/ul>\n<h2>Mise en Place de l&rsquo;Environnement<\/h2>\n<h3>\u00c9tape 1 &mdash; Cr\u00e9er le D\u00e9p\u00f4t de Test<\/h3>\n<p>Cr\u00e9ez un nouveau d\u00e9p\u00f4t GitHub appel\u00e9 <code>slsa-provenance-lab<\/code>. Clonez-le localement et ajoutez les fichiers suivants.<\/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>\u00c9tape 2 &mdash; Confirmer l&rsquo;Acc\u00e8s GHCR<\/h3>\n<p>Authentifiez Docker aupr\u00e8s de GHCR afin de pouvoir pousser des images :<\/p>\n<pre><code>echo $GITHUB_TOKEN | docker login ghcr.io -u YOUR_USER --password-stdin<\/code><\/pre>\n<p>Remplacez <code>YOUR_USER<\/code> par votre nom d&rsquo;utilisateur GitHub et <code>GITHUB_TOKEN<\/code> par un jeton d&rsquo;acc\u00e8s personnel disposant du scope <code>write:packages<\/code>.<\/p>\n<h3>\u00c9tape 3 &mdash; Workflow de Base Build-and-Push (Sans Provenance)<\/h3>\n<p>Cr\u00e9ez <code>.github\/workflows\/build.yml<\/code> pour v\u00e9rifier que l&rsquo;image se construit et se pousse correctement avant d&rsquo;ajouter la 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>Poussez un tag de test pour v\u00e9rifier :<\/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>Confirmez que l&rsquo;image appara\u00eet \u00e0 <code>ghcr.io\/YOUR_USER\/slsa-provenance-lab:v0.1.0<\/code> avant de continuer.<\/p>\n<h2>Exercice 1 : G\u00e9n\u00e9rer la Provenance SLSA avec slsa-github-generator<\/h2>\n<h3>Pourquoi slsa-github-generator Atteint le SLSA Level 3<\/h3>\n<p>La propri\u00e9t\u00e9 cl\u00e9 du SLSA Build Level 3 est que la provenance est g\u00e9n\u00e9r\u00e9e par une plateforme de build que le d\u00e9veloppeur <strong>ne peut pas<\/strong> influencer. Le <code>slsa-github-generator<\/code> y parvient en s&rsquo;ex\u00e9cutant comme un <strong>workflow r\u00e9utilisable h\u00e9berg\u00e9 dans un d\u00e9p\u00f4t s\u00e9par\u00e9<\/strong>. Comme GitHub Actions isole les ex\u00e9cutions de workflows r\u00e9utilisables du workflow appelant, l&rsquo;\u00e9tape de g\u00e9n\u00e9ration de provenance est prot\u00e9g\u00e9e contre la falsification &mdash; m\u00eame un job de build compromis ne peut pas alt\u00e9rer la sortie de provenance.<\/p>\n<h3>Le Workflow<\/h3>\n<p>Cr\u00e9ez <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>Comprendre le Workflow<\/h3>\n<ul>\n<li>Le job <strong>build<\/strong> construit l&rsquo;image, la pousse vers GHCR et produit en sortie la r\u00e9f\u00e9rence de l&rsquo;image et le digest.<\/li>\n<li>Le job <strong>provenance<\/strong> appelle le workflow r\u00e9utilisable depuis le d\u00e9p\u00f4t <code>slsa-framework\/slsa-github-generator<\/code> \u00e0 un tag \u00e9pingl\u00e9 (<code>@v2.1.0<\/code>). Comme ce workflow s&rsquo;ex\u00e9cute dans un environnement isol\u00e9 contr\u00f4l\u00e9 par les mainteneurs du framework SLSA, il satisfait l&rsquo;exigence SLSA Level 3 d&rsquo;une plateforme de build renforc\u00e9e et non falsifiable.<\/li>\n<li>La provenance est sign\u00e9e en utilisant la signature sans cl\u00e9 de Sigstore (certificat Fulcio + journal de transparence Rekor) et attach\u00e9e \u00e0 l&rsquo;image dans GHCR sous forme d&rsquo;attestation cosign.<\/li>\n<\/ul>\n<h3>D\u00e9clencher le 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>Dans l&rsquo;onglet Actions, vous verrez deux jobs : <strong>build<\/strong> et <strong>provenance<\/strong>. Le job provenance g\u00e9n\u00e8re une attestation in-toto, la signe via Sigstore et pousse l&rsquo;attestation vers GHCR aux c\u00f4t\u00e9s de l&rsquo;image. Lorsque les deux jobs r\u00e9ussissent, votre image \u00e0 <code>ghcr.io\/YOUR_USER\/slsa-provenance-lab@sha256:&lt;digest&gt;<\/code> porte d\u00e9sormais une attestation de provenance SLSA Level 3 sign\u00e9e.<\/p>\n<h2>Exercice 2 : G\u00e9n\u00e9rer la Provenance avec les GitHub Artifact Attestations<\/h2>\n<h3>L&rsquo;Approche Native de GitHub<\/h3>\n<p>GitHub fournit un m\u00e9canisme int\u00e9gr\u00e9 pour g\u00e9n\u00e9rer la provenance de build via l&rsquo;action <code>actions\/attest-build-provenance<\/code>. Cette approche est plus simple \u00e0 configurer et stocke les attestations dans le stockage d&rsquo;attestations propre \u00e0 GitHub, les rendant v\u00e9rifiables avec le CLI <code>gh<\/code>. Le compromis est que ces attestations suivent le chemin de v\u00e9rification propre \u00e0 GitHub plut\u00f4t que l&rsquo;outillage du framework SLSA.<\/p>\n<h3>Le Workflow<\/h3>\n<p>Cr\u00e9ez <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>Comparaison des Deux Approches<\/h3>\n<table>\n<thead>\n<tr>\n<th>Aspect<\/th>\n<th>slsa-github-generator<\/th>\n<th>GitHub Artifact Attestations<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Niveau SLSA<\/td>\n<td>Level 3 (workflow r\u00e9utilisable isol\u00e9)<\/td>\n<td>Level 2&ndash;3 (g\u00e9r\u00e9 par GitHub, workflow unique)<\/td>\n<\/tr>\n<tr>\n<td>Outil de v\u00e9rification<\/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>Stockage des attestations<\/td>\n<td>Registre OCI (aux c\u00f4t\u00e9s de l&rsquo;image)<\/td>\n<td>API d&rsquo;attestation GitHub + push OCI optionnel<\/td>\n<\/tr>\n<tr>\n<td>Complexit\u00e9 de mise en place<\/td>\n<td>Workflow \u00e0 deux jobs avec appel de workflow r\u00e9utilisable<\/td>\n<td>Workflow \u00e0 un seul job avec une \u00e9tape suppl\u00e9mentaire<\/td>\n<\/tr>\n<tr>\n<td>Signature<\/td>\n<td>Sigstore (Fulcio + Rekor)<\/td>\n<td>Sigstore (Fulcio + Rekor via GitHub)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Les deux approches sont valides. Utilisez <code>slsa-github-generator<\/code> lorsque vous avez besoin d&rsquo;une conformit\u00e9 stricte au SLSA Level 3 avec une v\u00e9rification multiplateforme. Utilisez les GitHub artifact attestations lorsque vous souhaitez une mise en place plus simple et que vos consommateurs utilisent d\u00e9j\u00e0 l&rsquo;\u00e9cosyst\u00e8me GitHub.<\/p>\n<h2>Exercice 3 : V\u00e9rifier la Provenance avec slsa-verifier<\/h2>\n<p>Le CLI <code>slsa-verifier<\/code> est l&rsquo;outil officiel pour v\u00e9rifier la provenance SLSA g\u00e9n\u00e9r\u00e9e par <code>slsa-github-generator<\/code>. Il v\u00e9rifie la signature cryptographique, l&rsquo;identit\u00e9 du builder, le d\u00e9p\u00f4t source et le digest de l&rsquo;artefact en une seule commande.<\/p>\n<h3>\u00c9tape 1 &mdash; Obtenir le Digest de l&rsquo;Image<\/h3>\n<p>R\u00e9cup\u00e9rez le digest de l&rsquo;image que vous avez pouss\u00e9e :<\/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>Vous pouvez \u00e9galement trouver le digest dans la sortie du workflow Actions ou sur la page du package GHCR.<\/p>\n<h3>\u00c9tape 2 &mdash; V\u00e9rification R\u00e9ussie<\/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>Sortie attendue :<\/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>\u00c9tape 3 &mdash; \u00c9chec de V\u00e9rification : URI Source Incorrect<\/h3>\n<p>Essayez de v\u00e9rifier contre un d\u00e9p\u00f4t source incorrect :<\/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>Sortie attendue :<\/p>\n<pre><code>FAILED: SLSA verification failed: source used to generate the binary does not match provenance<\/code><\/pre>\n<h3>\u00c9tape 4 &mdash; \u00c9chec de V\u00e9rification : Tag Incorrect<\/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>Sortie attendue :<\/p>\n<pre><code>FAILED: SLSA verification failed: tag \"v9.9.9\" does not match provenance<\/code><\/pre>\n<h3>Ce que slsa-verifier V\u00e9rifie<\/h3>\n<ul>\n<li><strong>Identit\u00e9 du builder<\/strong> &mdash; confirme que la provenance a \u00e9t\u00e9 cr\u00e9\u00e9e par le workflow r\u00e9utilisable officiel <code>slsa-github-generator<\/code> \u00e0 la r\u00e9f\u00e9rence attendue.<\/li>\n<li><strong>D\u00e9p\u00f4t source<\/strong> &mdash; la provenance doit r\u00e9f\u00e9rencer l&rsquo;URI source que vous sp\u00e9cifiez.<\/li>\n<li><strong>Tag\/branche source<\/strong> &mdash; v\u00e9rifie optionnellement la r\u00e9f\u00e9rence Git qui a d\u00e9clench\u00e9 le build.<\/li>\n<li><strong>Digest de l&rsquo;artefact<\/strong> &mdash; le digest SHA-256 enregistr\u00e9 dans la provenance doit correspondre \u00e0 l&rsquo;image que vous v\u00e9rifiez.<\/li>\n<li><strong>Signature et journal de transparence<\/strong> &mdash; la signature Sigstore est v\u00e9rifi\u00e9e contre le journal de transparence Rekor.<\/li>\n<\/ul>\n<h2>Exercice 4 : V\u00e9rifier avec cosign verify-attestation<\/h2>\n<p>Cosign fournit un moyen de plus bas niveau mais plus flexible pour v\u00e9rifier les attestations attach\u00e9es aux images container. C&rsquo;est utile lorsque vous devez inspecter le payload de provenance brut ou lors de l&rsquo;int\u00e9gration dans des pipelines de v\u00e9rification personnalis\u00e9s.<\/p>\n<h3>V\u00e9rifier l&rsquo;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 cas de succ\u00e8s, cosign affiche le payload de l&rsquo;attestation au format JSON. Un exemple tronqu\u00e9 :<\/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>Inspecter le Payload de Provenance<\/h3>\n<p>D\u00e9codez le payload en base64 pour inspecter les champs 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>Champs cl\u00e9s dans la sortie :<\/p>\n<ul>\n<li><strong><code>buildDefinition.buildType<\/code><\/strong> &mdash; identifie le syst\u00e8me de build (par exemple, <code>https:\/\/slsa-framework.github.io\/github-actions-buildtypes\/workflow\/v1<\/code>).<\/li>\n<li><strong><code>buildDefinition.externalParameters.workflow<\/code><\/strong> &mdash; le fichier de workflow et la r\u00e9f\u00e9rence qui ont ex\u00e9cut\u00e9 le build.<\/li>\n<li><strong><code>buildDefinition.resolvedDependencies<\/code><\/strong> &mdash; le commit Git, le d\u00e9p\u00f4t et les autres entr\u00e9es.<\/li>\n<li><strong><code>runDetails.builder.id<\/code><\/strong> &mdash; l&rsquo;URI du builder de confiance qui a g\u00e9n\u00e9r\u00e9 la provenance.<\/li>\n<\/ul>\n<h2>Exercice 5 : V\u00e9rifier avec gh attestation verify<\/h2>\n<p>Pour les images attest\u00e9es en utilisant les artifact attestations natifs de GitHub (Exercice 2), le CLI <code>gh<\/code> fournit le chemin de v\u00e9rification le plus simple.<\/p>\n<h3>V\u00e9rifier l&rsquo;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>Sortie attendue :<\/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>T\u00e9l\u00e9charger et Inspecter l&rsquo;Attestation<\/h3>\n<p>Pour t\u00e9l\u00e9charger le bundle d&rsquo;attestation brut pour une inspection hors ligne :<\/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# Inspecter le pr\u00e9dicat de provenance\ncat attestation-bundle.json | jq '.dsseEnvelope.payload' -r | base64 -d | jq .<\/code><\/pre>\n<p>Cela vous donne le pr\u00e9dicat de provenance SLSA complet, que vous pouvez stocker aux c\u00f4t\u00e9s de vos enregistrements de d\u00e9ploiement \u00e0 des fins d&rsquo;audit.<\/p>\n<h2>Exercice 6 : Appliquer la Provenance au Moment du D\u00e9ploiement<\/h2>\n<p>G\u00e9n\u00e9rer et v\u00e9rifier la provenance manuellement est pr\u00e9cieux, mais le v\u00e9ritable b\u00e9n\u00e9fice en termes de s\u00e9curit\u00e9 provient de l&rsquo;<strong>application automatis\u00e9e<\/strong> au moment du d\u00e9ploiement. Dans cet exercice, vous allez configurer une politique d&rsquo;admission Kubernetes qui rejette toute image container d\u00e9pourvue de provenance SLSA valide.<\/p>\n<h3>Option A : Sigstore Policy Controller<\/h3>\n<p>Le <a href=\"https:\/\/docs.sigstore.dev\/policy-controller\/overview\/\" target=\"_blank\" rel=\"noopener\">Sigstore policy-controller<\/a> est un webhook d&rsquo;admission Kubernetes qui v\u00e9rifie les signatures d&rsquo;images et les attestations avant que les pods ne soient admis.<\/p>\n<h4>Installer le 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>Cr\u00e9er une ClusterImagePolicy<\/h4>\n<p>Cr\u00e9ez <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>Appliquez-la :<\/p>\n<pre><code>kubectl apply -f slsa-policy.yml<\/code><\/pre>\n<h4>Labelliser le Namespace pour l&rsquo;Application<\/h4>\n<pre><code>kubectl label namespace default policy.sigstore.dev\/include=true<\/code><\/pre>\n<h3>Option B : Politique Kyverno<\/h3>\n<p>Si vous utilisez Kyverno comme moteur de politique, cr\u00e9ez <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>Appliquez-la :<\/p>\n<pre><code>kubectl apply -f kyverno-slsa-policy.yml<\/code><\/pre>\n<h3>Test : Image Avec Provenance (Admise)<\/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>R\u00e9sultat attendu : le pod est cr\u00e9\u00e9 avec succ\u00e8s.<\/p>\n<h3>Test : Image Sans Provenance (Rejet\u00e9e)<\/h3>\n<p>Poussez une image rapide sans 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>R\u00e9sultat attendu :<\/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>Cela confirme que la politique d&rsquo;admission bloque correctement les images d\u00e9pourvues de provenance SLSA.<\/p>\n<h2>Inspection du Document de Provenance<\/h2>\n<p>Comprendre le document de provenance est essentiel pour l&rsquo;audit et la construction d&rsquo;automatisations par-dessus. Ci-dessous se trouve un document de provenance repr\u00e9sentatif g\u00e9n\u00e9r\u00e9 par <code>slsa-github-generator<\/code>, suivi d&rsquo;une explication champ par champ.<\/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>Analyse Champ par Champ<\/h3>\n<ul>\n<li><strong><code>_type<\/code><\/strong> &mdash; identifie ceci comme une d\u00e9claration (Statement) <a href=\"https:\/\/in-toto.io\" target=\"_blank\" rel=\"noopener\">in-toto<\/a> v1, le format d&rsquo;enveloppe utilis\u00e9 par SLSA.<\/li>\n<li><strong><code>subject<\/code><\/strong> &mdash; l&rsquo;artefact que cette provenance d\u00e9crit. Contient le nom de l&rsquo;image et son digest SHA-256. C&rsquo;est ce que vous comparez avec l&rsquo;image que vous v\u00e9rifiez.<\/li>\n<li><strong><code>predicateType<\/code><\/strong> &mdash; d\u00e9clare que cette attestation est une provenance SLSA v1. Les outils de v\u00e9rification l&rsquo;utilisent pour d\u00e9terminer comment interpr\u00e9ter le pr\u00e9dicat.<\/li>\n<li><strong><code>buildDefinition.buildType<\/code><\/strong> &mdash; sp\u00e9cifie le syst\u00e8me de build. Pour GitHub Actions, cela indique aux v\u00e9rificateurs d&rsquo;attendre des champs sp\u00e9cifiques \u00e0 GitHub.<\/li>\n<li><strong><code>buildDefinition.externalParameters.workflow<\/code><\/strong> &mdash; le fichier de workflow, le d\u00e9p\u00f4t et la r\u00e9f\u00e9rence Git qui ont d\u00e9clench\u00e9 le build. Vous devez v\u00e9rifier que cela correspond \u00e0 la source attendue.<\/li>\n<li><strong><code>buildDefinition.resolvedDependencies<\/code><\/strong> &mdash; liste les entr\u00e9es r\u00e9solues, y compris le commit Git exact. C&rsquo;est la liste des \u00ab mat\u00e9riaux \u00bb &mdash; elle fournit un enregistrement complet de ce qui est entr\u00e9 dans le build.<\/li>\n<li><strong><code>runDetails.builder.id<\/code><\/strong> &mdash; l&rsquo;URI du builder qui a g\u00e9n\u00e9r\u00e9 la provenance. Pour le SLSA Level 3, il doit s&rsquo;agir d&rsquo;un builder de confiance et isol\u00e9 comme le workflow r\u00e9utilisable <code>slsa-github-generator<\/code> \u00e0 un tag \u00e9pingl\u00e9.<\/li>\n<li><strong><code>runDetails.metadata<\/code><\/strong> &mdash; horodatages et lien vers l&rsquo;ex\u00e9cution sp\u00e9cifique de GitHub Actions, permettant une tra\u00e7abilit\u00e9 compl\u00e8te de l&rsquo;artefact jusqu&rsquo;au build.<\/li>\n<\/ul>\n<p>Lors de la construction d&rsquo;une v\u00e9rification automatis\u00e9e, v\u00e9rifiez toujours : (1) le digest du sujet correspond, (2) l&rsquo;identifiant du builder est dans votre liste autoris\u00e9e, (3) le d\u00e9p\u00f4t source et la r\u00e9f\u00e9rence correspondent \u00e0 vos attentes, et (4) la signature est valide.<\/p>\n<h2>Nettoyage<\/h2>\n<p>Supprimez les ressources cr\u00e9\u00e9es pendant ce lab :<\/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>Points Cl\u00e9s \u00e0 Retenir<\/h2>\n<ul>\n<li><strong>La provenance SLSA est un enregistrement sign\u00e9 et inviolable<\/strong> de la fa\u00e7on dont une image container a \u00e9t\u00e9 construite. Elle capture la source, le builder et les param\u00e8tres de build.<\/li>\n<li><strong>Le SLSA Level 3 exige l&rsquo;isolation du build<\/strong> &mdash; <code>slsa-github-generator<\/code> y parvient en ex\u00e9cutant la g\u00e9n\u00e9ration de provenance dans un workflow r\u00e9utilisable s\u00e9par\u00e9 que le d\u00e9veloppeur ne peut pas modifier \u00e0 l&rsquo;ex\u00e9cution.<\/li>\n<li><strong>Les GitHub artifact attestations<\/strong> fournissent une alternative plus simple qui s&rsquo;int\u00e8gre \u00e9troitement \u00e0 l&rsquo;\u00e9cosyst\u00e8me GitHub, avec des compromis en termes de portabilit\u00e9 multiplateforme.<\/li>\n<li><strong>La v\u00e9rification doit \u00eatre automatis\u00e9e<\/strong> &mdash; utilisez <code>slsa-verifier<\/code> dans les portes CI, <code>cosign verify-attestation<\/code> dans les scripts, ou les contr\u00f4leurs d&rsquo;admission Kubernetes pour appliquer la provenance avant le d\u00e9ploiement.<\/li>\n<li><strong>La v\u00e9rification de provenance v\u00e9rifie plusieurs affirmations<\/strong> : l&rsquo;identit\u00e9 du builder, le d\u00e9p\u00f4t source, la r\u00e9f\u00e9rence source, le digest de l&rsquo;artefact et la validit\u00e9 de la signature cryptographique.<\/li>\n<li><strong>Inspectez les documents de provenance<\/strong> pour comprendre exactement ce qui a \u00e9t\u00e9 construit, \u00e0 partir de quel commit, par quel builder. C&rsquo;est votre piste d&rsquo;audit pour les incidents de cha\u00eene d&rsquo;approvisionnement.<\/li>\n<\/ul>\n<h2>Prochaines \u00c9tapes<\/h2>\n<p>Continuez \u00e0 renforcer la s\u00e9curit\u00e9 de votre cha\u00eene d&rsquo;approvisionnement logicielle :<\/p>\n<ul>\n<li><a href=\"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/artifact-provenance-attestations-slsa-in-toto-2\/\">Provenance des Artefacts et Attestations : De SLSA \u00e0 in-toto<\/a> &mdash; approfondissez le framework SLSA, les formats d&rsquo;attestation in-toto et comment construire une strat\u00e9gie de provenance compl\u00e8te \u00e0 travers l&rsquo;ensemble de votre pipeline de build.<\/li>\n<li><a href=\"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/signing-verifying-container-images-sigstore-cosign\/\">Signature et V\u00e9rification des Images Container avec Sigstore et Cosign<\/a> &mdash; apprenez \u00e0 signer des images container avec la signature sans cl\u00e9 Sigstore, \u00e0 v\u00e9rifier les signatures en CI\/CD et \u00e0 appliquer les politiques de signature dans Kubernetes.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Pr\u00e9sentation La provenance SLSA (Supply-chain Levels for Software Artifacts) est un enregistrement v\u00e9rifiable qui d\u00e9crit comment un artefact a \u00e9t\u00e9 construit : le d\u00e9p\u00f4t source, la plateforme de build, le point d&rsquo;entr\u00e9e et les mat\u00e9riaux d&rsquo;entr\u00e9e. Lorsqu&rsquo;elle est associ\u00e9e \u00e0 une image container, la provenance permet aux consommateurs de r\u00e9pondre \u00e0 une question critique avant &#8230; <a title=\"Lab : G\u00e9n\u00e9ration et V\u00e9rification de la Provenance SLSA pour les Images Container\" class=\"read-more\" href=\"https:\/\/secure-pipelines.com\/fr\/ci-cd-security\/lab-generating-verifying-slsa-provenance-container-images\/\" aria-label=\"En savoir plus sur Lab : G\u00e9n\u00e9ration et V\u00e9rification de la Provenance SLSA pour les Images Container\">Lire la suite<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[49,50],"tags":[],"post_folder":[],"class_list":["post-530","post","type-post","status-publish","format-standard","hentry","category-ci-cd-security","category-software-supply-chain"],"_links":{"self":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts\/530","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/comments?post=530"}],"version-history":[{"count":2,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts\/530\/revisions"}],"predecessor-version":[{"id":579,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/posts\/530\/revisions\/579"}],"wp:attachment":[{"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/media?parent=530"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/categories?post=530"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/tags?post=530"},{"taxonomy":"post_folder","embeddable":true,"href":"https:\/\/secure-pipelines.com\/fr\/wp-json\/wp\/v2\/post_folder?post=530"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}