Aller au contenu
Sécurité high

Sécurité des conteneurs : images, clusters, runtime

17 min de lecture

Vos conteneurs tournent en production, mais sont-ils vraiment sécurisés ? Ce guide vous explique les risques spécifiques aux conteneurs et comment les mitiger à chaque étape : build, deploy et runtime. Vous apprendrez à scanner vos images, durcir vos configurations Kubernetes et détecter les comportements anormaux. Résultat : une stratégie de sécurité conteneurs complète, de la CI/CD à la production.

Les conteneurs ont révolutionné le déploiement d'applications, mais ils introduisent des surfaces d'attaque spécifiques que les approches de sécurité traditionnelles ne couvrent pas.

Le problème fondamental : les conteneurs partagent le noyau de l'hôte. Contrairement à une VM qui a son propre kernel, un conteneur n'est qu'un processus isolé. Si un attaquant exploite une vulnérabilité kernel depuis un conteneur, il peut potentiellement compromettre tout le nœud, et par extension, tous les autres conteneurs qui y tournent.

Comprendre où se situent les risques est la première étape pour les mitiger. Les conteneurs présentent des vulnérabilités à plusieurs niveaux :

Surface d'attaqueRisqueExemple concret
Images vulnérablesCVE dans les dépendances, base image obsolèteLog4Shell présent dans une image Java non mise à jour
Configurations permissivesConteneurs root, capabilities excessivesUn conteneur avec CAP_SYS_ADMIN peut modifier le système hôte
Secrets exposésVariables d'environnement en clair, ConfigMaps accessiblesMot de passe BDD visible via kubectl describe pod
Réseau ouvertAbsence de Network Policies, trafic est-ouest libreUn pod compromis peut scanner tout le cluster
Supply chainImages tierces non vérifiées, registres publicsImage Docker Hub contenant un cryptominer caché

Ces risques ne sont pas théoriques. En analysant 250 000 images publiques de Docker Hub, les chercheurs de Sysdig en ont identifié 1 652 malveillantes : cryptomineurs, secrets embarqués utilisables comme portes dérobées, détournements DNS. Une image tirée d'un registre public n'est pas auditée par quiconque avant d'atterrir sur vos nœuds.

La sécurité des conteneurs est une responsabilité partagée. Chaque profil a un rôle spécifique, et la collaboration est essentielle pour couvrir toutes les surfaces d'attaque.

ProfilResponsabilité principaleActions concrètes
DéveloppeurConstruire des images sécuriséesUtiliser des images de base minimales, ne pas embarquer de secrets, définir un USER non-root
Ops / SREDurcir l'infrastructureAppliquer les Pod Security Standards, configurer les Network Policies, gérer les mises à jour
DevSecOpsAutomatiser les contrôlesIntégrer Trivy dans la CI, bloquer les déploiements non conformes, alerter sur les dérives
RSSI / ComplianceGarantir la conformitéAuditer selon CIS Benchmarks, documenter les exceptions, préparer les certifications

La sécurité des conteneurs ne repose pas sur un seul outil ou une seule étape. Elle s'articule autour de trois phases qui se complètent : Build, Deploy et Runtime. Si une couche échoue, les autres limitent l'impact.

C'est le moment le plus efficace pour détecter les problèmes. Une image vulnérable ne devrait jamais atteindre la production.

Bonnes pratiques :

  • Images de base minimales : Préférez distroless ou alpine à ubuntu. Moins de paquets = moins de CVE potentielles. Sur une machine de test, gcr.io/distroless/python3-debian12 pèse 80 Mo là où python:3.11 en pèse 1,6 Go : tout ce qui disparaît (shell, gestionnaire de paquets, compilateurs) est autant de surface d'attaque et de CVE en moins à traiter.

  • Scanner systématiquement : Intégrez un scanner (Trivy, Grype) dans votre CI. Bloquez le pipeline si une CVE critique est détectée.

  • Ne jamais tourner en root : Ajoutez USER 1000 dans votre Dockerfile. Un conteneur root compromis peut modifier l'hôte.

  • Signer vos images : Utilisez Cosign pour prouver l'origine et l'intégrité de vos images. Le cluster peut refuser les images non signées.

Le multi-stage build ci-dessous compile les dépendances dans une image complète, puis ne recopie que le résultat dans une image distroless qui ne contient ni shell ni pip. Le point qui fait échouer la plupart des tentatives : pip install écrit dans site-packages, pas dans /app. Sans --target et sans PYTHONPATH, l'image se construit sans erreur mais l'application meurt au démarrage sur un ModuleNotFoundError.

# Exemple de Dockerfile sécurisé
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --target=/app/deps -r requirements.txt
FROM gcr.io/distroless/python3-debian12:latest@sha256:2fdb05402a2cf21cf78fdb3ba4c5db167241e9e498140f5bf689d7efb773731f
WORKDIR /app
ENV PYTHONPATH=/app/deps
COPY --from=builder /app/deps /app/deps
COPY app.py .
USER 1000
CMD ["app.py"]

