DevSecOps

Scan de conteneurs : pourquoi et comment le mettre en place

Scan de conteneurs 2026 : pourquoi (CVE, secrets, misconfig), comment (Trivy, Grype, Docker Scout, Snyk), CI/CD, runtime, admission controllers Kubernetes.

Naim Aouaichia
13 min de lecture
  • Conteneurs
  • Container scanning
  • Docker
  • Kubernetes
  • Trivy
  • DevSecOps
  • CI/CD
  • Sigstore
  • Supply chain

Le scan de conteneurs est l'analyse automatisée d'une image Docker ou OCI pour détecter les vulnérabilités connues (CVE), les secrets accidentellement embarqués, les mauvaises configurations et les écarts par rapport aux benchmarks de sécurité (CIS Docker, CIS Kubernetes). Il s'exécute à quatre moments complémentaires du cycle de vie : pendant le build CI/CD, lors du push en registry, en scan continu du registry, et au runtime via admission controller Kubernetes. Les outils de référence en 2026 sont Trivy (Aqua Security, open source, standard de facto), Grype (Anchore), Docker Scout (natif Docker), Snyk Container (commercial) et Clair (open source, historique). Sans scan conteneur, une application parfaitement sécurisée côté code peut hériter de 50 à 200 CVE critiques via son image de base et ses paquets OS. Cet article détaille pourquoi c'est indispensable, quels outils choisir, comment intégrer dans le pipeline, et les bonnes pratiques pour minimiser la surface d'attaque.

Pourquoi scanner les conteneurs

Une image conteneur = beaucoup plus que du code applicatif

Une image Docker typique combine plusieurs couches qui cumulent chacune leurs vulnérabilités potentielles.

CoucheContenuRisques
Base OSAlpine, Ubuntu, Debian, RHEL UBICVE glibc, openssl, coreutils, shells
Runtime langagePython, Node.js, JVM, Go runtimeCVE interpréteur ou runtime
Dépendances systèmePaquets installés (apt, apk, dnf)CVE paquets distro, backdoors supply chain
Bibliothèques dynamiqueslibcurl, libxml2, libxslt, opensshCVE Heartbleed-like, buffer overflows
Dépendances applicativespackage.json, requirements.txtDéjà couvertes par SCA mais aussi dans l'image
Outils embarquéscurl, wget, bash, coreutils, debugAmplifient l'exploitation si compromise
ConfigurationUtilisateur, ports, ENTRYPOINTPrivilèges root, ports exposés inutiles
SecretsClés API, tokens, mots de passeFuite via layers, registre public

3 incidents récents qui illustrent le risque

XZ Utils backdoor - CVE-2024-3094 (mars 2024)
  Backdoor SSH dans la bibliothèque xz installée dans de nombreuses
  images de base Debian / Fedora / Ubuntu rolling.
  Des scans d'images publics ont révélé la présence dans des dizaines
  d'images Docker Hub non rebuildées pendant des semaines après disclosure.
 
OpenSSL CVE-2022-3602 et 3786 (novembre 2022)
  Buffer overflow dans le parsing de certificats X.509.
  Toutes les images avec OpenSSL 3.0.0 à 3.0.6 vulnérables.
  Impact massif pour les équipes qui n'ont pas rebuildé leurs images.
 
Docker Hub typosquatting et cryptojacking (continu 2020-2025)
  Des images populaires typosquattées ou piégées embarquent
  des crypto-miners. Une image pullée d'un registre public non vérifié
  peut tourner en prod avec un payload silencieux.

Chiffres 2025-2026

Selon les rapports Sysdig Cloud Native Security (2024) et Aqua Security (2025) :

  • Une image de base non optimisée typique contient 200 à 800 CVE toutes sévérités confondues.
  • Une image distroless ou Chainguard correspondante : 0 à 5 CVE.
  • 70 % des images publiques sur Docker Hub contiennent au moins une vulnérabilité Critical.
  • Temps moyen entre disclosure d'une CVE Critical et son arrivée dans les images rebuildées automatiquement : 6 à 14 jours chez les équipes matures, 40 à 90 jours sans automatisation.

Que scanner exactement

Un scan complet couvre cinq dimensions en 2026.

1. Vulnérabilités logicielles (CVE)

Couvre les paquets OS (via distro databases : Debian Security Tracker, Red Hat OVAL, Alpine secdb) et les dépendances applicatives (via NVD, GitHub Advisory Database, OSV.dev). Produit une liste de CVE avec criticité CVSS, patches disponibles, et chemin d'exploitation.

2. Secrets accidentellement embarqués

Clés API, tokens JWT, mots de passe, clés SSH, tokens cloud dans les layers. Souvent dus à un COPY . . aveugle ou à un build arg exposé. Les outils modernes (Trivy, trufflehog) scannent les layers via des patterns regex et des détections sémantiques.

3. Misconfigurations Dockerfile

Anti-patterns fréquents détectés par les scanners :
 
  USER root en ENTRYPOINT                  (CIS Docker Benchmark 4.1)
  ADD au lieu de COPY                      (téléchargement non vérifié)
  curl | bash dans un RUN                  (exécution non signée)
  Pas de HEALTHCHECK                        (observabilité limitée)
  latest tag sur FROM                       (pas de pinning)
  COPY . . avec .dockerignore absent        (fuite fichiers sensibles)
  Secrets dans ENV ou ARG                   (persistés dans layer)
  CAP_SYS_ADMIN ou --privileged             (privilèges excessifs)
  Port 22 exposé                            (SSH dans conteneur rare nécessaire)
  Multiple RUN sans multi-stage             (image gonflée inutilement)

4. Conformité aux benchmarks

  • CIS Docker Benchmark : 117 contrôles sur l'hôte Docker et les images.
  • CIS Kubernetes Benchmark : sécurité cluster et workloads.
  • NSA/CISA Kubernetes Hardening Guide (v1.2, 2022) : recommandations NSA.
  • NIST SP 800-190 : application container security guide.

5. SBOM (Software Bill of Materials)

Listing complet des composants installés dans l'image au format CycloneDX ou SPDX. Obligatoire sous Cyber Resilience Act UE et Executive Order 14028 US pour certains marchés.

Outils de scan 2026 : panorama détaillé

Trivy (Aqua Security, open source)

Standard de facto. Binaire unique, rapide, couvre CVE + secrets + misconfig + SBOM. Intégration CI/CD triviale.

# Scan CVE simple
trivy image --severity HIGH,CRITICAL nginx:1.25-alpine
 
# Scan complet avec secrets et misconfig
trivy image --scanners vuln,secret,misconfig --format json \
  --output report.json registry/app:${GITHUB_SHA}
 
# Générer un SBOM CycloneDX
trivy image --format cyclonedx --output sbom.json registry/app:${GITHUB_SHA}
 
# Ignorer les CVE non fixables (pas de patch disponible)
trivy image --ignore-unfixed registry/app:${GITHUB_SHA}
 
# Exit non zéro si CVE High/Critical - fait planter le CI
trivy image --exit-code 1 --severity HIGH,CRITICAL registry/app:${GITHUB_SHA}

Grype (Anchore, open source)

Alternative plus légère, souvent couplée à Syft pour la génération de SBOM en amont.

# Pipeline typique : Syft génère SBOM, Grype scanne le SBOM
syft registry/app:${GITHUB_SHA} -o cyclonedx-json > sbom.json
grype sbom:sbom.json --fail-on critical

Docker Scout (natif Docker)

Intégré à Docker Desktop et au CLI docker. Parfait pour les petites équipes sur Docker Hub.

# Vue rapide
docker scout cves registry/app:latest
 
# Recommandation d'image de base plus sûre
docker scout recommendations registry/app:latest
 
# Comparaison entre deux tags
docker scout compare --to registry/app:previous registry/app:latest

Snyk Container (commercial freemium)

Excelle sur la suggestion automatique de base image alternative et les fix PR automatiques.

snyk container test registry/app:${GITHUB_SHA}
snyk container test --file=Dockerfile registry/app:${GITHUB_SHA}

Clair (open source, historique)

API-driven, souvent intégré dans des registries (Harbor, Quay). Plus complexe à déployer qu'un CLI mais excellent pour le scan continu côté registry.

Comparatif synthétique

