Vous avez désormais des images de base : assurons la qualité de la supply chain conteneurs. Nous couvrons Docker multi-stage, BuildKit, SBOM, scanning et signature Cosign.
Table of Contents
Objectifs
- Écrire des Dockerfile optimisés (multi-stage, non-root, cache) et automatiser les builds.
- Générer et publier des SBOM (Syft) et réaliser des scans Trivy/Snyk.
- Signer et vérifier vos images (Cosign) et définir des policies d’admission.
1. Dockerfile multi-stage
# syntax=docker/dockerfile:1.6
FROM golang:1.22 AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o app ./cmd/api
FROM gcr.io/distroless/base-debian12
WORKDIR /app
COPY --from=builder /src/app /app/app
USER nonroot
ENTRYPOINT ["/app/app"]
HEALTHCHECK --interval=30s --timeout=5s --retries=3 CMD ["/app/app", "--health"]
Build :
docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/acme/webapp:$(git rev-parse --short HEAD) --push .
2. SBOM et scanning
syft ghcr.io/acme/webapp:$(git rev-parse --short HEAD) -o json > sbom.json
trivy image --security-checks vuln,config ghcr.io/acme/webapp:$(git rev-parse --short HEAD)
Ajoutez le rapport SBOM en artefact CI et configurez un seuil d’échec (CVSS ≥ 7).
3. Signature Cosign
cosign generate-key-pair
COSIGN_PASSWORD="${COSIGN_PASSWORD}" cosign sign ghcr.io/acme/webapp:$(git rev-parse --short HEAD)
cosign verify ghcr.io/acme/webapp:$(git rev-parse --short HEAD)
Stockez la clé privée dans un secret (Vault, GitHub OIDC + KMS).
4. Admission policy (Kyverno)
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-signed-images
spec:
validationFailureAction: enforce
rules:
- name: require-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- image: "ghcr.io/acme/*"
key: "k8s://kube-system/cosign-pub"
5. Pipeline exemple (GitHub Actions)
name: container-supply-chain
on:
push:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
packages: write
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- name: Build & push
uses: docker/build-push-action@v5
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
platforms: linux/amd64,linux/arm64
- name: Generate SBOM
run: syft ghcr.io/${{ github.repository }}:${{ github.sha }} -o json > sbom.json
- name: Scan image
run: trivy image --severity CRITICAL,HIGH ghcr.io/${{ github.repository }}:${{ github.sha }}
- name: Sign image
env:
COSIGN_YES: "true"
run: cosign sign ghcr.io/${{ github.repository }}:${{ github.sha }}
- uses: actions/upload-artifact@v4
with:
name: sbom
path: sbom.json
6. Lab guidé
- Refactoriser un Dockerfile existant en multi-stage, exécuter
docker scout cvespour vérifier le gain. - Configurer BuildKit + cache remote (
--cache-to type=registry). Mesurer le temps de build. - Générer une SBOM (
syft) et un scan (trivy), enregistrer les rapports dansartifacts/. - Signer l’image via Cosign et stocker la clé publique dans Kubernetes (
kubectl create secret generic cosign-pub --from-file=cosign.pub). - Déployer la policy Kyverno et vérifier qu’une image non signée est rejetée.
Challenge optionnel
- Mettre en place une politique d’expiration (retention GHCR) et un job Cron GitHub Actions pour nettoyer les tags anciens.
- Automatiser la génération de SBOM CycloneDX et l’envoyer vers Dependency-Track.
- Utiliser
cosign attestavec les résultats Trivy comme attestation.
Solution détaillée
- Build optimisé :
docker buildx buildaffiche#2 exporting to imageen ~40% de temps en moins grâce au cache.docker historymontre moins de couches. - Scan :
trivydoit afficher 0 vulnérabilité critique. Si ce n’est pas le cas, mettez à jour la base (ex.apt-get dist-upgradedans le Dockerfile). - Signature :
cosign verifyrenvoieVerified OK. Vérifiez dans le registre que l’attestation est présente (crane ls ghcr.io/... --full). - Policy Kyverno : déployez un Pod avec une image non signée →
Error from server (Forbidden) ... fails policy verify-signed-images. - Rapports :
artifacts/sbom.json,artifacts/trivy.txtdisponibles en artefacts pipeline.
Documentez les étapes dans docs/supply-chain.md avant de poursuivre.
Pièges fréquents
- Déployer des images root : pensez à
USER nonrootetRUN addgroup/adduser. - Oublier de purger le cache APT (
rm -rf /var/lib/apt/lists/*) → images lourdes. - Signer avec une clé stockée en clair dans le dépôt : utilisez OIDC + KMS ou Vault.
Ressources
Checklist
- ✅ Dockerfile multi-stage et non-root.
- ✅ SBOM et scan générés automatiquement.
- ✅ Images signées et vérifiées.
- ✅ Policy d’admission empêchant les images non signées.