Vérifiez toujours l'image finale en l'exécutant réellement (docker run --rm mon-image) : un docker build qui réussit ne prouve rien sur la présence des dépendances.

Même une image sécurisée peut être déployée de manière dangereuse. Kubernetes offre de nombreuses options de sécurité, mais elles sont souvent désactivées par défaut.

Bonnes pratiques :

  • Pod Security Standards : Appliquez le niveau restricted (ou au minimum baseline) sur vos namespaces. Cela interdit les conteneurs root, les capabilities dangereuses et les montages de volumes sensibles.
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/warn: restricted
  • Network Policies : Par défaut, tous les pods peuvent communiquer entre eux. Définissez des règles explicites pour n'autoriser que le trafic nécessaire.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
  • ResourceQuota et LimitRange : Empêchez un pod compromis de consommer toutes les ressources du nœud (déni de service).

  • RBAC strict : Appliquez le principe du moindre privilège. Un ServiceAccount ne devrait avoir que les permissions strictement nécessaires.

Les phases Build et Deploy ne suffisent pas. De nouvelles CVE sont découvertes quotidiennement, et un attaquant peut exploiter une faille zero-day. La protection runtime surveille les conteneurs en cours d'exécution.

Ce que surveille une solution runtime :

SignalCe qu'il détecteOutil
Syscalls anormauxExécution de shell dans un conteneur, modification de fichiers systèmeFalco
Connexions réseauTrafic vers des IPs suspectes, scan de portsNeuVector, Cilium
Processus inattendusCryptominer, reverse shellFalco, Sysdig
Dérive de configurationModification des fichiers par rapport à l'image d'origineNeuVector

Scénario : intégrer la sécurité dans votre pipeline

Section intitulée « Scénario : intégrer la sécurité dans votre pipeline »

Voyons comment une équipe DevSecOps intègre ces trois phases dans un pipeline CI/CD réel. L'objectif : qu'aucune image vulnérable ou mal configurée n'atteigne la production.

  1. Build : scanner l'image

    Dans la CI (GitLab CI, GitHub Actions, Jenkins), Trivy analyse l'image après le build. Si une CVE critique (score CVSS ≥ 9) est détectée, le pipeline échoue.

    .gitlab-ci.yml
    scan-image:
    stage: test
    script:
    - trivy image --exit-code 1 --severity CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  2. Registry : signer l'image

    Avant de pousser l'image vers le registre, elle est signée avec Cosign. La signature prouve qu'elle vient bien de votre CI et n'a pas été modifiée.

    Fenêtre de terminal
    cosign sign --key cosign.key $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  3. Admission : valider les manifests

    Au moment du déploiement, un admission controller (Kyverno, OPA Gatekeeper) vérifie que les manifests respectent les politiques de sécurité : pas de conteneur root, ressources définies, etc.

    # ValidatingPolicy Kyverno : interdire les conteneurs root
    apiVersion: policies.kyverno.io/v1
    kind: ValidatingPolicy
    metadata:
    name: require-non-root
    spec:
    validationActions: [Deny]
    matchConstraints:
    resourceRules:
    - apiGroups: [""]
    apiVersions: ["v1"]
    operations: ["CREATE", "UPDATE"]
    resources: ["pods"]
    validations:
    - expression: >-
    object.spec.containers.all(c,
    has(c.securityContext) &&
    has(c.securityContext.runAsNonRoot) &&
    c.securityContext.runAsNonRoot == true
    )
    message: "Les conteneurs doivent tourner en non-root (runAsNonRoot: true)."
  4. Runtime : surveiller en production

    NeuVector ou Falco surveille les conteneurs déployés. Une alerte est déclenchée si un comportement anormal est détecté (shell interactif, connexion sortante suspecte).

Résultat : une vulnérabilité Log4Shell est détectée dans une dépendance Java lors du scan CI. Le pipeline échoue, le développeur est notifié, et l'image n'atteint jamais la production. Temps de détection : 45 secondes au lieu de plusieurs jours (ou jamais) sans scan.

Même avec les bons outils, certaines erreurs reviennent fréquemment. Voici les pièges les plus courants et comment les éviter :

Chaque phase a sa famille d'outils, et un outil de la phase Build ne remplace jamais un outil de la phase Runtime. Les trois tableaux qui suivent se lisent par la colonne Quand l'utiliser : elle indique le contexte de déclenchement, pas une préférence de qualité. Deux outils de la même ligne ne se cumulent pas, ils se remplacent.

Un scanner de vulnérabilités compare les paquets présents dans une image aux bases de CVE publiques. Son résultat dépend donc entièrement de la fraîcheur de sa base : un scan lancé sur une image inchangée peut remonter dix vulnérabilités de plus qu'hier. Regardez surtout la colonne Forces pour savoir si l'outil couvre autre chose que les images (dépôts Git, manifests IaC), car c'est ce qui décide si vous en installez un seul ou plusieurs.

