Aller au contenu

Signer et vérifier les artefacts de build

Une chaîne de build doit produire des artefacts traçables, signés et refusés dès que leur provenance ne peut pas être prouvée. La règle à retenir est brutale : signer sans vérifier au déploiement ne protège que le tableau de bord du pipeline.

→ Lire l’explication complète de la marmotte

La signature d’un artefact associe son contenu exact à une identité de signature. Modifier un seul octet d’un binaire, d’un paquet ou d’une image produit une empreinte différente, donc invalide la signature. Une empreinte seule détecte une altération, mais ne dit pas qui a publié l’artefact : un attaquant peut remplacer le fichier et son empreinte dans le même registre. La signature apporte cette identité, sous réserve que la clé reste sous contrôle.

Le compromis central est connu : plus la clé de signature est isolée, plus l’automatisation de build devient contraignante. Ce coût doit être assumé. Une clé privée exportable dans une variable secrète du pipeline facilite l’intégration, mais transforme tout exécuteur compromis en autorité de publication. Une clé non exportable dans un HSM (Hardware Security Module) ou un service de gestion de clés réduit ce risque, au prix d’autorisations, de quotas et d’une reprise après incident à concevoir sérieusement.

La clé de build ne doit jamais être une clé de développeur individuel. Les deux répondent à des identités et à des responsabilités différentes. Une clé humaine prouve une action humaine, une clé de chaîne continue prouve qu’un pipeline autorisé a produit un artefact depuis une source contrôlée. Mélanger les deux rend l’audit inutile et la révocation franchement pénible.

Pour des binaires et paquets, publier le certificat X.509 de signature de code, ou au minimum la clé publique, dans un dépôt de confiance versionné. Un certificat X.509 lie une clé publique à une identité et à une période de validité. Son profil doit limiter les usages à la signature de code, avec une autorité de certification interne ou publique selon la distribution visée. Une clé destinée aux images de conteneurs peut être distincte, car le registre, la durée de vie et le mécanisme de vérification diffèrent.

La signature ne garantit PAS que le code est sain, que les dépendances ne comportent aucune faille, ni que la revue a été correcte. Elle garantit qu’un contenu précis a été autorisé par une clé donnée. La qualité du code vient des contrôles de source, de la revue, de l’analyse de dépendances et des fondations de développement. La signature n’est pas un désinfectant cryptographique. Les slides qui suggèrent le contraire méritent surtout une signature, puis une vérification.

Clé dédiée, HSM et cycle de vie cryptographique

Section intitulée « Clé dédiée, HSM et cycle de vie cryptographique »

Créer une clé asymétrique dédiée par domaine de confiance : production, préproduction et développement ne partagent pas la même clé. Une compromission de l’environnement de développement ne doit pas permettre de signer un artefact déployable en production. Cette séparation vaut aussi pour les registres de conteneurs, les dépôts de paquets et les familles de produits quand leurs équipes d’exploitation ne partagent pas le même périmètre.

Un HSM conserve la clé privée dans un matériel conçu pour empêcher son exportation. L’application ou le pipeline demande une opération de signature, le module retourne une signature, mais la clé ne sort pas. Avec l’interface PKCS#11 (Public-Key Cryptography Standards #11), le pipeline référence un objet cryptographique par une URI au lieu de lire un fichier de clé. Un coffre-fort de secrets reste acceptable si la clé est chiffrée et délivrée à un exécuteur éphémère, mais il constitue un compromis moins protecteur qu’une clé non exportable.

Avant de générer la clé, quatre prérequis doivent exister :

  1. Un registre capable de conserver les signatures associées aux images.
  2. Un exécuteur de pipeline isolé, éphémère et réservé aux branches protégées.
  3. Un contrôle d’accès fédéré entre le pipeline et le HSM ou le coffre-fort, sans mot de passe statique partagé.
  4. Un mécanisme de vérification obligatoire dans la chaîne de déploiement et, pour Kubernetes, au niveau de l’admission.