OutilTypeLicenceForcesUsage typique
TrivyCLI + APIOSS Apache 2.0Tout-en-un, rapide, CI-friendlyScan CI + local dev
GrypeCLIOSS Apache 2.0Léger, couplage Syft SBOMCI, scripting
Docker ScoutCLI + HubFreemiumUX simple, Docker natifPetites équipes, Docker Hub
Snyk ContainerSaaS + CLICommercial freemiumFix PR auto, base image suggestScale-up, enterprise
ClairAPIOSS Apache 2.0Scan registry continuQuay, Harbor
Anchore EnterpriseSaaSCommercialPolicy as code avancéEnterprise régulée
Prisma Cloud (Twistlock)SaaS + agentCommercialSuite complète CWPPMulti-cloud enterprise
Aqua EnterpriseSaaS + agentCommercialRuntime + complianceEnterprise régulée

Intégration CI/CD : exemples concrets

GitHub Actions avec Trivy

name: container-scan
on: [push, pull_request]
permissions:
  contents: read
  security-events: write  # requis pour upload SARIF
  id-token: write         # requis pour cosign keyless
jobs:
  build-and-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build image
        run: docker build -t app:${{ github.sha }} .
 
      - name: Trivy scan - fail on Critical
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: app:${{ github.sha }}
          severity: HIGH,CRITICAL
          exit-code: 1
          ignore-unfixed: true
          format: sarif
          output: trivy-results.sarif
 
      - name: Upload SARIF to GitHub Security
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: trivy-results.sarif
 
      - name: Generate SBOM
        run: trivy image --format cyclonedx --output sbom.json app:${{ github.sha }}
 
      - name: Upload SBOM as artifact
        uses: actions/upload-artifact@v4
        with:
          name: sbom
          path: sbom.json
 
      - name: Install cosign
        uses: sigstore/cosign-installer@v3
 
      - name: Sign image (keyless OIDC)
        run: |
          docker push ghcr.io/org/app:${{ github.sha }}
          cosign sign --yes ghcr.io/org/app:${{ github.sha }}
 
      - name: Attach SBOM attestation
        run: |
          cosign attest --yes --predicate sbom.json \
            --type cyclonedx ghcr.io/org/app:${{ github.sha }}

GitLab CI équivalent

stages:
  - build
  - scan
  - sign
 
container-build:
  stage: build
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
 
container-scan:
  stage: scan
  image: aquasec/trivy:latest
  script:
    - trivy image --exit-code 1 --severity HIGH,CRITICAL --ignore-unfixed
                  $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
 
container-sign:
  stage: sign
  script:
    - cosign sign --yes $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

Scan continu du registry

Un scan au moment du build ne protège pas contre les CVE qui tombent après la publication. Deux approches complémentaires :

Approche 1 - Scan scheduled via CI

# GitHub Actions cron nightly scan registry
on:
  schedule:
    - cron: '0 2 * * *'  # chaque nuit à 2h
jobs:
  rescan-registry-images:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        image: [app-api, app-worker, app-frontend]
    steps:
      - name: Trivy rescan
        run: |
          trivy image --severity HIGH,CRITICAL \
            --format json --output ${{ matrix.image }}.json \
            ghcr.io/org/${{ matrix.image }}:latest
      # Publier les résultats dans Slack/Jira/Dependency-Track

Approche 2 - Registry avec scan intégré

Les registres modernes intègrent nativement un scanner :

  • Harbor (CNCF) : Trivy intégré par défaut, Clair disponible.
  • Quay (Red Hat) : Clair intégré.
  • GitHub Container Registry : Docker Scout intégré.
  • Docker Hub : Docker Scout sur les plans payants.
  • AWS ECR : Enhanced Scanning avec Clair et Snyk.
  • GCP Artifact Registry : Container Analysis (Grafeas).
  • Azure Container Registry : Microsoft Defender for Containers.

Admission controllers Kubernetes : la dernière ligne

Un scan CI rigoureux ne suffit pas si un développeur peut déployer une image non vérifiée en cluster. Les admission controllers bloquent les pods qui ne respectent pas la policy.

Kyverno - verify image signature

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signatures
spec:
  validationFailureAction: Enforce
  rules:
    - name: verify-cosign-signature
      match:
        any:
          - resources:
              kinds: [Pod]
      verifyImages:
        - imageReferences:
            - "ghcr.io/org/*"
          attestors:
            - entries:
                - keyless:
                    subject: "https://github.com/org/*/.github/workflows/*"
                    issuer: "https://token.actions.githubusercontent.com"

