La supply chain security représente 20% du CKS et couvre la réduction de l'empreinte des images, la compréhension de la chaîne d'approvisionnement, la sécurisation des artefacts et l'analyse statique des workloads et images. Ce guide se concentre sur cinq pratiques concrètes : images minimales, scan de vulnérabilités, SBOM, signature d'images et contrôle d'admission.
Ces cinq pratiques couvrent le socle, mais elles doivent s'insérer dans une chaîne plus large incluant le CI/CD, le stockage d'artefacts et les contrôles d'admission.
Prérequis
Section intitulée « Prérequis »- Cluster Kubernetes fonctionnel avec accès cluster-admin
- Bases Docker/conteneurs (build d'images)
- kubectl configuré
- Notions de sécurité (CVE, vulnérabilités)
Qu'est-ce que la supply chain d'une image ?
Section intitulée « Qu'est-ce que la supply chain d'une image ? »La chaîne d'approvisionnement d'une image conteneur couvre tout le cycle de vie avant déploiement :
Une attaque supply chain compromet n'importe quel maillon : une dépendance malveillante, un build piraté, une image modifiée en transit, ou une registry non authentifiée.
Règle d'or : ne jamais faire confiance à une image simplement parce qu'elle « fonctionne ». Une image qui fonctionne peut quand même contenir des CVE critiques ou avoir été altérée.
1. Minimiser l'empreinte des images de base
Section intitulée « 1. Minimiser l'empreinte des images de base »Pourquoi les images légères réduisent la surface d'attaque
Section intitulée « Pourquoi les images légères réduisent la surface d'attaque »Une image contenant apt, bash, curl et des outils système offre à un attaquant de nombreux leviers s'il parvient à s'exécuter dans le conteneur. Une image distroless ne contient que le runtime et votre binaire.
| Type d'image | Taille | Surface d'attaque | Cas d'usage |
|---|---|---|---|
ubuntu:22.04 | ~70 Mo | Élevée (shell, apt, utils) | Développement |
alpine:3.19 | ~7 Mo | Modérée (shell BusyBox) | Usage général |
gcr.io/distroless/static | ~2 Mo | Minimale (pas de shell) | Go, binaires statiques |
gcr.io/distroless/base | ~20 Mo | Très faible (glibc seulement) | C, C++, Java |
scratch | 0 Mo | Minimale côté base image (la sécurité dépend toujours du binaire embarqué) | Binaires entièrement statiques |
Build multi-stage : compiler sans embarquer les outils
Section intitulée « Build multi-stage : compiler sans embarquer les outils »Le build multi-stage permet de compiler dans une image "build" complète et de ne copier que le binaire final dans une image minimale :
# Étape 1 : compilation (image complète)FROM golang:1.23 AS builderWORKDIR /appCOPY . .RUN CGO_ENABLED=0 go build -o myapp .
# Étape 2 : image finale minimale (distroless)FROM gcr.io/distroless/static-debian12:nonrootCOPY --from=builder /app/myapp /myappUSER nonroot:nonrootENTRYPOINT ["/myapp"]Bonnes pratiques images
Section intitulée « Bonnes pratiques images »Ces quatre règles portent toutes sur la même question : à quel point l'image que
vous déployez aujourd'hui sera-t-elle identique à celle que vous avez testée
hier. Un tag est un pointeur mutable côté registry, il peut être réaffecté
sans que rien ne change dans votre manifeste ; un digest est le condensat du
contenu, il ne peut pas mentir. Retenez la hiérarchie : latest ne garantit
rien, un tag de version garantit une intention, un digest garantit le contenu.
- PIN les versions :
nginx:1.25.3plutôt quenginx:latest, une mise à jour peut introduire des CVE - Utiliser le digest SHA256 pour garantir l'immuabilité :
nginx@sha256:abc123... - Ne pas installer de debuggers dans les images de production (
gdb,strace,tcpdump) - Nettoyer le cache dans le même RUN :
apt-get install -y curl && rm -rf /var/lib/apt/lists/*
# Recommandé : image référencée par digest, donc immuableFROM nginx@sha256:67f9a4f10d147a6e04629340e6493c9703300ca23a2f7f3aa56fe615d75d31ca
# À proscrire : latest n'est pas reproductibleFROM nginx:1.31.32. Scanner les vulnérabilités
Section intitulée « 2. Scanner les vulnérabilités »Avant toute chose : scanner vos images pour détecter les CVE (Common Vulnerabilities and Exposures) connues.
Scanner avec Grype, mon choix principal
Section intitulée « Scanner avec Grype, mon choix principal »Je le privilégie pour son intégration avec Syft, son accent sur EPSS, KEV, risk scoring et OpenVEX, et sa capacité à scanner images, file systems et SBOMs indifféremment.
# Installation par binaire officiel vérifié (empreinte SHA256)GRYPE_VERSION=0.111.0base="https://github.com/anchore/grype/releases/download/v${GRYPE_VERSION}"curl -sSfLO "${base}/grype_${GRYPE_VERSION}_linux_amd64.tar.gz"curl -sSfLO "${base}/grype_${GRYPE_VERSION}_checksums.txt"grep "grype_${GRYPE_VERSION}_linux_amd64.tar.gz" "grype_${GRYPE_VERSION}_checksums.txt" | sha256sum -c -sudo tar -C /usr/local/bin -xzf "grype_${GRYPE_VERSION}_linux_amd64.tar.gz" grype
# Scanner une imagegrype nginx:1.25.3
# Scanner avec seuil de sévérité (fail si CRITICAL détecté)grype nginx:1.25.3 --fail-on critical
# Format JSON pour CI/CDgrype nginx:1.25.3 -o json > results.jsonScanner avec Trivy, culture écosystème
Section intitulée « Scanner avec Trivy, culture écosystème »Vous croiserez ces commandes dans la quasi-totalité des pipelines existants et
des supports de préparation au CKS, ce qui suffit à justifier de les connaître.
Deux options méritent une explication : --ignore-unfixed masque les CVE pour
lesquelles aucun correctif n'est publié, utile pour ne pas bloquer un build sur
un problème que personne ne peut résoudre, mais dangereux si vous l'activez sans
suivre ces vulnérabilités par ailleurs. --exit-code 1 est ce qui transforme le
scan en garde-fou : sans lui, Trivy affiche les CVE et le job reste vert.
# Scanner une imagetrivy image nginx:1.25.3
# Ignorer les CVE non fixéestrivy image --ignore-unfixed nginx:1.25.3
# Format pour CI/CDtrivy image --exit-code 1 --severity CRITICAL nginx:1.25.3Pour approfondir le scanning et comprendre les scores CVE : Comprendre les CVE, CVSS et EPSS.
3. Générer et exploiter un SBOM
Section intitulée « 3. Générer et exploiter un SBOM »Un SBOM (Software Bill of Materials) est l'inventaire exhaustif de tous les composants d'une image : packages OS, bibliothèques, versions, licences. C'est la liste d'ingrédients de votre logiciel.
# Générer un SBOM avec Syftsyft nginx:1.25.3 -o cyclonedx-json > nginx-sbom.json
# Utiliser le SBOM pour scanner avec Grypegrype sbom:nginx-sbom.json
# Générer et scanner en une commandesyft nginx:1.25.3 | grypeVoir le guide SBOM complet pour les formats SPDX/CycloneDX et l'intégration CI/CD.
4. Signer et vérifier les images avec Cosign
Section intitulée « 4. Signer et vérifier les images avec Cosign »La signature d'images garantit l'authenticité (l'image provient bien du build attendu) et l'intégrité (elle n'a pas été modifiée). Cosign de Sigstore est l'outil standard.
Signer une image
Section intitulée « Signer une image »Un guide de supply chain qui installerait son propre outil sans vérification
serait contradictoire : le bloc ci-dessous épingle donc une version précise
et contrôle l'empreinte SHA256 publiée par le projet avant de rendre le binaire
exécutable. Sigstore publie ce fichier sous le nom cosign_checksums.txt dans
chaque release. La commande cosign generate-key-pair demande ensuite une
passphrase : elle protège cosign.key, qui est la seule chose à ne jamais
laisser sortir de votre coffre.
# Installation Cosign : version épinglée + vérification d'empreinteCOSIGN_VERSION=3.1.2base="https://github.com/sigstore/cosign/releases/download/v${COSIGN_VERSION}"curl -sSfLO "${base}/cosign-linux-amd64"curl -sSfLO "${base}/cosign_checksums.txt"grep " cosign-linux-amd64$" cosign_checksums.txt | sha256sum -c -chmod +x cosign-linux-amd64 && sudo mv cosign-linux-amd64 /usr/local/bin/cosign
# Générer une paire de cléscosign generate-key-pair# Produit cosign.key (privée) et cosign.pub (publique)
# Signer par digest (recommandé : le tag peut être réaffecté)cosign sign --key cosign.key registry.example.com/myapp@sha256:abc123...
# Signer par tag (acceptable mais moins robuste)cosign sign --key cosign.key registry.example.com/myapp:1.0.0
# Vérifier la signaturecosign verify --key cosign.pub registry.example.com/myapp:1.0.0Vérification dans Kubernetes avec ImagePolicyWebhook
Section intitulée « Vérification dans Kubernetes avec ImagePolicyWebhook »L'ImagePolicyWebhook est un admission controller historique, désactivé par défaut, qui délègue la décision d'autorisation à un backend webhook externe. Il reste documenté et utile pour comprendre les mécanismes de contrôle d'images, mais sur les clusters récents on rencontre davantage des admission webhooks génériques (ValidatingAdmissionWebhook) ou des moteurs de policy comme Kyverno.
La mise en place se fait en deux fichiers. D'abord les drapeaux du
kube-apiserver, à ajouter dans /etc/kubernetes/manifests/kube-apiserver.yaml
sur chaque nœud du plan de contrôle : le premier active le plugin, le second
indique où lire sa configuration. Une erreur ici empêche l'apiserver de
redémarrer, gardez une copie du manifeste avant de le modifier.
--enable-admission-plugins=...,ImagePolicyWebhook--admission-control-config-file=/etc/kubernetes/admission/admission-config.yamlapiVersion: apiserver.config.k8s.io/v1kind: AdmissionConfigurationplugins: - name: ImagePolicyWebhook configuration: imagePolicy: kubeConfigFile: /etc/kubernetes/admission/webhook-kubeconfig.yaml allowTTL: 50 denyTTL: 50 retryBackoff: 500 defaultAllow: false # Bloquer si le webhook est inaccessiblePour aller plus loin sur la signature : Guide Cosign complet.
5. Limiter les registries autorisées
Section intitulée « 5. Limiter les registries autorisées »En plus de la signature, on peut restreindre Kubernetes pour n'accepter que des images venant de registries approuvées. C'est la voie moderne et recommandée : les controllers de policy comme Kyverno ou Gatekeeper sont activés par défaut et offrent plus de flexibilité qu'ImagePolicyWebhook.
Avec Kyverno (recommandé)
Section intitulée « Avec Kyverno (recommandé) »La politique ci-dessous s'écrit avec l'API policies.kyverno.io/v1, disponible
depuis Kyverno 1.14 et servie par les versions 1.18.x. Deux champs portent tout
le comportement : validationActions: [Deny] refuse la création plutôt que de
se contenter d'un rapport, et l'expression CEL parcourt tous les conteneurs
du Pod avec all(...), ce qui bloque aussi un Pod dont un seul conteneur
viendrait d'ailleurs. Attention, matchConstraints ne cible ici que les Pods :
un Deployment passera, puis son Pod sera refusé, avec un message d'erreur qui
apparaîtra dans le ReplicaSet et non dans le Deployment.
apiVersion: policies.kyverno.io/v1kind: ValidatingPolicymetadata: name: restrict-registriesspec: validationActions: [Deny] matchConstraints: resourceRules: - apiGroups: [""] apiVersions: ["v1"] operations: ["CREATE", "UPDATE"] resources: ["pods"] validations: - expression: >- object.spec.containers.all(c, c.image.startsWith('registry.example.com/') ) message: "Seules les images de registry.example.com sont autorisées."Avec Gatekeeper (OPA)
Section intitulée « Avec Gatekeeper (OPA) »Gatekeeper sépare le code de la politique de son paramétrage. Le manifeste
ci-dessous est une Constraint, c'est-à-dire une instance : il suppose que le
ConstraintTemplate K8sAllowedRepos, fourni par la bibliothèque officielle
gatekeeper-library, a déjà été appliqué au cluster. Sans lui, l'API rejette le
manifeste avec une erreur de ressource inconnue. Le champ repos fonctionne par
préfixe de chaîne, pas par expression régulière : une entrée sans barre
oblique finale autoriserait aussi un registry dont le nom commence pareil.
apiVersion: constraints.gatekeeper.sh/v1beta1kind: K8sAllowedReposmetadata: name: allowed-reposspec: match: kinds: - apiGroups: [""] kinds: ["Pod"] parameters: repos: - "registry.example.com/" - "gcr.io/distroless/"→ Voir Guide Kyverno et Guide Gatekeeper.
Workflow supply chain complet
Section intitulée « Workflow supply chain complet »En production et pour le CKS, voici le cycle recommandé :
-
Build avec une image de base minimale (distroless/alpine) et build multi-stage
-
Scanner l'image avant le push :
grype myapp:1.0.0 --fail-on high -
Générer le SBOM et l'attacher à l'image :
syft myapp:1.0.0 -o cyclonedx-json -
Pinner par digest : référencer l'image par son SHA256 pour garantir l'immuabilité
-
Signer par digest :
cosign sign --key cosign.key registry/myapp@sha256:abc123... -
Pousser vers un artifact repository privé et contrôlé (registry interne approuvée)
-
Vérifier à l'admission : politique Kyverno/Gatekeeper ou ImagePolicyWebhook
Dépannage
Section intitulée « Dépannage »Les quatre situations ci-dessous ont un point commun : le cluster se comporte exactement comme il a été configuré, et c'est la configuration qui pose problème. Les deux premières lignes concernent des blocages visibles, les deux dernières sont plus pernicieuses car rien n'échoue : le pipeline reste vert alors que le contrôle attendu n'a jamais eu lieu. Vérifiez ces deux-là en priorité si votre chaîne semble « trop » silencieuse.
| Symptôme | Cause probable | Solution |
|---|---|---|
| Pod bloqué par ImagePolicyWebhook | Webhook inaccessible avec defaultAllow: false | Vérifier la disponibilité du webhook |
| Signature non vérifiée | Mauvaise clé publique ou image re-taguée | Re-signer ou utiliser le digest SHA256 |
| CVE CRITICAL non bloquantes | Seuil pas configuré | Ajouter --fail-on critical dans le CI/CD |
Images latest en production | Convention de tag permissive | Politique Kyverno pour interdire latest |
Testez vos connaissances
Section intitulée « Testez vos connaissances »Les dix questions ci-dessous sont tirées de la banque CKS et couvrent uniquement le domaine supply chain. Elles insistent volontairement sur les distinctions que l'examen exploite : scan contre signature, tag contre digest, et contrôle d'admission contre contrôle en CI.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »- Images minimales : distroless > alpine > ubuntu, build multi-stage ;
scratchréduit l'empreinte base mais la sécurité dépend du binaire embarqué - Scanner avant push : Grype (mon choix prod, EPSS, KEV, OpenVEX) ou Trivy (culture écosystème)
- Le scan ne suffit pas : une image sans CVE peut rester malveillante ou compromise, compléter avec signature et admission
- SBOM : inventaire exhaustif avec Syft, re-scannable séparément sans rebuild
- Signature : Cosign, de préférence par digest et keyless en production
- Contrôle admission : Kyverno/Gatekeeper comme voie moderne ; ImagePolicyWebhook comme mécanisme historique
- Registries : restreindre aux sources de confiance, préférer un artifact repository interne
- CI/CD : évitez les installations d'outils à la volée depuis Internet en production