Security musings

Catégories

Tags

🔍 Licence d'Utilisation 🔍

Sauf mention contraire, le contenu de ce blog est sous licence CC BY-NC-ND 4.0.

© 2025 à 2042 Sébastien Gioria. Tous droits réservés.

⏱️
Temps de lecture estimé
~10 minutes

Cet article fait partie de la série OWASP Top 10 Kubernetes 2026. Retrouvez le tableau de bord complet des dix risques et la matrice STRIDE sur la page d’entrée de la série.


K04 descend d’un cran par rapport à K02. K02 demande si le workload a le droit d’entrer dans le cluster. K04 demande si le conteneur lui-même est durci une fois lancé.

Un conteneur qui tourne en root, avec un filesystem writable, sans seccomp, avec un shell complet et des packages inutiles, n’a pas besoin d’être “malveillant” pour être dangereux. Il suffit qu’une vulnérabilité applicative donne une exécution de commande. Le reste est déjà préparé.

Le cas le plus parlant : image Debian complète, USER root, bash, curl, apk ou apt disponible, filesystem writable, aucun securityContext. L’équipe pense avoir livré une application. Elle a aussi livré une boîte à outils à l’attaquant.

Cela ne devrait réellement pas arriver si vous avez une vrai chaine DevSecOPS car vous avez une gate sur cela n’est-il pas ?

Si malgré tout vous ne l’avez pas (saismal (c) ), ou ne pouvez pas (oui oui ca arrive….), vous trouverez quelques mitigations ici.

Vecteurs d’attaque

Le conteneur root

root dans un conteneur n’est pas root sur le node, mais ce n’est pas anodin. En cas de mauvaise configuration runtime, de volume monté, ou de vulnérabilité kernel, le différentiel d’impact est réel.

Le minimum : runAsNonRoot: true, un UID explicite, et une image compatible avec cet UID. Si l’application casse, on corrige l’image. On ne désactive pas le contrôle en production “pour gagner du temps”.

Le filesystem writable

Un filesystem racine writable facilite l’écriture de payloads, la modification de binaires, le dépôt d’outils et certains contournements de détection. readOnlyRootFilesystem: true force à déclarer les vrais besoins d’écriture via des volumes dédiés.

Cette option révèle souvent des surprises :

  • logs écrits dans /tmp (au lieu d’un envoi dans le SIEM), c
  • ache dans /root,
  • framework qui veut créer un fichier au démarrage.

Seccomp et AppArmor absents

seccompProfile: RuntimeDefault réduit la surface de syscalls accessibles. AppArmor ajoute un confinement côté Linux quand il est disponible. Ces contrôles ne rendent pas le conteneur hyper méga secure, mais ils cassent des chemins d’exploitation.

Depuis Kubernetes 1.25, RuntimeDefault est le choix pragmatique. Il faut quand même rester sobre sur la promesse : ce profil :

  • réduit la surface de syscalls,
  • ne corrige pas une image root,
  • un volume hôte trop large
  • ou une application vulnérable.

Les profils custom sont utiles pour des workloads critiques, mais ils demandent de la maintenance.

Les images trop riches

Une image de production n’a pas besoin de compilateur, gestionnaire de paquets, shell interactif, clients réseau inutiles et documentation complète.

Distroless, Chainguard ou une image minimale bien maîtrisée réduisent ce qui peut être exploité après compromission.

Attention au piège inverse : une image minimale mal comprise complique le debug et peut devenir impossible à maintenir si personne ne sait la reconstruire. Une image minimale garde seulement ce qui sert à exécuter l’application. Une image maintenable a aussi une base suivie, des CVE triées, un SBOM, une procédure de rebuild et une image de diagnostic séparée dans un namespace contrôlé avec expiration.

Mitigations possibles

Pod Security Standards en mode restricted

Comme pour K02, le niveau restricted est le socle. Il évite de rediscuter à chaque merge des évidences :

  • pas de privilège,
  • pas de host namespace,
  • pas de capabilities dangereuses,
  • pas d’élévation.
  • pas de paf le chien (ni de panpan culcul)

Images minimales et signatures

Trivy détecte les vulnérabilités connues, mais aussi les packages installés. Une image qui contient cent cinquante paquets inutiles expose mécaniquement plus de surface.

Le pipeline doit produire :

  • un SBOM
  • un scan vulnérabilités
  • une signature Cosign du digest
  • une attestation de provenance minimale
  • un blocage si l’image n’est pas celle qui a été validée

Tests runtime

On teste ce que l’on affirme :

  • écrire dans / doit échouer
  • lancer /bin/sh doit échouer si l’image n’embarque pas de shell
  • lire /proc/1/status doit montrer les capabilities attendues
  • le profil seccomp doit être RuntimeDefault

Ces tests sont simples et souvent plus parlants qu’un long standard interne, et cela s’automatise…

DevSecOps : intégrer K04 dans la chaîne CI/CD

Phase Outil Action K04
Code Hadolint, semgrep, pre-commit Détecter USER root, packages inutiles et manifests sans securityContext.
Build Trivy, Dependency-Track, cycloneDX Scanner l'image, générer le SBOM et bloquer les vulnérabilités critiques exploitables.
Test kind, kubectl exec Vérifier non-root, filesystem read-only, drop capabilities et seccomp actif.
Deploy Kyverno Imposer RuntimeDefault, readOnlyRootFilesystem et allowPrivilegeEscalation: false.
Monitor Falco Alerter sur shell, écriture système, modification de binaire et chargement module kernel.

K04 complète naturellement l’article K02 : admission d’un côté, durcissement runtime de l’autre.

🔒 Plus d'éléments en contenu premium
Ce contenu représente de nombreuses heures de travail, d'expérience etc... J'ai remarqué que mon contenu était repris par certaines sociétés/personnes et j'ai donc décidé de donner du contenu minimal sur ce blog. C'est pourquoi je vous invite a me contacter sur LinkedIn en mentionnant cet article pour plus d'informations.

À retenir 📌
  • Non-root doit être la norme : runAsNonRoot et UID explicite dans les workloads applicatifs.
  • Le filesystem racine doit être read-only : les vrais besoins d'écriture passent par des volumes déclarés.
  • Seccomp RuntimeDefault est le minimum : les profils custom viennent ensuite, pour les workloads critiques.
  • Drop ALL sur les capabilities : on réajoute rarement, explicitement, et avec une justification.
  • L'image de production n'est pas une image de debug : shell, package manager et outils réseau doivent être l'exception.