
Les Pod Security Standards (PSS) définissent 3 niveaux de restrictions de sécurité pour vos pods Kubernetes : Privileged (aucune restriction), Baseline (bloque les escalades évidentes), et Restricted (hardening maximal). Ce guide vous explique quand utiliser chaque niveau et comment les appliquer sans casser vos applications.
Ce sujet relève du domaine Minimize Microservice Vulnerabilities de la certification CKS, qui pèse 20 % de l'épreuve.
Qu'est-ce que Pod Security Standards ?
Section intitulée « Qu'est-ce que Pod Security Standards ? »Pod Security Standards (PSS) est le standard officiel Kubernetes pour définir les niveaux de sécurité des pods. Pensez-y comme à des "profils de sécurité prédéfinis" que vous pouvez appliquer à vos namespaces.
Pourquoi c'est important ?
Section intitulée « Pourquoi c'est important ? »Par défaut, Kubernetes autorise des configurations dangereuses. Sans restriction explicite, n'importe qui pouvant créer un Pod peut lui donner un accès complet au nœud hôte : c'est exactement ce qu'un attaquant recherche.
Voici ce qui est autorisé si vous ne configurez rien :
| Configuration par défaut | Risque |
|---|---|
Pod en root (UID 0) | Escalade de privilèges si le conteneur est compromis |
privileged: true autorisé | Accès complet à l'hôte |
Montage de / possible | Lecture/écriture du système hôte |
hostNetwork: true autorisé | Écoute sur les ports de l'hôte |
Scénario d'attaque : Un attaquant compromet une application vulnérable dans un pod. Si le pod tourne en root avec privileged: true, l'attaquant peut s'échapper du conteneur, accéder au nœud, puis pivoter vers d'autres nœuds du cluster. Les PSS empêchent ce scénario en bloquant ces configurations dès le déploiement.
Les PSS bloquent ces configurations selon leur niveau de restriction.
Les 3 niveaux PSS
Section intitulée « Les 3 niveaux PSS »Les trois niveaux forment une échelle, pas un menu : chacun contient les
restrictions du précédent et en ajoute. Privileged n'interdit rien,
Baseline bloque les élévations de privilèges les plus connues, Restricted
impose le durcissement complet. Les onglets ci-dessous donnent, pour chacun, ce
qu'il autorise et le manifeste minimal qui y passe. Lisez-les dans l'ordre : le
saut de difficulté se situe entre les deux derniers.
Niveau Privileged
Section intitulée « Niveau Privileged »Aucune restriction, Ce niveau autorise tout, y compris les configurations les plus dangereuses.
Quand l'utiliser :
- Namespaces système (
kube-system) - Outils d'infrastructure (monitoring agents, CNI, CSI drivers)
- Jamais pour des applications métier
# Ce pod est autorisé en PrivilegedapiVersion: v1kind: Podmetadata: name: privileged-podspec: containers: - name: debug image: ubuntu:24.04@sha256:224a1869083a311ef3f13648a154ba79832fbef6364d31493642ca03082da254 securityContext: privileged: true # Accès root complet à l'hôte runAsUser: 0 # Exécution en rootUne règle à ne pas relâcher : le niveau Privileged est réservé aux
composants système, ceux qui ont réellement besoin d'accéder au nœud. Ne
l'appliquez jamais à un namespace applicatif, même temporairement pour
débloquer un déploiement : c'est ainsi qu'un cluster se retrouve sans aucune
contrainte plusieurs mois après l'incident qui l'a justifié.
Niveau Baseline
Section intitulée « Niveau Baseline »Restrictions minimales, Bloque les escalades de privilèges les plus dangereuses tout en restant compatible avec la majorité des workloads.
Ce qui est bloqué :
| Configuration | Pourquoi c'est bloqué |
|---|---|
privileged: true | Accès complet à l'hôte |
hostPID: true | Voir les processus de l'hôte |
hostIPC: true | Accès à la mémoire partagée de l'hôte |
hostNetwork: true | Écoute sur les ports de l'hôte |
| Capabilities dangereuses | SYS_ADMIN, NET_RAW, etc. |
Quand l'utiliser :
- Applications legacy ne supportant pas Restricted
- Première étape de migration depuis Privileged
- Environnements de développement
# Ce pod est compatible BaselineapiVersion: v1kind: Podmetadata: name: baseline-podspec: containers: - name: app image: nginx:1.25@sha256:a484819eb60211f5299034ac80f6a681b06f89e65866ce91f356ed7c72af059c securityContext: runAsUser: 1000 # Non-root recommandé allowPrivilegeEscalation: falseNiveau Restricted
Section intitulée « Niveau Restricted »Hardening maximal, Applique les meilleures pratiques de sécurité. C'est le niveau recommandé pour la production.
Ce qui est exigé :
| Exigence | Valeur requise |
|---|---|
runAsNonRoot | true |
allowPrivilegeEscalation | false |
seccompProfile | RuntimeDefault ou Localhost |
capabilities.drop | ALL |
| Volumes autorisés | Seulement configMap, secret, emptyDir, persistentVolumeClaim, projected |
Quand l'utiliser :
- Applications de production
- Workloads manipulant des données sensibles
- Préparation à la certification CKS
# Ce pod est conforme RestrictedapiVersion: v1kind: Podmetadata: name: restricted-podspec: securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault containers: - name: app image: nginx:1.25-alpine@sha256:516475cc129da42866742567714ddc681e5eed7b9ee0b9e9c015e464b4221a00 securityContext: runAsUser: 1000 runAsGroup: 1000 allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALLComment appliquer PSS ?
Section intitulée « Comment appliquer PSS ? »Kubernetes applique les Pod Security Standards via Pod Security Admission (PSA), un admission controller intégré depuis la version 1.25.
Les 3 modes d'application
Section intitulée « Les 3 modes d'application »PSA offre trois manières d'appliquer un niveau PSS à un namespace. Ces modes peuvent être combinés pour une migration progressive et sécurisée.
| Mode | Comportement | Usage |
|---|---|---|
enforce | Bloque les pods non conformes | Production |
audit | Enregistre dans les audit logs | Migration |
warn | Affiche un warning à l'utilisateur | Développement |
Les trois sont indépendants, et la différence se voit à l'œil nu. Sur un
namespace en warn seulement, le Pod non conforme est créé, précédé d'un
avertissement :
Warning: would violate PodSecurity "restricted:latest": allowPrivilegeEscalation!= false (container "non-conforme" must setsecurityContext.allowPrivilegeEscalation=false), unrestricted capabilities ...pod/non-conforme createdSur un namespace en enforce, la même commande échoue et aucun Pod n'existe :
Error from server (Forbidden): pods "non-conforme" is forbidden:violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false ...Notez le pod/non-conforme created de la première sortie : un avertissement ne
protège de rien, il informe.
Stratégie de migration recommandée :
- D'abord
warn+audit: Les développeurs voient les warnings, les violations sont loggées, mais rien n'est bloqué. Cela vous donne le temps de corriger les manifests. - Ensuite
enforce: Une fois tous les pods conformes, activez le blocage. Toute tentative de déploiement non conforme sera refusée.
Cette approche évite de casser la production du jour au lendemain.
Appliquer PSS à un namespace
Section intitulée « Appliquer PSS à un namespace »PSS ne s'applique pas à un Pod mais à un namespace entier, par des labels. Deux façons de les poser, strictement équivalentes dans leur effet : les écrire dans le manifeste du namespace, ce qui les rend versionnables, ou les ajouter en ligne de commande sur un namespace existant. La première convient à une infrastructure décrite en Git, la seconde à un test rapide.
Méthode 1 : Labels sur le namespace
apiVersion: v1kind: Namespacemetadata: name: production labels: # Applique Restricted en mode enforce pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/enforce-version: latest
# Audit les violations Restricted pod-security.kubernetes.io/audit: restricted pod-security.kubernetes.io/audit-version: latest
# Avertit pour Restricted pod-security.kubernetes.io/warn: restricted pod-security.kubernetes.io/warn-version: latestMéthode 2 : kubectl label
# Appliquer Restricted sur un namespace existantkubectl label namespace production \ pod-security.kubernetes.io/enforce=restricted \ pod-security.kubernetes.io/warn=restricted \ pod-security.kubernetes.io/audit=restricted
# Vérifier les labelskubectl get namespace production -o yaml | grep pod-securityMigrer vers Restricted sans casser vos applications
Section intitulée « Migrer vers Restricted sans casser vos applications »-
Audit d'abord : identifiez les violations
Appliquez d'abord en mode
audit+warnpour voir ce qui casserait :Fenêtre de terminal kubectl label namespace monapp \pod-security.kubernetes.io/audit=restricted \pod-security.kubernetes.io/warn=restrictedCréez un pod de test et observez les warnings :
Fenêtre de terminal kubectl run test --image=nginx:1.25@sha256:a484819eb60211f5299034ac80f6a681b06f89e65866ce91f356ed7c72af059c -n monapp# Warning: would violate "restricted:latest"... -
Corrigez vos Deployments
Pour chaque violation identifiée, mettez à jour le
securityContext:spec:securityContext:runAsNonRoot: trueseccompProfile:type: RuntimeDefaultcontainers:- name: appsecurityContext:allowPrivilegeEscalation: falsereadOnlyRootFilesystem: truerunAsUser: 1000capabilities:drop: ["ALL"] -
Testez en staging
Déployez avec les nouveaux
securityContextet validez que l'application fonctionne. -
Appliquez Restricted en enforce
Une fois tous les pods conformes :
Fenêtre de terminal kubectl label namespace production \pod-security.kubernetes.io/enforce=restricted \--overwrite
Le blocage le plus fréquent vient de l'image, pas du manifeste. Beaucoup
d'images officielles s'exécutent en root par défaut, nginx, redis ou postgres
par exemple, et aucun securityContext ne les rendra conformes si elles n'ont
pas été construites pour. Cherchez leur variante non-root : nginx
devient nginxinc/nginx-unprivileged, et la plupart des éditeurs publient un
équivalent. C'est souvent le seul changement à faire pour passer en
Restricted.
Erreurs fréquentes et solutions
Section intitulée « Erreurs fréquentes et solutions »Les trois messages ci-dessous représentent la quasi-totalité des rejets après un
passage en Restricted, et ils ont un point commun : ils apparaissent au
démarrage du Pod, pas à l'apply. Le manifeste est accepté, le Pod est créé,
et c'est l'admission qui refuse. Cherchez donc dans les événements du Pod ou
de son objet parent, jamais dans les journaux du conteneur, qui n'existent pas
encore.
PSA ne signale pas les violations une par une
Section intitulée « PSA ne signale pas les violations une par une »Le point de méthode qui fait gagner le plus de temps : le message liste toutes les violations en une fois. Corriger la première et relancer pour découvrir la suivante est une perte de temps, tout est déjà écrit.
Voici le message complet, relevé sur un Pod nginx sans aucun securityContext
dans un namespace en restricted :
Error from server (Forbidden): pods "non-conforme" is forbidden:violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "non-conforme" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "non-conforme" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "non-conforme" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "non-conforme" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")Quatre violations, quatre corrections, et le manifeste ci-dessous les couvre
toutes. Il a été appliqué avec succès dans un namespace en restricted, ce
qui en fait le plus petit Pod conforme possible :
apiVersion: v1kind: Podmetadata: name: conformespec: securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault containers: - name: app image: nginx:1.30@sha256:d5792f71a9496b833bc08ea834a758c46e2b6a6306c10f4be926f38a656cdc1c securityContext: allowPrivilegeEscalation: false capabilities: drop: ["ALL"]Deux champs se posent au niveau du Pod, deux au niveau du conteneur : c'est l'erreur de placement la plus fréquente. Les sections suivantes reprennent chaque violation isolément, pour le cas où vous n'en rencontreriez qu'une.
Erreur 1 : "container has runAsNonRoot and image will run as root"
Section intitulée « Erreur 1 : "container has runAsNonRoot and image will run as root" »Cause : L'image utilise root mais vous avez runAsNonRoot: true.
Solution :
securityContext: runAsUser: 1000 # Forcer un UID non-root runAsGroup: 1000 runAsNonRoot: trueErreur 2 : "seccompProfile is required"
Section intitulée « Erreur 2 : "seccompProfile is required" »Cause : Le niveau Restricted exige un profil seccomp.
Solution :
spec: securityContext: seccompProfile: type: RuntimeDefaultErreur 3 : "unrestricted capabilities"
Section intitulée « Erreur 3 : "unrestricted capabilities" »Cause : Vous n'avez pas droppé toutes les capabilities.
Solution :
containers:- name: app securityContext: capabilities: drop: ["ALL"] # Si vraiment nécessaire, ajoutez explicitement : # add: ["NET_BIND_SERVICE"]Comparatif des 3 niveaux
Section intitulée « Comparatif des 3 niveaux »Ce tableau résume ce qui est autorisé ou bloqué à chaque niveau. Utilisez-le comme référence rapide lors de vos audits de sécurité.
| Configuration | Privileged | Baseline | Restricted |
|---|---|---|---|
privileged: true | ✅ | ❌ | ❌ |
hostNetwork/PID/IPC | ✅ | ❌ | ❌ |
hostPath volumes | ✅ | ✅ | ❌ |
| Root (UID 0) | ✅ | ✅ | ❌ |
allowPrivilegeEscalation | ✅ | ✅ | ❌ |
| Capabilities dangereuses | ✅ | ❌ | ❌ |
| Seccomp requis | ❌ | ❌ | ✅ |
Comment lire ce tableau ?
- Baseline bloque les vulnérabilités critiques (
privileged,hostNetwork) mais autorise encore des pratiques risquées (hostPath, root). - Restricted va plus loin : il exige un profil seccomp, interdit root, et limite les volumes montés. C'est la posture "zéro confiance" pour vos workloads.
- Attention à
hostPath: Même en Baseline, un attaquant peut monter/etc/shadows'il contrôle le manifest du pod. C'est pourquoi Restricted est recommandé en production.
À retenir
Section intitulée « À retenir »- 3 niveaux : Privileged (tout autorisé), Baseline (bloque le pire), Restricted (hardening maximal)
- Production = Restricted : C'est le niveau recommandé par la documentation Kubernetes
- Migration progressive : Utilisez
auditetwarnavantenforce - Pod Security Admission : L'admission controller natif qui applique les PSS via des labels
- CKS : Les PSS représentent 20% du domaine "Minimize Microservice Vulnerabilities"
Testez vos connaissances
Section intitulée « Testez vos connaissances »Sept questions sur ce qui coûte le plus cher en pratique : la différence
réelle entre les trois niveaux, les trois modes d'application, et la
lecture des rejets qui suivent un passage en Restricted.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
Pour aller plus loin
Section intitulée « Pour aller plus loin »- VAP et MAP, les policies natives : Les règles en CEL pour tout ce que les trois profils PSS ne couvrent pas.
- Kyverno : Un moteur de policies capable de corriger un manifest non conforme.
- VAP vs Kyverno vs Gatekeeper : Le comparatif des moteurs à placer au-dessus des profils PSS.