La sécurité Docker pour développeurs en 2026 repose sur 7 piliers : anti-patterns Dockerfile éliminés (root user, tag latest, ADD vs COPY, secrets en build args), secure base images (distroless, Chainguard Images, alpine 3.19+), multi-stage builds pour réduire la surface d'attaque, image scanning (Trivy, Grype, Docker Scout, Snyk Container), image signing (Cosign keyless OIDC Sigstore), runtime hardening (seccomp, AppArmor/SELinux, capabilities drop, read-only root FS), SBOM attestation (Syft plus Cosign). Les CVE container escape récentes rappellent la nécessité de défense en profondeur : CVE-2019-5736 runc (overwrite binaire), CVE-2022-0811 cri-o (kernel parameters, CVSS 8.8), CVE-2024-0132 NVIDIA Container Toolkit (TOCTOU, CVSS 9.0, impact GPU workloads massif 2024), CVE-2024-10220 Kubernetes gitRepo (escape vers node). Les 5 gains rapides ROI observés 2023-2026 : migration distroless ou Chainguard (-70 à -90 % CVE), USER non-root systématique, Trivy en pre-commit plus CI fail-build, Cosign keyless OIDC, Pod Security Standards restricted. Représentent 80 % du bénéfice avec 20 % de l'effort. Les organisations qui ne les ont pas en place en 2026 ont un retard structurel face à leurs pairs — rattrapable en 4-8 semaines de sprint dédié. Zeroday Cyber Academy recommande cette priorisation : les 5 gains rapides d'abord, puis runtime hardening avancé (seccomp custom, AppArmor profiles, user namespaces), puis supply chain complet (SBOM CycloneDX plus SLSA niveau 3). Cet article détaille les 7 anti-patterns Dockerfile, la comparaison des base images sécurisées, les patterns multi-stage avec code hands-on, la stack scanning 2026, la signature Cosign, le runtime hardening, les CVE container escape à connaître et notre bilan factuel.
1. Les sept anti-patterns Dockerfile à éliminer
| Anti-pattern | Risque | Remédiation |
|---|---|---|
| 1. Container root par défaut (pas de USER) | Escalade privilège, container escape | USER 65532 (nonroot) minimum |
| 2. Tag "latest" base image | Reproductibilité nulle, supply chain risk | Pin version + hash SHA256 |
| 3. ADD au lieu de COPY | Download URL, extraction tar automatique, surface élargie | COPY exclusivement sauf cas justifié |
| 4. Secrets en ENV ou build args | Visibles via docker history | Docker BuildKit --mount=type=secret |
| 5. Pas de multi-stage build | Image finale contient tous les outils de build | Multi-stage avec COPY --from= |
| 6. Base image full OS (ubuntu, debian bullseye) | Surface d'attaque large, nombreuses CVE | Distroless, Chainguard, alpine 3.19+ |
| 7. Pas de HEALTHCHECK | Orchestration ne détecte pas les états dégradés | HEALTHCHECK avec endpoint /health |
Détection automatique : les 7 anti-patterns sont détectés par Trivy config (scan Dockerfile), Hadolint (linter Dockerfile), Docker Scout (analyse build). Intégration recommandée en pre-commit hook ou CI pour filtrage systématique.
2. Secure base images — comparaison 2026
| Base image | Taille indicative | CVE typiques | Usage recommandé |
|---|---|---|---|
| gcr.io/distroless/base-debian12:nonroot | ≈ 20 MB | Très faible | Applications Go, Rust, binaires statiques |
| gcr.io/distroless/nodejs20-debian12:nonroot | ≈ 80 MB | Très faible | Applications Node.js runtime-only |
| gcr.io/distroless/python3-debian12:nonroot | ≈ 50 MB | Très faible | Applications Python (sans compilation runtime) |
| chainguard/static | ≈ 3 MB | Extrêmement faible | Binaires statiques, signed Sigstore par défaut |
| chainguard/node:latest | ≈ 60 MB | Très faible (Wolfi OS) | Node.js moderne avec updates rolling |
| alpine:3.19 | ≈ 5 MB | Faible-moyen (musl libc) | Images minimales, attention musl vs glibc bugs |
| ubuntu:22.04 | ≈ 77 MB | Moyen-élevé | À éviter pour production, OK dev |
| debian:bookworm-slim | ≈ 80 MB | Moyen | Alternative si distroless non-applicable |
Chainguard Images (fondée 2021 par Dan Lorenc et anciens Google Container Security) — positionnement 2026 :
- Wolfi OS : distribution Linux conçue pour containers (glibc moderne).
- Signed-by-default avec Sigstore Cosign.
- SBOM attached par défaut sur chaque image.
- CVE fix SLA agressif : patch dans les heures suivant publication CVE critique.
- Open-source (chainguard/images) avec alternatives commerciales premium.
Recommandation 2026 :
- Premier choix : Chainguard Images (modernité plus supply chain native).
- Alternative gratuite équivalente : distroless Google (gcr.io/distroless/*).
- Si besoin shell pour debug : alpine:3.19+ avec USER non-root.
- À éviter : ubuntu:22.04, debian:bookworm-slim en production (surface d'attaque démesurée pour cas standard).
3. Dockerfile sécurisé — pattern multi-stage distroless non-root
Exemple complet avec anti-pattern et pattern recommandé, exploitable en portfolio GitHub.
# ===== ANTI-PATTERN (ne pas utiliser en production) =====
FROM node:latest
WORKDIR /app
# Secret en ENV visible via docker history
ENV API_KEY=sk-production-key-value-hardcoded
# ADD au lieu de COPY
ADD . /app
# Installation dans image finale (outils de build restent)
RUN npm install
# Pas de USER - tourne en root par defaut
CMD ["node", "server.js"]
# ===== PATTERN SECURISE RECOMMANDE 2026 =====
# --- Stage 1 - Build ---
FROM node:20.12.2-alpine3.19 AS builder
WORKDIR /app
# Copy uniquement les fichiers de dependances pour optimisation cache
COPY package.json package-lock.json ./
# Installation avec lockfile strict, aucune installation transitive non-lockee
RUN npm ci --only=production && \
npm cache clean --force
# Copy du code source puis build
COPY . .
RUN npm run build
# Suppression des fichiers inutiles pour stage runtime
RUN rm -rf tests/ docs/ .git/
# --- Stage 2 - Runtime distroless non-root ---
FROM gcr.io/distroless/nodejs20-debian12:nonroot
WORKDIR /app
# Copy uniquement les artefacts necessaires depuis stage builder
# COPY --chown cree ownership nonroot:nonroot (UID 65532)
COPY --from=builder --chown=nonroot:nonroot /app/node_modules ./node_modules
COPY --from=builder --chown=nonroot:nonroot /app/dist ./dist
COPY --from=builder --chown=nonroot:nonroot /app/package.json ./
# User non-root explicite (distroless a deja nonroot UID 65532 par defaut)
USER nonroot
# Port expose (pas de privilege requis si > 1024)
EXPOSE 3000
# Healthcheck pour orchestrateurs
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD ["node", "-e", "require('http').get('http://localhost:3000/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"]
# Entrypoint explicite (distroless fournit /nodejs/bin/node)
CMD ["dist/server.js"]Pour secrets build-time (cas spécifiques type access token pour private registry npm) — utiliser Docker BuildKit secrets mount au lieu d'ENV :
# syntax=docker/dockerfile:1.7
FROM node:20.12.2-alpine3.19 AS builder
WORKDIR /app
COPY package.json package-lock.json ./
# Secret monte temporairement pendant build, JAMAIS persiste dans layer
RUN --mount=type=secret,id=npm_token,target=/root/.npmrc \
npm ci --only=productionBuild avec secret : docker build --secret id=npm_token,src=.npmrc -t myapp:1.0 .
4. Stack scanning 2026 — quatre outils complémentaires
| Outil | Éditeur | Force principale | Coût |
|---|---|---|---|
| Trivy | Aqua Security (open-source) | Scanner universel : images, FS, Git, K8s, SBOM, secrets, IaC misconfig | Gratuit |
| Grype | Anchore (open-source) | Scanner rapide optimisé SBOM, complément de Syft | Gratuit |
| Docker Scout | Docker Inc. | Intégré Docker Desktop et Docker Hub, policy evaluation | Freemium |
| Snyk Container | Snyk | Enrichissement DB vulnérabilités, fix advice, intégration IDE | Freemium |
Commandes essentielles :
# Trivy scan image avec fail-build sur CRITICAL plus HIGH
trivy image --severity CRITICAL,HIGH --exit-code 1 myapp:1.0
# Trivy scan avec format SARIF pour GitHub Advanced Security
trivy image --format sarif --output trivy-results.sarif myapp:1.0
# Trivy config scan sur Dockerfile
trivy config ./Dockerfile
# Trivy secrets scan
trivy image --scanners secret myapp:1.0
# Grype scan SBOM existant
syft myapp:1.0 -o cyclonedx-json > sbom.cdx.json
grype sbom:./sbom.cdx.json --fail-on high
# Docker Scout analyse CVE avec policy evaluation
docker scout cves myapp:1.0
docker scout policy myapp:1.0
# Snyk Container test
snyk container test myapp:1.0 --severity-threshold=highPattern recommandé pipeline CI : Trivy en build (fail-build CRITICAL/HIGH), Grype sur SBOM, Docker Scout en monitoring continu registry.
5. Image signing avec Cosign — keyless OIDC Sigstore
Cosign (projet Sigstore, OpenSSF, Linux Foundation) est devenu le standard de facto signature conteneurs 2026, remplaçant Docker Content Trust (DCT) obsolète.
Mode keyless OIDC (recommandé par défaut CI/CD)
- Signature via identité OIDC plateforme CI (GitHub Actions, GitLab CI, CircleCI).
- Aucune clé privée à gérer ou rotater.
- Certificat éphémère issued par Fulcio (CA Sigstore).
- Signature logguée dans Rekor (transparency log immutable).
- Intégration workflow GitHub Actions quasiment zero-config.
Exemple GitHub Actions avec Cosign keyless :
# .github/workflows/docker-build-sign.yml
# Build et signature image Docker avec Cosign keyless OIDC Sigstore.
name: Build, Scan, and Sign Docker Image
on:
push:
branches: [main]
permissions:
contents: read
packages: write
id-token: write # Obligatoire pour OIDC Cosign keyless
jobs:
build-scan-sign:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# --- Build image ---
- name: Build Docker image
id: build
run: |
IMAGE_TAG="ghcr.io/${{ github.repository }}:${{ github.sha }}"
docker build -t "$IMAGE_TAG" .
docker push "$IMAGE_TAG"
echo "image=$IMAGE_TAG" >> $GITHUB_OUTPUT
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE_TAG")
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
# --- Scan Trivy ---
- name: Trivy vulnerability scan
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ steps.build.outputs.image }}
severity: CRITICAL,HIGH
exit-code: '1'
format: sarif
output: trivy-results.sarif
- name: Upload Trivy results to GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy-results.sarif
# --- Generate SBOM with Syft ---
- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
image: ${{ steps.build.outputs.image }}
format: cyclonedx-json
output-file: sbom.cdx.json
# --- Sign image with Cosign keyless OIDC ---
- name: Install Cosign
uses: sigstore/cosign-installer@v3
- name: Sign image (keyless OIDC Sigstore)
run: |
cosign sign --yes ${{ steps.build.outputs.digest }}
- name: Attest SBOM (keyless OIDC Sigstore)
run: |
cosign attest --yes \
--predicate sbom.cdx.json \
--type cyclonedx \
${{ steps.build.outputs.digest }}
# --- Verify signature localement pour feedback pipeline ---
- name: Verify signature
run: |
cosign verify \
--certificate-identity-regexp "https://github.com/${{ github.repository_owner }}/.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
${{ steps.build.outputs.digest }}Vérification runtime côté Kubernetes via Kyverno (voir Policy as Code : définition) — seules les images signées par votre pipeline CI avec identité OIDC précise peuvent être déployées en production.
6. Runtime hardening — seccomp, AppArmor, capabilities, read-only
Défense en profondeur runtime au-delà de la build image. Cinq contrôles obligatoires en production.
1. Drop des capabilities Linux
Par défaut, Docker attribue 14 capabilities Linux (sur 40+) aux containers. Anti-pattern : garder toutes. Pattern : drop ALL puis ajouter uniquement les nécessaires.
# Docker Compose ou Kubernetes Pod spec
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE # Uniquement si binding port < 10242. Read-only root filesystem
Empêche toute modification du filesystem par le container. Les applications qui nécessitent écriture peuvent utiliser emptyDir volumes pour /tmp, /var/log.
securityContext:
readOnlyRootFilesystem: true
volumes:
- name: tmp
emptyDir: {}
volumeMounts:
- name: tmp
mountPath: /tmp3. Seccomp profile
Restrict les system calls autorisés. Docker default seccomp profile (activé par défaut) bloque déjà ~50 syscalls dangereux. Custom seccomp profile pour restrictions plus strictes.
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": ["read", "write", "open", "close", "stat", "fstat", "lseek", "mmap", "mprotect", "munmap", "brk", "rt_sigaction", "rt_sigprocmask", "rt_sigreturn", "ioctl", "pread64", "pwrite64", "readv", "writev", "access", "pipe", "select", "sched_yield", "mremap", "msync", "mincore", "madvise", "dup", "dup2", "nanosleep", "getitimer", "alarm", "setitimer", "getpid", "sendfile", "socket", "connect", "accept", "sendto", "recvfrom", "sendmsg", "recvmsg", "shutdown", "bind", "listen", "getsockname", "getpeername", "socketpair", "setsockopt", "getsockopt", "clone", "fork", "vfork", "execve", "exit", "wait4", "kill", "uname", "getpriority", "setpriority", "arch_prctl", "gettid", "futex", "sched_setaffinity", "sched_getaffinity", "exit_group"],
"action": "SCMP_ACT_ALLOW"
}
]
}Appliqué via docker run --security-opt seccomp=custom-seccomp.json ou Kubernetes securityContext.seccompProfile.type: Localhost.
4. AppArmor ou SELinux
MAC (Mandatory Access Control) en complément. AppArmor sur Ubuntu/Debian (docker-default profile activé), SELinux sur RHEL/Fedora/AmazonLinux.
5. User namespaces (advanced)
Isolation UID/GID container versus host. Mode --userns-remap ou userns=host contextuel. Docker Desktop 4.25+ supporte user namespaces automatique.
7. CVE container escape à connaître 2019-2024
| CVE | Composant | Année | Impact |
|---|---|---|---|
| CVE-2019-5736 | runc | 2019 | Container escape via overwrite binaire runc. CVSS 8.6. Patch runc 1.0.0-rc6 |
| CVE-2022-0811 | cri-o | 2022 | Kernel parameters modification, container escape. CVSS 8.8 |
| CVE-2022-0492 | kernel cgroups v1 | 2022 | Abuse release_agent pour escape. CVSS 7.0 |
| CVE-2022-0185 | kernel filesystem | 2022 | fsconfig out-of-bounds write, escape possible. CVSS 8.4 |
| CVE-2023-5528 | Kubernetes kubelet | 2023 | In-tree storage driver Local, path traversal |
| CVE-2024-0132 | NVIDIA Container Toolkit | 2024 | TOCTOU container escape, impact GPU workloads. CVSS 9.0. Patch 1.16.2+ |
| CVE-2024-10220 | Kubernetes gitRepo volume | 2024 | Legacy gitRepo plugin exploit escape vers node |
Implication opérationnelle : les container escape ne sont pas théoriques. Défense en profondeur est obligatoire :
- Patch rapide des runtimes (runc, cri-o, containerd, NVIDIA CT).
- Seccomp profile custom restrictif.
- Capabilities drop ALL avec ajouts minimaux.
- Read-only root FS systématique.
- Pod Security Standards restricted sur clusters Kubernetes.
- Monitoring runtime (Falco, Tetragon) pour détection exploits live.
8. Docker Compose secure patterns
Anti-patterns fréquents Docker Compose :
- Pas de version pinning des images.
- Secrets en
environment. - Ports exposés inutilement publics (0.0.0.0).
- Pas de
read_only: true. - Pas de
cap_drop: [ALL].
Pattern recommandé :
# docker-compose.secure.yml
# Pattern Docker Compose securise 2026.
version: '3.9'
services:
api:
image: ghcr.io/myorg/api@sha256:a1b2c3d4e5f6... # Pin digest SHA256
restart: unless-stopped
# Security hardening
user: "65532:65532" # Nonroot UID/GID
read_only: true
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE # Uniquement si port < 1024
security_opt:
- no-new-privileges:true
- seccomp=./seccomp-custom.json
# Limites ressources
mem_limit: 512m
cpus: '1.0'
pids_limit: 200
# Read-only FS avec tmpfs pour writable paths
tmpfs:
- /tmp:size=100m,noexec,nosuid,nodev
# Secrets via Docker secrets (non ENV)
secrets:
- api_db_password
- api_jwt_secret
# Networking
networks:
- internal
ports:
- "127.0.0.1:3000:3000" # Bind localhost uniquement
# Healthcheck
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
secrets:
api_db_password:
file: ./secrets/db_password.txt
api_jwt_secret:
file: ./secrets/jwt_secret.txt
networks:
internal:
driver: bridge
internal: true # Pas de communication exterieure directe9. Checklist sécurité Docker pour review
Checklist reproductible exploitable en review Dockerfile et Compose :
- Dockerfile : USER nonroot présent, base image pinned (tag + digest), multi-stage, COPY exclusivement, pas de secret en ENV/build args, HEALTHCHECK défini, distroless ou Chainguard ou alpine.
- Image : scan Trivy CRITICAL/HIGH passé, SBOM généré, signature Cosign keyless présente, taille < 200 MB pour application runtime.
- Compose/Runtime : user: "65532:65532", read_only: true, cap_drop: [ALL], security_opt no-new-privileges, limits mem/cpu/pids, secrets via Docker secrets pas ENV, ports bind localhost ou network internal.
- Kubernetes : Pod Security Standards restricted, seccompProfile RuntimeDefault minimum, resources requests/limits, PodDisruptionBudget, HPA.
- Pipeline CI : Trivy fail-build HIGH, Syft SBOM, Cosign sign, Cosign attest SBOM, policy verification Kyverno.
10. Bilan Zeroday Cyber Academy
Cinq gains rapides à ROI élevé observés 2023-2026, ordre d'implémentation recommandé :
- Migration vers distroless ou Chainguard Images — réduction CVE 70-90 % immédiate, effort 1-2 jours par service.
- USER non-root systématique — 2 lignes Dockerfile, protection container escape.
- Trivy en pre-commit plus CI fail-build HIGH/CRITICAL — un incident évité amortit largement.
- Signature Cosign keyless OIDC — 30 minutes d'intégration, protection supply chain attack.
- Pod Security Standards restricted sur clusters Kubernetes — blocage automatique des Pods privilégiés.
Ces 5 actions représentent 80 % du bénéfice sécurité Docker avec 20 % de l'effort.
Ce que nous ne cachons pas
- Distroless n'est pas gratuit cognitivement : pas de shell pour debug, nécessite adaptation des workflows.
- Cosign keyless dépend de Sigstore infrastructure — en cas d'indisponibilité temporaire, vérification peut échouer (durée SLA Sigstore 2026 : > 99,9 %).
- Seccomp profile custom demande expertise : trop restrictif bloque l'application, trop permissif n'apporte rien. Démarrer avec
seccomp=runtime/defaultpuis durcir progressivement. - Les 5 gains rapides suffisent pour 80 % des cas — les 20 % restants (custom seccomp, user namespaces, service mesh mTLS) sont pour stacks avancées et contextes régulés OIV/défense.
11. Pour aller plus loin
- Devenir DevSecOps sans expérience : trajectoire DevSecOps complète.
- Compétences DevSecOps à apprendre : cartographie des 7 piliers.
- Policy as Code : définition : complément pour verification images Kubernetes.
- Roadmap DevSecOps : roadmap technique structurée.
- Qu'est-ce qu'un SBOM : supply chain security approfondie.
- Secrets management pour développeurs : complément secrets containers.
12. Points clés à retenir
- 7 anti-patterns Dockerfile à éliminer : root user, tag latest, ADD, secrets ENV, pas multi-stage, base full OS, pas HEALTHCHECK.
- Base image recommandée 2026 : Chainguard Images, distroless Google, alpine 3.19+. Éviter ubuntu/debian slim pour production.
- Pattern multi-stage distroless non-root : réduit taille 3-10x, CVE 70-90 %, élimine shell et outils de build.
- Stack scanning 2026 : Trivy (universel open-source), Grype (SBOM), Docker Scout (intégré), Snyk Container (commercial).
- Cosign keyless OIDC : standard Sigstore, zero-config CI/CD, remplace Docker Content Trust obsolète.
- Runtime hardening : capabilities drop ALL, read-only root FS, seccomp profile, no-new-privileges, Pod Security Standards restricted.
- CVE container escape 2019-2024 : runc, cri-o, cgroups v1, NVIDIA CT TOCTOU CVE-2024-0132 CVSS 9.0, kubelet gitRepo CVE-2024-10220.
- 5 gains rapides ROI élevé : distroless, USER non-root, Trivy fail-build, Cosign sign, Pod Security Standards restricted. 80/20.
- Docker Compose secure : pin digest SHA256, user 65532, read_only, cap_drop ALL, secrets Docker secrets, ports localhost.
- Images Docker = artefact supply chain critique — SBOM + signature + verification runtime obligatoires en production régulée.
Le bootcamp DevSecOps Zeroday Cyber Academy inclut un module approfondi sécurité conteneurs avec labs distroless plus Chainguard Images, Dockerfiles hardened multi-stage, intégration Trivy plus Grype en pipeline, signature Cosign keyless complète, policies Kyverno pour verification runtime, runtime hardening Kubernetes (seccomp, Pod Security Standards), et préparation aux certifications CKS (Certified Kubernetes Security Specialist) plus AWS Certified Security Specialty.







