Générer des attestations n'a de valeur que si elles sont vérifiées. Ce guide explique comment valider la provenance de vos artefacts avant de les déployer.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Vérifier un artefact avec
gh attestation verify - Bloquer un déploiement non vérifié dans un workflow CI/CD
- Utiliser cosign et slsa-verifier pour la vérification SLSA
- Afficher le niveau SLSA atteint via un badge README
- Imposer la vérification à l'admission dans Kubernetes
Pourquoi vérifier ?
Section intitulée « Pourquoi vérifier ? »Vérifier une attestation, c'est s'assurer qu'un artefact est bien celui qu'on croit. Une attestation prouve :
- L'artefact vient du bon repository
- Il a été construit par le bon workflow
- Le code source correspond au commit attendu
- La signature est valide (pas de modification)
Sans vérification, un attaquant pourrait substituer un artefact malveillant sans que rien ne le signale.
Avec la CLI GitHub
Section intitulée « Avec la CLI GitHub »La CLI GitHub (gh) est le moyen le plus direct de vérifier une
attestation : elle interroge l'API GitHub et valide la signature Sigstore.
Installation
Section intitulée « Installation »Installez la CLI selon votre système :
# macOSbrew install gh
# Linux (Debian/Ubuntu)curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpgecho "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.listsudo apt update && sudo apt install ghVoir le guide GitHub CLI pour l'installation complète et l'authentification.
Vérifier un fichier local
Section intitulée « Vérifier un fichier local »Pointez la commande sur le fichier téléchargé et indiquez le dépôt attendu :
# Vérifier un artefact téléchargégh attestation verify my-app-v1.0.0.tar.gz --owner owner --repo repoSortie en cas de succès :
Loaded digest sha256:abc123... for file my-app-v1.0.0.tar.gzLoaded 1 attestation from GitHub API✓ Verification succeeded!
SHA256 digest: abc123...Sigstore Bundle: presentCertificate Subject: https://github.com/owner/repo/.github/workflows/release.yml@refs/tags/v1.0.0Certificate Issuer: https://token.actions.githubusercontent.comVérifier une image Docker
Section intitulée « Vérifier une image Docker »Pour une image, préfixez la référence par oci:// :
# Vérifier une image depuis un registrygh attestation verify oci://ghcr.io/owner/app:v1.0.0 --owner ownerOptions de vérification
Section intitulée « Options de vérification »Plusieurs options resserrent la vérification — digest exact, workflow signataire, sortie machine :
# Vérifier avec un digest spécifiquegh attestation verify --digest sha256:abc123... --owner owner --repo repo
# Vérifier que le workflow source est correctgh attestation verify my-app.tar.gz \ --owner owner \ --repo repo \ --signer-workflow release.yml
# Format JSON pour traitement automatiségh attestation verify my-app.tar.gz --owner owner --format jsonDans un workflow CI/CD
Section intitulée « Dans un workflow CI/CD »La vérification prend tout son sens automatisée : un déploiement ne doit jamais consommer un artefact dont la provenance n'a pas été validée.
Vérifier avant déploiement
Section intitulée « Vérifier avant déploiement »Ce workflow télécharge un artefact, vérifie son attestation, et ne déploie que si la vérification réussit.
name: Deploy
on: workflow_dispatch: inputs: version: description: 'Version to deploy' required: true
permissions: {}
jobs: deploy: runs-on: ubuntu-24.04 permissions: contents: read steps: - name: Télécharger l'artefact env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} VERSION: ${{ inputs.version }} run: | gh release download "$VERSION" \ --repo "$GITHUB_REPOSITORY" \ --pattern "my-app-*.tar.gz"
- name: Vérifier l'attestation env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh attestation verify my-app-*.tar.gz \ --owner "$GITHUB_REPOSITORY_OWNER" \ --repo "${GITHUB_REPOSITORY#*/}"
- name: Déployer (uniquement si la vérification a réussi) run: ./deploy.sh my-app-*.tar.gzVérifier une image avant pull
Section intitulée « Vérifier une image avant pull »Même principe pour une image : on valide l'attestation avant le docker pull.
name: Deploy Image
on: workflow_dispatch: inputs: version: description: 'Version to deploy' required: true
permissions: {}
jobs: deploy: runs-on: ubuntu-24.04 permissions: contents: read steps: - name: Vérifier l'attestation de l'image env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} VERSION: ${{ inputs.version }} run: | gh attestation verify \ "oci://ghcr.io/$GITHUB_REPOSITORY:$VERSION" \ --owner "$GITHUB_REPOSITORY_OWNER"
- name: Pull et déploiement env: VERSION: ${{ inputs.version }} run: | docker pull "ghcr.io/$GITHUB_REPOSITORY:$VERSION" kubectl set image deployment/app "app=ghcr.io/$GITHUB_REPOSITORY:$VERSION"Avec cosign
Section intitulée « Avec cosign »cosign est l'outil de signature de Sigstore, utilisé en coulisse par les attestations GitHub.
Installation
Section intitulée « Installation »Installez le binaire cosign :
# macOSbrew install cosign
# Linuxcurl -LO https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64sudo install cosign-linux-amd64 /usr/local/bin/cosignVérifier une image
Section intitulée « Vérifier une image »cosign verify contrôle la signature keyless contre l'identité du workflow
attendu :
# Vérifier avec les certificats Sigstorecosign verify \ --certificate-identity-regexp="https://github.com/owner/repo/.github/workflows/*" \ --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \ ghcr.io/owner/app:v1.0.0Vérifier l'attestation SLSA
Section intitulée « Vérifier l'attestation SLSA »cosign verify-attestation valide en plus le prédicat de provenance SLSA :
# Télécharger et vérifier l'attestationcosign verify-attestation \ --type slsaprovenance \ --certificate-identity-regexp="https://github.com/owner/repo/.github/workflows/*" \ --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \ ghcr.io/owner/app:v1.0.0Avec slsa-verifier
Section intitulée « Avec slsa-verifier »slsa-verifier est l'outil officiel SLSA pour vérifier les attestations de provenance.
Installation
Section intitulée « Installation »Installez-le via Go ou en téléchargeant le binaire :
# Go installgo install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@latest
# Ou télécharger le binairecurl -LO https://github.com/slsa-framework/slsa-verifier/releases/latest/download/slsa-verifier-linux-amd64chmod +x slsa-verifier-linux-amd64sudo mv slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifierVérifier un artefact local
Section intitulée « Vérifier un artefact local »Téléchargez l'artefact et son fichier de provenance, puis lancez la vérification :
# Télécharger l'artefact et son attestation depuis une releasegh release download v1.0.0 --repo owner/repo --pattern "*.tar.gz"gh release download v1.0.0 --repo owner/repo --pattern "*.intoto.jsonl"
# Vérifier avec slsa-verifierslsa-verifier verify-artifact my-app-v1.0.0.tar.gz \ --provenance-path my-app-v1.0.0.intoto.jsonl \ --source-uri github.com/owner/repo \ --source-tag v1.0.0Sortie en cas de succès :
Verified signature against tlog entry index 12345 at URL https://rekor.sigstore.devVerified build using builder "https://github.com/actions/runner" at commit abc123def456SLSA verification passed✓ Verification succeeded!Vérifier une image conteneur
Section intitulée « Vérifier une image conteneur »Pour une image, préférez la vérification par digest plutôt que par tag :
# Vérifier une image GHCR avec tagslsa-verifier verify-image ghcr.io/owner/app:v1.0.0 \ --source-uri github.com/owner/repo \ --source-tag v1.0.0
# Vérifier avec un digest (plus sûr)slsa-verifier verify-image ghcr.io/owner/app@sha256:abc123... \ --source-uri github.com/owner/repo \ --source-tag v1.0.0Afficher le niveau SLSA atteint
Section intitulée « Afficher le niveau SLSA atteint »L'option --print-provenance affiche le prédicat complet, dont le buildType
qui détermine le niveau SLSA :
# Vérifier et afficher le niveau SLSA en mode verbeuxslsa-verifier verify-image ghcr.io/owner/app:v1.0.0 \ --source-uri github.com/owner/repo \ --source-tag v1.0.0 \ --print-provenanceSortie détaillée :
{ "_type": "https://in-toto.io/Statement/v1", "subject": [ { "name": "ghcr.io/owner/app", "digest": {"sha256": "abc123..."} } ], "predicateType": "https://slsa.dev/provenance/v1", "predicate": { "buildDefinition": { "buildType": "https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1" } }}Niveau SLSA :
| buildType | Niveau SLSA |
|---|---|
workflow/v1 | SLSA L3 |
workflow/v0 | SLSA L2 |
Script de vérification complet
Section intitulée « Script de vérification complet »Ce script enchaîne la vérification et l'affichage du niveau SLSA, et échoue proprement en cas de problème :
#!/bin/bash# verify-slsa.sh - Vérifier et afficher le niveau SLSA
set -e
IMAGE="$1"SOURCE_URI="$2"SOURCE_TAG="$3"
if [ -z "$IMAGE" ] || [ -z "$SOURCE_URI" ] || [ -z "$SOURCE_TAG" ]; then echo "Usage: $0 <image> <source-uri> <source-tag>" echo "Exemple: $0 ghcr.io/owner/app:v1.0.0 github.com/owner/repo v1.0.0" exit 1fi
echo "Vérification SLSA de $IMAGE"echo ""
# Vérifier avec slsa-verifierif slsa-verifier verify-image "$IMAGE" \ --source-uri "$SOURCE_URI" \ --source-tag "$SOURCE_TAG" \ --print-provenance > /tmp/slsa-provenance.json 2>&1; then
echo "Vérification SLSA réussie" echo ""
# Extraire le niveau SLSA BUILD_TYPE=$(jq -r '.predicate.buildDefinition.buildType' /tmp/slsa-provenance.json)
echo "Niveau SLSA atteint :" if [[ "$BUILD_TYPE" == *"workflow/v1"* ]]; then echo " SLSA Level 3" elif [[ "$BUILD_TYPE" == *"workflow/v0"* ]]; then echo " SLSA Level 2" else echo " Niveau inconnu : $BUILD_TYPE" fi
echo "" echo "Détails de provenance :" jq '{repository: .predicate.buildDefinition.externalParameters.workflow.repository, ref: .predicate.buildDefinition.externalParameters.workflow.ref, builder: .predicate.runDetails.builder.id}' /tmp/slsa-provenance.json
else echo "Échec de la vérification SLSA" exit 1fiUtilisation :
chmod +x verify-slsa.sh./verify-slsa.sh ghcr.io/stephrobert/test-sigstore:v1.0.2 github.com/stephrobert/test-sigstore v1.0.2Afficher le badge SLSA dans le README
Section intitulée « Afficher le badge SLSA dans le README »Pour communiquer le niveau SLSA atteint, ajoutez un badge dans votre
README.md.
Badge statique
Section intitulée « Badge statique »Le badge statique reflète le niveau visé — à mettre à jour si le projet progresse :
<!-- Badge SLSA Level 3 -->[](https://slsa.dev)
<!-- Badge SLSA Level 2 -->[](https://slsa.dev)
<!-- Badge SLSA Level 1 -->[](https://slsa.dev)Rendu :
Badge dynamique avec OpenSSF Scorecard
Section intitulée « Badge dynamique avec OpenSSF Scorecard »Ce badge se met à jour automatiquement avec le score réel du dépôt :
[](https://scorecard.dev/viewer/?uri=github.com/owner/repo)Ce badge affiche le score global (qui inclut SLSA parmi d'autres critères).
Badge de vérification continue
Section intitulée « Badge de vérification continue »Si vous avez un workflow de vérification automatique, son badge de statut prouve que la vérification tourne réellement :
[](https://github.com/owner/repo/actions/workflows/verify-slsa.yml)Exemple de README complet
Section intitulée « Exemple de README complet »Voici comment ces badges et la section sécurité s'assemblent dans un README :
# Mon Application
[](https://slsa.dev)[](https://scorecard.dev/viewer/?uri=github.com/owner/repo)[](https://github.com/owner/repo/actions/workflows/release.yml)
## Supply Chain Security
Ce projet atteint **SLSA Level 3** pour garantir la traçabilité de la chaîne d'approvisionnement :
- Provenance SLSA générée pour chaque release- Signatures Sigstore sur toutes les images- Attestations vérifiables avec `gh attestation verify`
### Vérifier une release
```bash# Vérifier l'image Dockergh attestation verify oci://ghcr.io/owner/repo:v1.0.0 --owner owner
# Avec slsa-verifierslsa-verifier verify-image ghcr.io/owner/repo:v1.0.0 \ --source-uri github.com/owner/repo \ --source-tag v1.0.0```Workflow de vérification automatique
Section intitulée « Workflow de vérification automatique »Créez .github/workflows/verify-slsa.yml pour vérifier automatiquement vos
releases, chaque nuit :
name: SLSA Verification
on: schedule: # Vérifier toutes les nuits - cron: '0 2 * * *' workflow_dispatch:
permissions: {}
jobs: verify: runs-on: ubuntu-24.04 permissions: contents: read steps: - name: Installer slsa-verifier run: | curl -LO https://github.com/slsa-framework/slsa-verifier/releases/latest/download/slsa-verifier-linux-amd64 chmod +x slsa-verifier-linux-amd64 sudo mv slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier
- name: Récupérer la dernière release id: latest env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | LATEST_TAG=$(gh release view --repo "$GITHUB_REPOSITORY" --json tagName -q .tagName) echo "tag=$LATEST_TAG" >> "$GITHUB_OUTPUT"
- name: Vérifier la provenance SLSA env: RELEASE_TAG: ${{ steps.latest.outputs.tag }} run: | slsa-verifier verify-image "ghcr.io/$GITHUB_REPOSITORY:$RELEASE_TAG" \ --source-uri "github.com/$GITHUB_REPOSITORY" \ --source-tag "$RELEASE_TAG" \ --print-provenance
- name: Rapporter le statut if: always() env: JOB_STATUS: ${{ job.status }} RELEASE_TAG: ${{ steps.latest.outputs.tag }} run: | if [ "$JOB_STATUS" = "success" ]; then echo "Vérification SLSA réussie pour $RELEASE_TAG" else echo "Vérification SLSA échouée pour $RELEASE_TAG" exit 1 fiCe workflow :
- S'exécute chaque nuit à 2h
- Récupère la dernière release
- Vérifie son attestation SLSA
- Échoue si la vérification rate
Vous pouvez ensuite afficher le badge de ce workflow dans votre README.
Automatiser dans Kubernetes
Section intitulée « Automatiser dans Kubernetes »La vérification peut être imposée à l'admission : le cluster refuse tout pod dont l'image n'a pas d'attestation valide.
Avec Kyverno
Section intitulée « Avec Kyverno »Kyverno applique une politique qui exige une attestation keyless GitHub sur les images :
apiVersion: policies.kyverno.io/v1kind: ImageValidatingPolicymetadata: name: verify-attestationspec: validationActions: [Deny] matchConstraints: resourceRules: - apiGroups: [""] apiVersions: ["v1"] operations: ["CREATE", "UPDATE"] resources: ["pods"] matchImageReferences: - glob: "ghcr.io/owner/*" attestors: - name: github-keyless cosign: keyless: identities: - issuer: "https://token.actions.githubusercontent.com" subjectRegExp: "^https://github.com/owner/" validations: - expression: "true" message: "Image must have a valid SLSA provenance attestation."Avec Sigstore Policy Controller
Section intitulée « Avec Sigstore Policy Controller »Le Policy Controller de Sigstore propose une ClusterImagePolicy au rôle
équivalent :
apiVersion: policy.sigstore.dev/v1beta1kind: ClusterImagePolicymetadata: name: github-attestationspec: images: - glob: "ghcr.io/owner/**" authorities: - keyless: identities: - issuer: "https://token.actions.githubusercontent.com" subjectRegExp: "https://github.com/owner/.*"Erreurs courantes
Section intitulée « Erreurs courantes »Trois échecs reviennent souvent — chacun a une cause précise et une parade.
"No attestations found"
Section intitulée « "No attestations found" »Error: no attestations found for digest sha256:abc123Causes possibles :
- L'artefact n'a pas d'attestation générée
- Le digest ne correspond pas
- Le repository n'a pas activé les attestations
"Verification failed"
Section intitulée « "Verification failed" »Error: verification failed: signature mismatchCauses possibles :
- L'artefact a été modifié après la signature
- Le mauvais fichier est vérifié
- L'attestation vient d'un autre artefact
"Certificate identity mismatch"
Section intitulée « "Certificate identity mismatch" »Error: certificate identity mismatchCause : le workflow qui a signé ne correspond pas aux critères attendus.
Solution : vérifier --signer-workflow ou --certificate-identity-regexp.
Checklist de vérification
Section intitulée « Checklist de vérification »Avant de valider une vérification, parcourez cette liste — chaque point ferme une voie de contournement :
- Vérifier que le digest SHA256 correspond à l'artefact
- Vérifier le repository source (
--owner,--repo) - Vérifier le workflow source si critique (
--signer-workflow) - Vérifier la version/tag attendu
- Automatiser la vérification dans le pipeline de déploiement
À retenir
Section intitulée « À retenir »- Une attestation non vérifiée ne protège de rien : la vérification est l'étape qui ferme la boucle.
gh attestation verifyest le moyen le plus direct ;cosignetslsa-verifiercouvrent les besoins SLSA avancés.- En CI/CD, vérifier avant de déployer : aucun artefact non validé ne doit atteindre la production.
- L'option
--print-provenancerévèle lebuildType, donc le niveau SLSA réellement atteint. - Dans Kubernetes, Kyverno ou le Policy Controller Sigstore imposent la vérification à l'admission.
Prochaines étapes
Section intitulée « Prochaines étapes »Pour la référence complète, consultez la documentation de gh attestation verify et le dépôt slsa-verifier.