Cette policy refuse tout pod utilisant une image du registre ghcr.io/org/* qui n'a pas été signée par une GitHub Actions OIDC de l'organisation. Combiné au scan CI, elle garantit qu'une image vulnérable ne peut pas arriver en cluster via shortcut.

OPA Gatekeeper et autres contrôleurs

Alternatives et compléments :

  • OPA Gatekeeper : policies Rego, historique, large adoption.
  • Kyverno : YAML, plus accessible, fort sur verify-image.
  • Ratify + Gatekeeper : verify-image policies Sigstore.
  • Falco : runtime detection eBPF, alertes.

Bonnes pratiques pour minimiser la surface

1. Images de base minimales

ubuntu:24.04                   : 77 MB, 90+ CVE résiduelles typiques
python:3.12-slim               : 45 MB, 20-40 CVE
python:3.12-alpine             : 19 MB, 15-30 CVE (mais libc musl)
chainguard/python:latest        : 15 MB, 0-3 CVE (sponsored base)
gcr.io/distroless/python3       : 25 MB, 0-5 CVE
scratch + binaire statique Go   : 5-15 MB, 0 CVE distro

2. Multi-stage builds

# Build stage - gros, outils de build inclus
FROM golang:1.22 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /bin/app ./cmd/app
 
# Runtime stage - minimal, seul le binaire
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /bin/app /bin/app
USER nonroot
ENTRYPOINT ["/bin/app"]

3. Pinning strict et mise à jour automatisée

# MAUVAIS - mutable, non reproductible
FROM python:3.12-slim
 
# MIEUX - tag minor pinné
FROM python:3.12.6-slim
 
# IDÉAL - digest SHA256 immuable
FROM python:3.12.6-slim@sha256:1a89c1d4...

Automatiser les mises à jour avec Renovate ou Dependabot pour rebuilder les images dès qu'une nouvelle version minor sort.

4. Utilisateur non-root

RUN useradd -u 10001 -m -s /usr/sbin/nologin app
USER 10001

5. Signature et SBOM systématiques

cosign pour signer, Syft ou Trivy pour SBOM, attestation attachée à l'image via cosign attest. Voir l'exemple GitHub Actions plus haut.

Pièges fréquents à éviter

  1. Scanner uniquement au build et jamais le registry : les CVE tombent après la publication, il faut rescanner.
  2. Ignorer les CVE non fixables sans exception tracée : --ignore-unfixed est utile mais doit faire l'objet d'un suivi.
  3. Scan avec sévérité Medium bloquante en CI : taux de bruit élevé, les équipes finissent par ignorer tout. Commencer par Critical seulement, puis durcir.
  4. Absence d'admission controller : un pipeline CI parfait ne protège pas d'un kubectl apply direct avec une image bypass.
  5. SBOM généré mais non stocké : un SBOM sert seulement s'il est archivé et consultable après le déploiement. Dependency-Track (OWASP) est la plateforme de référence.
  6. Scan seulement de l'application, pas des images sidecars et init containers : inclure tous les conteneurs du pod.
  7. Absence de signature : Sigstore cosign est gratuit et facile. Ne pas le faire = accepter qu'un attaquant puisse pousser une image piégée avec le même nom.

Points clés à retenir

  • Scanner un conteneur = scanner bien plus que le code : OS de base, runtime langage, paquets distro, binaires système, secrets, configurations Dockerfile, benchmarks CIS.
  • Quatre moments de scan complémentaires en 2026 : CI (bloquer avant registry), push (scan du registre), scheduled rescan (CVE nouvelles), admission controller K8s (dernière ligne).
  • Stack outil minimale 2026 : Trivy (open source, standard) en CI + scan continu registry + Kyverno verify-image en cluster. Ajouter Snyk Container ou Snyk si budget.
  • 5 leviers de réduction CVE : images distroless / Chainguard, multi-stage builds, pinning digest SHA256, mises à jour automatisées (Renovate), utilisateur non-root.
  • Signer les images avec cosign (keyless OIDC gratuit) et générer un SBOM CycloneDX à chaque build. Obligatoire sous Cyber Resilience Act UE et Executive Order 14028 US.
  • Pièges à éviter : scan seulement au build, seuils trop agressifs qui font ignorer, SBOM non archivé, absence d'admission controller, scan limité au conteneur principal.

Pour approfondir la discipline DevSecOps complète et savoir où le scan conteneur s'inscrit, voir la roadmap DevSecOps 2026. Pour comprendre le positionnement SAST vs DAST vs scan conteneur dans un pipeline, lire SAST vs DAST : comparaison complète. Pour la vision cadre général supply chain dont les images font partie, voir software supply chain : définition et enjeux sécurité.

Questions fréquentes

  • Pourquoi scanner les conteneurs alors que je scanne déjà mes dépendances ?
    Parce qu'une image conteneur contient bien plus que les dépendances applicatives : une distribution Linux complète (glibc, openssl, coreutils), des binaires système, des bibliothèques chargées dynamiquement, parfois des outils de debug oubliés. Les CVE critiques de 2024-2025 (XZ Utils, OpenSSL, curl, libcurl) touchent ces couches. Scanner les dépendances applicatives est insuffisant : il faut aussi scanner l'image complète pour couvrir l'OS de base, les paquets distro et les binaires embarqués.
  • Quel est le meilleur scanner de conteneurs en 2026 : Trivy, Grype, Snyk ou Docker Scout ?
    Trivy (Aqua Security, open source) est le standard de facto en 2026 pour la plupart des équipes : CLI unique, rapide, multi-format, couvre CVE + secrets + misconfig + SBOM, intégration CI triviale. Grype (Anchore, open source) est une alternative plus légère, excellente en CI. Docker Scout est parfait pour des petites équipes déjà sur Docker Hub. Snyk Container (commercial freemium) excelle sur la suggestion automatique de base image plus sûre et les fix PR. Pour la plupart : commencer par Trivy, ajouter Snyk si le budget le permet.
  • Faut-il scanner les images en CI, en registry ou en runtime ?
    Les trois, car chaque couche couvre un risque différent. CI : bloquer le build en cas de CVE Critical avant même d'arriver en registry. Registry : continuous rescan des images stockées car de nouvelles CVE sortent chaque jour sur des images déjà publiées. Runtime : admission controller Kubernetes (Kyverno verify-image, OPA Gatekeeper) pour refuser un pod qui utilise une image non signée ou vulnérable. L'architecture minimale 2026 combine Trivy en CI + Trivy/Grype scheduled sur le registry + Kyverno en cluster.
  • Un scan d'image remplace-t-il un scan de dépendances applicatives (SCA) ?
    Non, les deux sont complémentaires. Un SCA (Snyk, Dependabot, OSV-Scanner) sur package.json ou requirements.txt cible les dépendances applicatives directes et transitives avec une précision de version fine. Un scan d'image détecte en plus les paquets OS, les binaires système, les bibliothèques linkées dynamiquement et les secrets accidentellement embarqués. Les deux ont des angles morts différents. Un pipeline DevSecOps mature fait les deux.
  • Comment réduire le volume de CVE remontées dans les images ?
    Cinq leviers cumulés : choisir des images de base minimales (distroless, Chainguard Images, Alpine pour certains contextes), multi-stage builds pour exclure les outils de compilation du runtime, pinner les versions exactes (pas de FROM ubuntu:latest mais ubuntu:24.04-SHA256), mettre à jour les bases chaque semaine automatiquement (Renovate, Dependabot), et signer les images avec cosign pour prouver leur provenance. Ces pratiques divisent par 5 à 20 le nombre de CVE critiques résiduelles.
  • Que faire des secrets détectés dans une image ?
    Trois actions simultanées : retirer le secret immédiatement (nouvelle image sans le secret, supprimer l'historique de build si possible), faire tourner tous les registres publics/privés avec cette image pour supprimer les copies, et surtout révoquer et régénérer le secret compromis (clé API, mot de passe, token JWT). Un secret commité dans une image publique doit être considéré compromis dès la première publication, même s'il n'a pas été détecté par un attaquant. Les outils trufflehog, gitleaks et Trivy détectent secrets en images.

Écrit par

Naim Aouaichia

Expert cybersécurité et fondateur de Zeroday Cyber Academy

Expert cybersécurité avec un master spécialisé et un parcours hybride : développement, DevOps, DevSecOps, SOC, GRC. Fondateur de Hash24Security et Zeroday Cyber Academy. Formateur et créateur de contenu technique sur la cybersécurité appliquée, la sécurité des LLM et le DevSecOps.