Configurer une autorisation de signature limitée à l’identité du pipeline, au dépôt concerné et aux références de branches protégées. Un jeton de pipeline ayant le droit de signer toutes les images de tous les projets est une clé passe-partout avec une moustache de conformité dessinée dessus.

Prévoir une rotation au moins annuelle, et immédiatement après compromission présumée d’un exécuteur, d’un compte de déploiement ou d’une politique d’accès au HSM. La rotation implique une période où les vérificateurs acceptent l’ancienne et la nouvelle clé, puis le retrait explicite de l’ancienne. Ne pas supprimer une clé avant d’avoir inventorié les artefacts encore déployés et les mécanismes qui les vérifient.

Sauvegarder les métadonnées de clé, les certificats, les politiques d’accès, les journaux d’audit et les procédures de restauration. La sauvegarde d’une clé privée non exportable dépend du mécanisme de réplication du HSM, pas d’une copie de fichier. Exporter la clé pour la sauvegarder annule précisément la propriété recherchée. Les détails de hiérarchie, d’enveloppe cryptographique et de rotation figurent dans les principes de cryptographie appliquée et dans la page sur le module cryptographique matériel PKCS#11.

Sigstore est un ensemble d’outils de signature et de transparence pour les artefacts logiciels. cosign signe notamment les images de conteneurs. L’image doit être identifiée par son condensat, aussi appelé digest, et non seulement par un tag. Un tag comme production ou 1.4 est mutable : il peut pointer vers un autre contenu sans modifier le manifeste de déploiement. Un digest SHA-256 désigne un contenu déterminé.

L’exemple suivant utilise une clé cosign dans un emplacement PKCS#11. Le jeton matériel doit être initialisé auparavant, et l’exécuteur doit disposer de la bibliothèque PKCS#11 du fournisseur. La commande ne crée pas de clé exportable sur le disque.

Fenêtre de terminal
# Créer une paire dédiée dans un jeton PKCS#11.
# Le code PIN provient d'un mécanisme d'authentification du runner, pas d'un fichier CI.
export COSIGN_PASSWORD="${HSM_PIN}"
cosign generate-key-pair \
--output-key-prefix build-production \
"pkcs11:token=build-signing;object=cosign-production;type=private"
# Construire et publier une image, puis récupérer son digest immuable.
docker build -t registry.example.net/paiement/api:1.8.2 .
docker push registry.example.net/paiement/api:1.8.2
DIGEST="$(crane digest registry.example.net/paiement/api:1.8.2)"
IMAGE="registry.example.net/paiement/api@${DIGEST}"
# Signer l'image par digest avant toute promotion.
cosign sign --key "pkcs11:token=build-signing;object=cosign-production;type=private" \
"${IMAGE}"
# Vérifier avec la clé publique distribuée aux environnements de déploiement.
cosign verify --key build-production.pub "${IMAGE}"

Le fichier public build-production.pub peut être distribué dans le dépôt de politiques de déploiement. Sa modification exige la même revue que celle d’une règle d’accès : remplacer la clé publique de confiance revient à changer qui peut publier. Le fichier privé, lui, ne doit exister ni dans le dépôt, ni dans une variable CI (Continuous Integration), ni dans une image de runner.

Signer après le push n’est pas facultatif. La signature doit porter sur le digest renvoyé par le registre, car c’est ce que le registre sert réellement. Signer un tag local revient à signer une étiquette avant que le colis ne soit remis au transporteur. Les environnements de déploiement doivent consommer image@sha256:..., jamais image:latest.

Pour les binaires, signer le fichier final après compilation et avant publication avec un certificat de signature de code. Pour les paquets, signer à la fois le dépôt de paquets et les métadonnées de distribution quand le format le prévoit. Un paquet signé dans un index non signé peut rester exposé à des attaques de substitution ou de gel de version.

Le pipeline de déploiement doit exécuter cosign verify sur chaque digest avant d’appliquer le manifeste. Un échec doit arrêter le déploiement, sans option de contournement cachée derrière une variable nommée SKIP_SECURITY_FOR_REAL_THIS_TIME. La clé publique attendue, le registre autorisé et le dépôt source doivent être déclarés dans la politique, pas injectés dynamiquement par l’artefact vérifié.

