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.


K02 parle des workloads qui ne devraient jamais arriver dans un cluster de production : pod privilégié, image tirée depuis un registry inconnu, hostPath monté sur /var/run/docker.sock, capability SYS_ADMIN, image latest construite sur un poste de dev, ou conteneur qui démarre un mineur dix secondes après le déploiement.

Le point pénible, c’est que Kubernetes accepte beaucoup de ces objets par défaut si aucun contrôle d’admission ne vient les arrêter. L’API Server valide la syntaxe. Il ne juge pas l’intention.

Vecteurs d’attaque

Le pod privilégié qui devient un accès node

privileged: true donne au conteneur un accès très large aux primitives du noyau. Combiné à hostPID, hostNetwork ou un hostPath, on quitte vite le cadre “application isolée” pour arriver à “processus avec vue sur le node”.

Le scénario classique : un attaquant obtient une exécution de commande dans une application exposée. Le pod tourne avec allowPrivilegeEscalation: true, des capabilities non maîtrisées, et un montage hôte trop généreux. À partir de là, il récupère des secrets, observe les processus du node, ou tente une évasion vers le runtime.

Les images non vérifiées

Une image non signée n’est pas automatiquement malveillante. Mais en incident, elle pose une question à laquelle personne ne sait répondre vite : qui l’a construite, à partir de quoi, et avec quel digest ?

Les tags flottants comme latest aggravent le problème(de manière générale, on ne devrait jamais avoir un latest meme sur un pull docker….). Deux déploiements avec le même manifest peuvent lancer deux artefacts différents.

Sigstore et Cosign ne remplacent pas une bonne hygiène de build, mais ils donnent un garde-fou : si l’image n’est pas signée par l’identité CI attendue, elle ne doit pas passer. La limite est importante : une signature prouve une provenance, pas la qualité du contenu. Si l’identité CI est trop large, si tout le monde peut déclencher le pipeline de release, ou si la clé de signature historique traîne encore dans un secret GitHub Actions, on a juste déplacé le problème.

Les registry trop ouvertes

Autoriser docker.io/* ou n’importe quel registry public depuis la production revient à déléguer une partie de la sécurité du cluster à Internet. On voit souvent ce choix arriver par facilité : une image d’outil, un test rapide, un job Cron temporaire. Six mois plus tard, le temporaire est toujours là.

La règle exploitable en production est plus sèche : registry interne ou liste courte de registries approuvés, digest obligatoire pour les workloads sensibles, exception documentée avec expiration.

Mitigations prioritaires

Poser une baseline Pod Security Standards

Le niveau restricted des Pod Security Standards est le point de départ raisonnable pour les namespaces applicatifs. Il impose notamment l’absence de conteneurs privilégiés, un durcissement du securityContext, et des restrictions sur les volumes.

kubectl label namespace production \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted

Ce n’est pas magique. Les workloads legacy vont casser. C’est justement le signal utile : ils dépendaient d’un privilège implicite qu’il fallait rendre visible.

Bloquer à l’admission avec Kyverno

Kyverno reste très pratique pour exprimer les règles dans le vocabulaire Kubernetes. J’en parle plus longuement dans l’article Kyverno : Policy-as-Code pour Kubernetes.

On commence par six refus très simples :

  • D’abord, pas de privileged: true
  • pas de allowPrivilegeEscalation: true dans les namespaces applicatifs.
  • pas de hostPath, sauf exception système strictement listée
  • Les workloads doivent déclarer runAsNonRoot: true,
  • tirer leurs images depuis un registry approuvé
  • présenter une signature Cosign vérifiable.

Scanner avant l’admission

Trivy doit tourner avant le push d’image et avant le déploiement. Le bon seuil dépend du contexte, mais laisser passer une vulnérabilité critique exploitable à distance dans un workload Internet-facing n’est pas un compromis acceptable.

Pour les manifests, Kubescape donne une lecture utile des écarts NSA/CISA et OWASP. Il complète bien kube-bench, déjà évoqué dans l’article kube-bench : audit CIS Kubernetes.

Supprimer les privilèges de debug permanents

Les images de debug et les pods temporaires sont nécessaires. Le problème, c’est leur durée de vie. Je recommande un namespace dédié, une policy plus permissive mais bornée, et une expiration automatique via GitOps.

Le vrai marqueur de maturité n’est pas “nous n’avons jamais d’exception”. C’est “nous savons qui l’a demandée, pourquoi, et quand elle expire”.

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

Phase Outil Action K02
Code pre-commit, conftest Refuser les manifests avec privileged, hostPath, latest, ou capabilities dangereuses
Build Trivy, Syft, Cosign Scanner l'image, générer le SBOM, signer le digest et bloquer les critiques exploitables
Deploy Kyverno (admission) Vérifier registry, signature, non-root et interdiction des privilèges à l'admission
Operate Kubescape Mesurer les écarts OWASP K02 par namespace et suivre les exceptions
Monitor Falco Alerter sur shell dans conteneur, accès Docker socket, mineur, écriture système ou pod privilégié
🔒 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 📌
  • Un pod privilégié est un risque node : privileged, hostPID, hostNetwork et hostPath doivent être bloqués par défaut.
  • Les images doivent être traçables : registry approuvé, digest stable, scan Trivy, SBOM et signature Cosign.
  • Les capabilities Linux se traitent explicitement : drop ALL, puis ajout très rare et documenté.
  • Kyverno complète les Pod Security Standards : PSS fixe la baseline, Kyverno porte les règles métier et les exceptions.
  • Les exceptions expirent : pas de pod de debug permanent, pas de namespace "temporaire" sans propriétaire.