Une image signée prouve qu’elle vient bien du pipeline qui l’a signée. Elle ne prouve rien sur ce que ce pipeline a réellement fait pour la produire : quel code source, avec quelles dépendances, sur quelle machine, avec quels privilèges. Un pipeline compromis qui construit une image malveillante peut la signer tout aussi légitimement qu’une image saine, signée par la même identité, avec la même clé. La signature répond à « qui a produit ceci », pas à « comment ».

Ce que la provenance ajoute à la signature

Une attestation de provenance est un document signé qui accompagne l’artefact et décrit sa construction : le commit source exact, les paramètres du build, l’identité du système qui l’a exécuté, l’heure. La spécification in-toto formalise ce format, indépendamment de l’outil qui le produit.

// Attestation de provenance simplifiée (format in-toto)
{
  "predicateType": "https://slsa.dev/provenance/v1",
  "subject": [{ "name": "registry.exemple.com/app", "digest": { "sha256": "1e9c...a41f" } }],
  "predicate": {
    "buildDefinition": {
      "buildType": "https://github.com/actions/runner",
      "externalParameters": { "repository": "acme/app", "ref": "refs/heads/main" }
    },
    "runDetails": {
      "builder": { "id": "https://github.com/acme/app/.github/workflows/build.yml" }
    }
  }
}

Cette attestation répond à une question que la signature seule ne pose même pas : est-ce que cette image a été construite par le pipeline officiel, à partir du code du dépôt principal, ou par n’importe quel processus capable d’obtenir une identité OIDC valide ?

SLSA : des niveaux, pas un interrupteur

Le framework SLSA (Supply-chain Levels for Software Artifacts) définit des niveaux de maturité croissante, pas un état binaire conforme/non conforme. Le niveau 1 exige une provenance documentée, générée par un processus automatisé. Le niveau 2 exige que ce processus tourne sur une plateforme de build hébergée, pas sur un poste de développeur. Le niveau 3 exige l’isolation entre builds : qu’un build ne puisse ni lire ni influencer les secrets ou artefacts d’un autre build sur la même infrastructure.

# GitHub Actions : générateur SLSA officiel, produit une provenance
# de niveau 3 sans réimplémenter la spécification soi-même
- uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
  with:
    base64-subjects: "${{ needs.build.outputs.digests }}"

Viser le niveau 3 directement sur un pipeline qui n’a même pas de provenance documentée aujourd’hui revient à optimiser un problème avant d’avoir mesuré s’il existe. La progression par niveau évite ce piège : chaque niveau ajoute une garantie précise, vérifiable indépendamment des suivants.

Vérifier une attestation à l’admission

Une attestation que personne ne vérifie a la même valeur qu’une signature ignorée : aucune. Une politique d’admission Kubernetes peut exiger, en plus de la signature déjà couverte par le scan et la signature d’images, la présence d’une attestation de provenance conforme à un builder spécifique avant d’admettre un pod.

# Kyverno : exige une attestation de provenance signée par le
# builder GitHub Actions officiel, en plus de la signature d'image
verifyImages:
  - imageReferences: ["registry.exemple.com/*"]
    attestations:
      - predicateType: https://slsa.dev/provenance/v1
        attestors:
          - entries:
              - keyless:
                  issuer: "https://token.actions.githubusercontent.com"

Ce contrôle ferme une brèche que la seule signature laisse ouverte : une identité OIDC légitime, mais utilisée depuis un pipeline différent de celui attendu (un fork, une branche non protégée), signe une image qui passerait la vérification de signature seule, mais pas la vérification d’attestation qui exige un builder précis.

Où ça s’arrête d’être pertinent

SLSA niveau 3 et au-delà (l’isolation hermétique complète, la reproductibilité bit-à-bit du build) a un coût d’infrastructure réel, justifié pour un éditeur de logiciel distribué à grande échelle ou un fournisseur soumis à des obligations réglementaires strictes. Pour une PME qui livre son propre produit en interne, le niveau 2 (build hébergé, provenance signée et vérifiée à l’admission) couvre déjà l’essentiel du risque réaliste : un pipeline compromis qui produit une image malveillante sans que rien ne le détecte avant la production.

À retenir

Une signature d’image prouve une identité ; une attestation de provenance prouve un processus de construction. SLSA structure cette maturité en niveaux progressifs plutôt qu’en un état binaire, et chaque niveau n’a de valeur que si l’attestation qu’il produit est effectivement vérifiée à l’admission, pas seulement générée puis archivée. Ce socle fait partie de ce qui se met en place lors de l’industrialisation d’une chaîne CI/CD confrontée à des exigences de conformité réelles.