Cette vérification côté pipeline ne suffit pas si un opérateur, un compte compromis ou une autre automatisation peut soumettre directement une ressource au cluster. Dans Kubernetes, imposer une politique d’admission qui vérifie chaque image avant sa création. Kyverno ou un mécanisme équivalent doit refuser les images non signées, signées par une clé inconnue, issues d’un registre non approuvé, ou référencées par tag mutable.

La politique doit limiter les références d’images, par exemple registry.example.net/paiement/*, et associer ce périmètre à la clé publique de production. Accepter toute image signée par la clé de build dans tout espace de noms élargit inutilement le rayon d’action d’une compromission. L’admission doit également exiger le digest dans les manifestes, sinon une signature valide peut protéger un contenu différent de celui effectivement téléchargé.

Superviser quatre événements : échec de signature, échec de vérification, refus d’admission et utilisation anormale de la clé. Conserver les journaux d’audit du HSM, du registre, du pipeline et du contrôleur d’admission avec un identifiant commun d’artefact, idéalement le digest. Sans cette corrélation, l’investigation devient une chasse au trésor où le trésor est un conteneur compromis.

Une révocation ne retire pas automatiquement les artefacts déjà exécutés. Une clé compromise exige d’identifier les digests signés depuis la dernière preuve fiable, de bloquer leur redéploiement, de déployer des remplaçants signés avec une nouvelle clé, puis de révoquer l’ancienne dans toutes les politiques. La vérification d’intégrité traite la provenance de l’artefact, pas la persistance d’un processus déjà lancé.

Sans signature ni vérification obligatoire, la confiance repose entièrement sur les droits d’accès du registre et sur la disponibilité du réseau de distribution : quiconque obtient un jeton de publication, un miroir intermédiaire ou un cache de proxy peut substituer un contenu sans laisser de trace exploitable. Une image republiée sous le même tag ne déclenche aucun signal, et rien ne distingue une reconstruction légitime d’un artefact injecté hors chaîne. En cas d’incident, le périmètre devient incalculable : sans lien cryptographique entre un digest, une identité de publication et un journal d’audit, il faut suspecter l’ensemble des versions déployées plutôt qu’une plage datée. La reprise se fait alors à l’aveugle, par redéploiement massif, et les retours arrière vers d’anciennes versions ne peuvent plus être distingués d’une attaque de gel de version.

Un programme compilé, un paquet logiciel ou une image de conteneur devient un artefact à distribuer. Avant sa publication, la chaîne de fabrication calcule une empreinte qui dépend de tout son contenu. Elle demande ensuite à une clé privée de produire une signature liée à cette empreinte. La clé privée est conservée dans un matériel spécialisé ou un coffre protégé afin que le système de fabrication puisse signer sans pouvoir copier la clé.

La clé publique associée est distribuée aux systèmes qui installent les artefacts. Lors du déploiement, ces systèmes récupèrent l’artefact avec son identifiant précis, puis recalculent son empreinte. Ils utilisent la clé publique pour vérifier que la signature correspond à ce contenu et à une clé autorisée. Si le contenu a changé, si la signature manque, ou si elle vient d’une autre clé, le déploiement est refusé.

Les images de conteneurs doivent être désignées par leur identifiant de contenu plutôt que par une étiquette modifiable. Une étiquette peut être déplacée vers une autre image, alors que l’identifiant change dès que le contenu change.

Cette protection ne dit pas que le programme est sans défaut ni qu’il est sans danger. Elle prouve seulement qu’il vient de la chaîne de fabrication autorisée et qu’il n’a pas été modifié après sa signature. Si la clé privée est volée, un attaquant peut produire des signatures acceptées : il faut alors remplacer la clé, bloquer les anciens artefacts concernés et examiner les déploiements effectués depuis le vol.

À lire aussi

Pages voisines

: les deux pages se citent l’une l’autre.