OutilForcesQuand l'utiliser
TrivyRapide, gratuit, multi-cibles (images, repos, IaC)Premier choix pour la CI/CD
GrypeLéger, intégration AnchoreAlternative à Trivy
SnykBase de données CVE enrichie, remédiation guidéeSi vous avez un budget sécurité

Ces outils ne cherchent pas de CVE : ils comparent la configuration réelle de votre cluster à un référentiel (CIS Benchmark, recommandations NSA). Ils répondent à la question « ma configuration est-elle conforme », pas « mes images sont-elles vulnérables ». Choisissez selon le référentiel que votre organisation doit prouver, car c'est ce référentiel qui sera exigé lors d'un audit externe.

OutilForcesQuand l'utiliser
KubescapeCIS Benchmarks, NSA guidelines, gratuitAudit initial et continu
kube-benchCIS Kubernetes Benchmark officielAudit de conformité formel
PolarisBest practices Kubernetes, simplePremiers pas en sécurité K8s

La protection runtime observe les appels système et le trafic des conteneurs déjà démarrés. Contrairement aux deux familles précédentes, elle produit des alertes en continu et non un rapport ponctuel : prévoyez qui les reçoit et qui y répond avant de la déployer. Un outil runtime installé sans destinataire d'alerte ne protège personne.

OutilForcesQuand l'utiliser
FalcoOpen source, basé sur eBPF/syscallsDétection d'intrusion
NeuVectorProtection complète (réseau + runtime), pare-feu L7Sécurité enterprise
Sysdig SecureObservabilité + sécurité intégréesSi vous utilisez déjà Sysdig

Les pages ci-dessous reprennent chacun de ces outils en mode pratique : installation, première exécution et lecture du rapport. Si vous partez de zéro, commencez par Trivy (un scan d'image se lance en une commande et donne un résultat immédiat), puis Kubescape pour mesurer l'écart de votre cluster aux CIS Benchmarks. NeuVector et Cosign supposent un cluster déjà en place et une chaîne de build maîtrisée.

  1. Les conteneurs partagent le kernel : une vulnérabilité exploitée peut compromettre tout le nœud, pas juste le conteneur.

  2. Défense en profondeur : Build (scan d'images) + Deploy (durcissement K8s) + Runtime (détection) = trois couches qui se complètent.

  3. Shift-left : détectez les problèmes dans la CI, pas en production. Un scan prend 30 secondes, une remédiation d'incident prend des jours.

  4. Pod Security Standards : appliquez au minimum le niveau baseline, visez restricted en production.

  5. Network Policies obligatoires : sans elles, le trafic est-ouest est grand ouvert. Un pod compromis peut attaquer tout le cluster.

  6. Scan continu : les CVE sont découvertes quotidiennement. Scannez aussi les images déjà déployées.

Cette checklist sert de revue avant une mise en production, pas de liste de courses à cocher d'un bloc. Traitez-la dans l'ordre Build, Deploy, Runtime : chaque bloc suppose le précédent acquis. Une case laissée vide n'est pas forcément un blocage, mais elle doit être une exception documentée, avec un nom en face.

Ce bloc se joue entièrement dans le dépôt et dans la CI, avant qu'aucune image n'atteigne un registre. C'est le moment le moins coûteux : une correction ici est un commit, la même correction en production est un incident. Le point le plus souvent oublié reste la signature des images, parce qu'elle demande de gérer une clé.

  • Images de base minimales (distroless, alpine)
  • Scanner intégré dans la CI (Trivy, Grype)
  • Pipeline bloqué si CVE critique détectée
  • Pas de secrets dans les images
  • Dockerfile avec USER non-root
  • Images signées (Cosign)

Ces contrôles se posent sur le namespace et sur le cluster, pas sur l'image. Ils protègent même contre une image que vous n'avez pas construite, ce qui en fait le dernier filet quand une dépendance tierce arrive dans votre chaîne. Vérifiez chaque case sur un namespace réel : un label Pod Security mal orthographié est ignoré silencieusement par l'API server, sans le moindre message d'erreur.

  • Pod Security Standards appliqués (baseline ou restricted)
  • Network Policies définies (deny by default)
  • RBAC avec moindre privilège
  • ResourceQuota et LimitRange configurés
  • Secrets dans des Secret K8s (pas en variables d'environnement)

Le bloc runtime est celui qui se dégrade le plus vite : un agent déployé une fois et jamais relu finit par alerter dans le vide. Les deux cases qui comptent réellement sont la destination des alertes et la procédure de réponse, car un détecteur sans destinataire ne change rien au délai de réaction.

  • Outil de détection déployé (Falco, NeuVector)
  • Alertes configurées pour les comportements anormaux
  • Scan régulier des images en production
  • Procédure de réponse aux incidents documentée

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn