Aller au contenu
English
Conteneurs & Orchestration medium

ServiceAccounts pour développeurs

35 min de lecture

logo kubernetes

Un ServiceAccount est l'identité Kubernetes de votre application. Chaque Pod est associé à un ServiceAccount. Lorsqu'un Pod doit appeler l'API Kubernetes, il peut utiliser les credentials montés pour ce ServiceAccount, sauf si ce montage est désactivé. Ce guide vous montre comment créer des ServiceAccounts dédiés avec les permissions minimales nécessaires.

  • Comprendre le rôle des ServiceAccounts comme identité
  • Créer un ServiceAccount dédié
  • Configurer les permissions avec Role et RoleBinding
  • Maîtriser les tokens projetés modernes
  • Désactiver le montage de token quand inutile
  • Appliquer les bonnes pratiques de sécurité

Ce tableau donne la combinaison d'objets à retenir selon le besoin. La ligne la plus utile est la quatrième : un Pod qui n'appelle jamais l'API Kubernetes ne doit tout simplement pas recevoir de token, et c'est le cas de la majorité des applications web classiques.

BesoinOutil recommandé
Pod lit des ressources dans son namespaceRole + RoleBinding
Même permission réutilisée dans plusieurs namespacesClusterRole + RoleBinding (par namespace)
Accès réellement global au clusterClusterRole + ClusterRoleBinding
Pod n'appelle jamais l'API KubernetesautomountServiceAccountToken: false
Test ponctuel d'un tokenkubectl create token

Par défaut, un Pod utilise le ServiceAccount default du namespace. Ce n'est pas dangereux en soi, mais c'est rarement un bon choix pour une application de production :

ProblèmeConséquence
Identité partagéePlusieurs workloads apparaissent sous la même identité vis-à-vis de l'API
Traçabilité réduiteLa corrélation d'audit devient moins fine
Permissions héritéesTout RoleBinding sur default s'applique à tous les Pods

Une nuance utile pour ne pas se tromper de cible : le risque n'est pas le nom default, c'est le partage d'identité entre des workloads qui n'ont pas les mêmes besoins, et la tentation d'attacher à cette identité commune des permissions trop larges. Un RoleBinding posé sur default s'applique d'un coup à tous les Pods du namespace qui n'ont pas déclaré autre chose.

Solution : Un ServiceAccount par application (ou groupe d'applications avec le même besoin).

L'objet est volontairement minimal : un nom et un namespace suffisent. Un ServiceAccount est local à son namespace, deux objets portant le même nom dans deux namespaces différents sont deux identités distinctes. À sa création il ne dispose d'aucun droit, il faudra un Role et un RoleBinding pour lui en accorder.

serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-sa
namespace: mon-app

Ou en une ligne :

Fenêtre de terminal
kubectl create serviceaccount app-sa -n mon-app

Adoptez une convention dès le premier ServiceAccount, <app>-sa par exemple. Ce n'est pas cosmétique : c'est ce qui rend lisible la sortie de kubectl get rolebindings -o wide le jour où vous cherchez qui a le droit de faire quoi.

RBAC (Role-Based Access Control) définit ce que le ServiceAccount peut faire. Le modèle repose sur trois éléments qu'il faut relier : un sujet (ici le ServiceAccount), un ensemble de règles décrivant des actions autorisées, et un binding qui associe les deux. Kubernetes fonctionne en refus par défaut, tout ce qui n'est pas explicitement autorisé est interdit, et il n'existe aucune règle de refus à écrire.

Quatre objets suffisent à couvrir tous les cas, et leur nom porte à confusion. Retenez que le préfixe Cluster indique la portée de l'objet, pas nécessairement celle des permissions accordées : c'est le binding choisi qui tranche.

RessourcePortéeDescription
RoleNamespacePermissions dans un namespace
ClusterRoleClusterDéfinition de permissions réutilisable
RoleBindingNamespaceAssocie Role ou ClusterRole à un sujet dans un namespace
ClusterRoleBindingClusterAssocie ClusterRole à un sujet pour tout le cluster

Un Role liste les permissions accordées dans un namespace :

role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: mon-app
rules:
- apiGroups: [""] # "" = core API group
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]

Les verbes disponibles :

VerbeAction
getLire une ressource
listLister les ressources
watchObserver les changements
createCréer une ressource
updateModifier une ressource
patchModifier partiellement
deleteSupprimer une ressource

Le RoleBinding connecte le Role au ServiceAccount :

rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: mon-app
subjects:
- kind: ServiceAccount
name: app-sa
namespace: mon-app
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io

Réutiliser un ClusterRole dans plusieurs namespaces

Section intitulée « Réutiliser un ClusterRole dans plusieurs namespaces »

Cas fréquent : vous avez besoin des mêmes permissions dans plusieurs namespaces, mais pas sur tout le cluster.

Solution : Créez un ClusterRole (définition réutilisable), puis un RoleBinding par namespace.

clusterrole-reusable.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: configmap-reader
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]

Puis, dans chaque namespace où c'est nécessaire :

rolebinding-namespace-a.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-configmap-reader
namespace: namespace-a
subjects:
- kind: ServiceAccount
name: app-sa
namespace: namespace-a
roleRef:
kind: ClusterRole # Référence le ClusterRole
name: configmap-reader
apiGroup: rbac.authorization.k8s.io

Cette combinaison est la plus utile des quatre, et la moins connue : une définition centrale de permissions, réutilisée sans copier-coller, mais dont la portée effective reste limitée au namespace du RoleBinding. Corriger la définition en un seul endroit corrige tous les namespaces à la fois.

Certaines charges de travail ont besoin de voir l'ensemble du cluster : un agent de supervision qui collecte les métriques de tous les namespaces, un opérateur qui surveille ses ressources personnalisées partout. Dans ce cas seulement, le ClusterRoleBinding accorde les permissions sur la totalité du cluster, y compris les namespaces créés après le binding.

clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespace-reader
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: app-namespace-reader
subjects:
- kind: ServiceAccount
name: app-sa
namespace: mon-app
roleRef:
kind: ClusterRole
name: namespace-reader
apiGroup: rbac.authorization.k8s.io

Le champ serviceAccountName se déclare dans la spécification du Pod. Sur un Deployment, il se place donc dans spec.template.spec et non directement sous le spec du Deployment, confusion fréquente qui fait échouer l'application du manifeste. Si le champ est omis, Kubernetes attribue le ServiceAccount default du namespace. Et le ServiceAccount d'un Pod existant ne se modifie pas : l'API refuse avec un message qui énumère les rares champs mutables d'un Pod, à savoir les images des conteneurs, activeDeadlineSeconds, les tolérations en ajout seul et terminationGracePeriodSeconds. Changer l'identité d'un workload impose donc de le recréer, ce qui se planifie.

pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: mon-pod
namespace: mon-app
spec:
serviceAccountName: app-sa
containers:
- name: app
image: mon-image:1.0.0

Pour un Deployment :

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mon-app
spec:
replicas: 3
template:
spec:
serviceAccountName: app-sa
containers:
- name: app
image: mon-image:1.0.0

Le token est la preuve d'identité que le Pod présente à l'API server pour être reconnu comme « ce ServiceAccount ». Sa gestion a profondément changé au fil des versions de Kubernetes : les jetons permanents stockés dans des Secrets ont cédé la place à des jetons projetés, de courte durée et renouvelés automatiquement. Comprendre cette différence évite de reproduire des pratiques devenues risquées.

Les clusters Kubernetes modernes montent des tokens projetés et liés au Pod. Ces tokens sont :

  • À durée limitée, renouvelés automatiquement avant expiration
  • Audience-bound, portent une audience contrôlée (typiquement l'API server)
  • Liés au Pod, invalidés si le Pod est supprimé

Structure du répertoire monté :

/var/run/secrets/kubernetes.io/serviceaccount/
├── ca.crt # Certificat CA du cluster
├── namespace # Namespace du Pod
└── token # Token JWT (renouvelé automatiquement)

Côté serveur, rien n'est pris pour argent comptant : l'API server vérifie la signature du token, son expiration, les claims d'audience, et la validité des objets auxquels il est lié. Un token présenté après suppression du Pod qui le portait est donc refusé, même s'il n'a pas encore expiré.

Pour tester une identité ou intégrer un composant externe :

Fenêtre de terminal
# Token avec durée par défaut (1h)
kubectl create token app-sa -n mon-app
# Token avec durée personnalisée
kubectl create token app-sa -n mon-app --duration=24h

Le token créé par cette commande vit une heure par défaut, valeur vérifiée sur le cluster de cette formation en comparant les claims iat et exp, et son audience est l'API server lui-même, https://kubernetes.default.svc.cluster.local.

La sortie est un JWT signé par l'API server. En décodant son header avec base64, vous obtenez l'algorithme et l'identifiant de clé :

Fenêtre de terminal
kubectl create token app-sa -n mon-app | cut -d. -f1 | base64 -d
# {"alg":"RS256","kid":"LxkUHA9ITF5w3mg80D102dT48j1E4k1DsNIgUcHOrRg"}

Le payload, deuxième segment, porte huit claims sur ce cluster : aud (audience), iss (issuer), sub (sujet), le trio temporel iat, nbf et exp, l'identifiant unique jti, et un bloc kubernetes.io qui rattache le token au namespace, au ServiceAccount et, pour un token projeté, au Pod lui-même. C'est ce dernier rattachement qui rend le token inutilisable dès que le Pod disparaît.

Un mot sur ce qu'il ne faut pas en faire : ces tokens conviennent à un test ponctuel ou à une intégration, pas à un stockage durable. Les écrire dans un fichier, une variable d'environnement permanente ou un dépôt recrée exactement le problème que les tokens projetés ont supprimé, un secret de longue durée qu'on ne sait plus révoquer.

Par défaut, l'API server signe les tokens ServiceAccount avec une clé privée stockée localement (--service-account-signing-key-file). Cette clé ne quitte jamais le control plane, mais elle reste un secret hautement sensible : sa compromission permettrait de forger n'importe quelle identité de pod.

Kubernetes 1.36 fait passer en GA la signature externe : l'API server délègue l'opération de signature à un service externe via un endpoint Unix domain socket. La clé privée vit alors dans un KMS (HashiCorp Vault, AWS KMS, GCP KMS, Azure Key Vault…) et n'est jamais exposée au control plane.

L'API server ne fabrique plus la signature lui-même : il transmet la demande au service externe par une socket Unix locale et reçoit le jeton signé en retour. La clé privée reste donc chez le fournisseur de signature, et le control plane n'en détient jamais de copie.

Le kube-apiserver, configuré par --service-account-signing-endpoint, envoie la demande de signature au service externe (Vault, KMS) par socket Unix et reçoit le token signé en retour ; la clé privée reste chez le service de signature et n'est jamais exposée au control plane

Sur kubeadm, ajouter dans /etc/kubernetes/manifests/kube-apiserver.yaml :

spec:
containers:
- name: kube-apiserver
command:
- kube-apiserver
- --service-account-signing-endpoint=unix:///var/run/k8s-signer/signer.sock
# Garder --service-account-issuer pour la cohérence des claims
- --service-account-issuer=https://kubernetes.default.svc.cluster.local
volumeMounts:
- name: signer-socket
mountPath: /var/run/k8s-signer
volumes:
- name: signer-socket
hostPath:
path: /var/run/k8s-signer
type: Directory

Le service de signature (Vault avec le plugin vault-plugin-secrets-kubernetes ou un binaire maison conforme au protocole gRPC signing.k8s.io/v1) écoute sur la même socket Unix.

Trois situations justifient cette complexité supplémentaire. Les architectures zero-trust, où aucun secret ne doit résider sur les nœuds. Les environnements multi-clusters qui veulent une autorité de signature unique, un seul KMS signant les tokens de plusieurs clusters. Et les contraintes de conformité, PCI-DSS, FedRAMP ou eIDAS, qui exigent des clés privées gérées par un module matériel.

L'activation de la signature externe est transparente côté workloads : les tokens projetés montés dans les pods continuent d'avoir le même format JWT RS256, le même issuer et la même structure de claims. Seul le porteur de la clé privée change. Aucune adaptation des SDK Kubernetes (client-go, fabric8, kubernetes-python) n'est nécessaire.

Sur EKS, GKE et AKS, ce réglage ne vous concerne pas : ces plateformes exposent leur propre intégration KMS, souvent déjà active, et le flag --service-account-signing-endpoint n'est pas accessible côté client. La signature externe y est gérée par le control plane managé.

Les versions antérieures de Kubernetes créaient des tokens statiques dans des Secrets de type kubernetes.io/service-account-token. Ces tokens :

  • N'expirent jamais
  • Restent valides même après suppression du Pod
  • Sont plus difficiles à révoquer
❌ À éviter - token statique legacy
apiVersion: v1
kind: Secret
metadata:
name: app-sa-token
annotations:
kubernetes.io/service-account.name: app-sa
type: kubernetes.io/service-account-token

Par défaut, Kubernetes monte le token du ServiceAccount dans chaque conteneur du Pod, qu'il en ait besoin ou non. Un attaquant qui obtient l'exécution de code dans le conteneur récupère donc immédiatement une identité valide auprès de l'API server. Retirer ce montage quand il est inutile est l'une des mesures les plus rentables du durcissement : coût nul, surface d'attaque réduite.

La checklist sécurité Kubernetes recommande de ne pas monter de token dans les Pods qui n'en ont pas besoin. Exemples :

Type de workloadBesoin de token ?
Frontend statique (nginx, Caddy)❌ Non
Worker applicatif pur (calcul, ML)❌ Non
Job batch sans interaction API❌ Non
Application qui lit des ConfigMaps via API✅ Oui
Opérateur Kubernetes✅ Oui
Sidecar qui contacte l'API✅ Oui

Le champ automountServiceAccountToken: false supprime le montage pour ce Pod uniquement. Le répertoire /var/run/secrets/kubernetes.io/serviceaccount/ disparaît alors du conteneur : c'est le contrôle à faire pour valider la configuration.

pod-sans-token.yaml
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
serviceAccountName: frontend-sa
automountServiceAccountToken: false
containers:
- name: nginx
image: nginx:1.30@sha256:d5792f71a9496b833bc08ea834a758c46e2b6a6306c10f4be926f38a656cdc1c

Pour définir un comportement par défaut pour tous les Pods utilisant ce ServiceAccount :

sa-sans-automount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: frontend-sa
namespace: mon-app
automountServiceAccountToken: false

Quand les deux niveaux déclarent ce champ, c'est la valeur du Pod qui l'emporte. La combinaison la plus sûre en découle : désactiver le montage par défaut sur le ServiceAccount, et le réactiver explicitement sur les rares Pods qui appellent vraiment l'API.

Cette séquence assemble tout ce qui précède sur un cas réaliste : une application qui doit lire les Pods de son propre namespace. Les trois étapes se déroulent dans l'ordre, la vérification finale avec kubectl auth can-i étant la seule qui prouve réellement que le RBAC est correct. Testez toujours l'autorisation attendue et une opération qui doit échouer.

  1. Créez les ressources RBAC

    rbac-complet.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
    name: app-sa
    namespace: mon-app
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
    name: pod-reader
    namespace: mon-app
    rules:
    - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list", "watch"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
    name: read-pods
    namespace: mon-app
    subjects:
    - kind: ServiceAccount
    name: app-sa
    namespace: mon-app
    roleRef:
    kind: Role
    name: pod-reader
    apiGroup: rbac.authorization.k8s.io
    Fenêtre de terminal
    kubectl apply -f rbac-complet.yaml
  2. Déployez votre application

    deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: mon-app
    namespace: mon-app
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: mon-app
    template:
    metadata:
    labels:
    app: mon-app
    spec:
    serviceAccountName: app-sa
    containers:
    - name: app
    image: registry.k8s.io/kubectl:v1.37.0@sha256:5ed410ebac5dc976cc717098994dcdb29bbbd38f6bd65f582311f5be4ba719cf
    command: ["sleep", "3600"]
  3. Vérifiez les permissions

    Fenêtre de terminal
    # Ce que le ServiceAccount peut faire
    kubectl auth can-i list pods \
    --as=system:serviceaccount:mon-app:app-sa \
    -n mon-app
    # Résultat: yes
    # Ce qu'il ne peut PAS faire
    kubectl auth can-i delete pods \
    --as=system:serviceaccount:mon-app:app-sa \
    -n mon-app
    # Résultat: no

Ces trois blocs de règles couvrent la majorité des besoins rencontrés en développement. Ils sont classés du plus restreint au plus ciblé, et se copient tels quels dans un Role. Rappel de lecture : apiGroups: [""] désigne le groupe d'API core, celui des Pods, Services, ConfigMaps et Secrets.

Le trio get, list, watch correspond au besoin d'un client qui recharge sa configuration à chaud. Le verbe watch est indispensable dès que l'application écoute les changements : sans lui, elle retombe en interrogation périodique.

rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]

Un opérateur écrit vraiment dans le cluster, ses permissions sont donc bien plus larges. La seconde règle est facile à oublier et pourtant nécessaire : sans le droit de créer des events, l'opérateur fonctionne mais ne peut plus rendre compte de ses actions dans kubectl describe.

rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "patch"]

C'est la formulation à privilégier dès qu'il s'agit de Secrets : resourceNames restreint la règle à deux objets nommés, au lieu d'ouvrir la lecture de tous les Secrets du namespace. Le verbe get seul, sans list, empêche en plus d'énumérer ce qui existe.

rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["app-credentials", "db-password"]
verbs: ["get"]

Un détail de resourceNames mérite d'être connu avant de s'y fier. Il fonctionne bien avec get, update, patch et delete, qui désignent tous un objet précis. Avec list, la logique diffère : sans resourceNames, la règle liste tout ; avec, elle ne rend que les objets nommés. Un get seul, sans list, reste la formulation la plus stricte puisqu'elle empêche même d'énumérer ce qui existe.

Les recommandations se regroupent en trois temps : nommer et organiser les identités, restreindre ce qu'elles peuvent faire, puis vérifier dans la durée que ces droits restent justifiés. Le troisième volet est le plus négligé, alors que les permissions RBAC ne font que s'accumuler si personne ne les revoit.

Ces trois points se décident une fois pour toutes, au moment où la première identité est créée. L'annotation d'usage est celle qu'on saute le plus souvent : c'est pourtant elle qui permet, des mois plus tard, de savoir si un ServiceAccount sert encore à quelque chose avant de le supprimer.

  1. Un ServiceAccount par application : pas de partage entre applications différentes
  2. Convention de nommage, <app>-sa pour identifier facilement
  3. Documentation : annotez vos ServiceAccounts avec leur usage

Ces six règles appliquent le même principe : n'accorder que ce qui est démontré nécessaire. Le joker * dans les verbes mérite une vigilance particulière : il accorde silencieusement les nouveaux verbes introduits par les versions ultérieures de Kubernetes.

  1. Principe du moindre privilège : n'accordez que les permissions strictement nécessaires
  2. Évitez * dans les verbes, Listez explicitement les actions autorisées
  3. Utilisez resourceNames quand possible : limitez l'accès à des ressources spécifiques
  4. Préférez Role à ClusterRole : scope namespace sauf besoin cluster-wide
  5. Désactivez automount si inutile : réduisez la surface d'attaque
  6. Préférez les tokens projetés : évitez les tokens statiques en Secret

Les permissions sont accordées quand un besoin apparaît, presque jamais retirées quand il disparaît. Une revue périodique, appuyée sur kubectl auth can-i --list, est le seul moyen de repérer ces droits devenus orphelins.

  1. Revoyez régulièrement les permissions : les besoins évoluent
  2. Utilisez kubectl auth can-i : testez ce qu'un ServiceAccount peut faire
  3. Activez l'audit logging : tracez les actions sur l'API

Un message Forbidden indique toujours quel sujet, quel verbe et quelle ressource ont été refusés : lisez-le en entier avant de modifier quoi que ce soit. L'option --as=system:serviceaccount:<namespace>:<nom> rejoue ensuite la question à la place du ServiceAccount, sans déployer le moindre Pod. C'est l'outil de diagnostic principal, à condition de disposer vous-même du droit d'usurpation.

Fenêtre de terminal
# Lister toutes les permissions d'un ServiceAccount
kubectl auth can-i --list \
--as=system:serviceaccount:mon-app:app-sa \
-n mon-app
# Tester une permission spécifique
kubectl auth can-i create deployments \
--as=system:serviceaccount:mon-app:app-sa \
-n mon-app
# Voir les RoleBindings d'un namespace
kubectl get rolebindings -n mon-app -o wide
# Voir les ClusterRoleBindings qui concernent un ServiceAccount
kubectl get clusterrolebindings -o wide | grep app-sa
# Créer un token pour tester
kubectl create token app-sa -n mon-app

Un admission controller est un module de l'API server qui inspecte une ressource après l'autorisation RBAC, et peut la modifier ou la rejeter. C'est lui qui explique les refus les plus déroutants : vous avez le droit de créer un Pod, la requête est bien authentifiée et autorisée, et pourtant elle échoue. Savoir distinguer un refus RBAC d'un refus d'admission fait gagner beaucoup de temps de diagnostic.

Ce point relève explicitement du programme CKAD, qui demande de distinguer authentification, autorisation et contrôle d'admission. La confusion coûte cher en examen comme en production : RBAC peut parfaitement autoriser votre Pod, et un admission controller le refuser juste après.

Quand vous créez un Pod, la requête passe par 3 étapes :

Traitement d'une requête par l'API server en trois étapes successives : l'authentification identifie l'appelant par token ServiceAccount, certificat ou OIDC, l'autorisation vérifie le Role ou ClusterRole via RBAC, puis le contrôle d'admission applique webhooks de validation et de mutation, Pod Security Admission et quotas

Le vocabulaire de l'erreur permet de trancher sans réfléchir : Forbidden signale un refus RBAC, tandis qu'un message mentionnant un webhook, PodSecurity ou un quota signale un refus d'admission. Le tableau ci-dessous illustre les quatre cas les plus courants.

ProblèmeRBACAdmissionRésultat
Pas de Role pour créer des Podsnon atteintForbidden
Pod privilégié dans namespace restricted❌ PSARejected
ResourceQuota dépassé❌ QuotaRejected
Image non signée❌ PolicyRejected

PSA remplace les anciennes PodSecurityPolicies. Il applique les Pod Security Standards (PSS) au niveau namespace :

NiveauCe qui est autoriséCas d'usage
privilegedToutPods système, debug
baselinePas de privileges dangereuxApplications standards
restrictedConfiguration la plus sécuriséeProduction, multi-tenant
Fenêtre de terminal
# Vérifier le niveau PSA d'un namespace
kubectl get namespace mon-app -o yaml | grep pod-security

Si votre Pod est refusé avec une erreur mentionnant pod-security.kubernetes.io, c'est PSA qui bloque.

Le message de rejet remonte directement quand vous créez le Pod à la main. Créé par un Deployment ou un Job, le Pod n'existe jamais et l'erreur se lit alors dans les événements de l'objet parent, ce qui explique l'impression trompeuse d'un déploiement « bloqué sans raison ».

Fenêtre de terminal
# L'erreur apparaît dans le message de rejet
kubectl apply -f pod.yaml
# Error: admission webhook "validate.policy" denied the request...
# Ou via describe sur le parent (Deployment, Job...)
kubectl describe deployment mon-app -n mon-namespace
# Events:
# Warning FailedCreate ... violates PodSecurity "restricted:latest"

Ces quatre contrôleurs sont configurés par l'équipe plateforme, pas par vous. Votre marge d'action consiste à connaître les contraintes qu'ils imposent et à écrire des manifestes qui les respectent dès le départ, plutôt qu'à découvrir chaque règle par un rejet.

Admission ControllerCe qu'il vérifieComment s'adapter
PSAPrivileges, capabilities, volumesRespecter les Pod Security Standards
ResourceQuotaCPU/mémoire du namespaceVérifier les quotas disponibles
LimitRangeRequests/limits par PodDéfinir requests/limits conformes
ValidatingWebhookRègles custom (Kyverno, Gatekeeper)Consulter les policies actives

Trois réflexes quand un Pod est rejeté sans que RBAC soit en cause. Regardez les labels PSA du namespace avec kubectl get ns <ns> --show-labels, puis les ResourceQuotas avec kubectl describe quota -n <ns>, et demandez enfin à votre équipe plateforme la liste des policies actives, que rien ne permet de deviner depuis un manifeste.

ConceptUtilisation
ServiceAccountIdentité d'un workload dans Kubernetes
RolePermissions dans un namespace
ClusterRoleDéfinition de permissions réutilisable
RoleBindingAssocie un rôle à un sujet dans un namespace
ClusterRoleBindingAssocie un rôle à un sujet pour tout le cluster
serviceAccountNameSpécifie l'identité du Pod
automountServiceAccountTokenContrôle le montage du token
kubectl create tokenCrée un token ponctuel pour tests

Règle d'or : Le ServiceAccount est une identité, les permissions viennent de RBAC, et le token ne doit être monté que lorsqu'il y a un vrai besoin.

Ce quiz reprend les distinctions qui posent le plus de difficultés : identité contre permissions, ClusterRole contre ClusterRoleBinding, et les conditions dans lesquelles un token doit être monté.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

7 questions
5 min.
80% requis

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

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