
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.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- 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é
Tableau de décision rapide
Section intitulée « Tableau de décision rapide »| Besoin | Outil recommandé |
|---|---|
| Pod lit des ressources dans son namespace | Role + RoleBinding |
| Même permission réutilisée dans plusieurs namespaces | ClusterRole + RoleBinding (par namespace) |
| Accès réellement global au cluster | ClusterRole + ClusterRoleBinding |
| Pod n'appelle jamais l'API Kubernetes | automountServiceAccountToken: false |
| Test ponctuel d'un token | kubectl create token |
Pourquoi des ServiceAccounts dédiés ?
Section intitulée « Pourquoi des ServiceAccounts dédiés ? »Par défaut, un Pod utilise le ServiceAccount default du namespace. Ce n'est pas forcément dangereux en soi, mais c'est rarement un bon choix pour une application de production :
| Problème | Conséquence |
|---|---|
| Identité partagée | Plusieurs workloads apparaissent sous la même identité vis-à-vis de l'API |
| Traçabilité réduite | La corrélation d'audit devient moins fine |
| Permissions héritées | Tout RoleBinding sur default s'applique à tous les Pods |
Solution : Un ServiceAccount par application (ou groupe d'applications avec le même besoin).
Créer un ServiceAccount
Section intitulée « Créer un ServiceAccount »apiVersion: v1kind: ServiceAccountmetadata: name: app-sa namespace: mon-appOu en une ligne :
kubectl create serviceaccount app-sa -n mon-appConfigurer RBAC
Section intitulée « Configurer RBAC »RBAC (Role-Based Access Control) définit ce que le ServiceAccount peut faire.
Concepts RBAC
Section intitulée « Concepts RBAC »| Ressource | Portée | Description |
|---|---|---|
| Role | Namespace | Permissions dans un namespace |
| ClusterRole | Cluster | Définition de permissions réutilisable |
| RoleBinding | Namespace | Associe Role ou ClusterRole à un sujet dans un namespace |
| ClusterRoleBinding | Cluster | Associe ClusterRole à un sujet pour tout le cluster |
Créer un Role
Section intitulée « Créer un Role »Un Role liste les permissions accordées dans un namespace :
apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata: name: pod-reader namespace: mon-apprules:- apiGroups: [""] # "" = core API group resources: ["pods"] verbs: ["get", "list", "watch"]- apiGroups: [""] resources: ["pods/log"] verbs: ["get"]Les verbes disponibles :
| Verbe | Action |
|---|---|
| get | Lire une ressource |
| list | Lister les ressources |
| watch | Observer les changements |
| create | Créer une ressource |
| update | Modifier une ressource |
| patch | Modifier partiellement |
| delete | Supprimer une ressource |
Créer un RoleBinding
Section intitulée « Créer un RoleBinding »Le RoleBinding connecte le Role au ServiceAccount :
apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata: name: read-pods namespace: mon-appsubjects:- kind: ServiceAccount name: app-sa namespace: mon-approleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.ioRé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.
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: configmap-readerrules:- apiGroups: [""] resources: ["configmaps"] verbs: ["get", "list", "watch"]Puis, dans chaque namespace où c'est nécessaire :
apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata: name: app-configmap-reader namespace: namespace-asubjects:- kind: ServiceAccount name: app-sa namespace: namespace-aroleRef: kind: ClusterRole # Référence le ClusterRole name: configmap-reader apiGroup: rbac.authorization.k8s.ioPermissions vraiment cluster-wide
Section intitulée « Permissions vraiment cluster-wide »Pour un accès global (monitoring, opérateur, controller manager), utilisez ClusterRoleBinding :
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: namespace-readerrules:- apiGroups: [""] resources: ["namespaces"] verbs: ["get", "list"]---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: app-namespace-readersubjects:- kind: ServiceAccount name: app-sa namespace: mon-approleRef: kind: ClusterRole name: namespace-reader apiGroup: rbac.authorization.k8s.ioAssocier à un Pod
Section intitulée « Associer à un Pod »Spécifiez le ServiceAccount dans le spec du Pod :
apiVersion: v1kind: Podmetadata: name: mon-pod namespace: mon-appspec: serviceAccountName: app-sa containers: - name: app image: mon-image:1.0.0Pour un Deployment :
apiVersion: apps/v1kind: Deploymentmetadata: name: mon-appspec: replicas: 3 template: spec: serviceAccountName: app-sa containers: - name: app image: mon-image:1.0.0Tokens : comprendre le mécanisme moderne
Section intitulée « Tokens : comprendre le mécanisme moderne »Tokens projetés (bound service account tokens)
Section intitulée « Tokens projetés (bound service account tokens) »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)Créer un token manuellement
Section intitulée « Créer un token manuellement »Pour tester une identité ou intégrer un composant externe :
# Token avec durée par défaut (1h)kubectl create token app-sa -n mon-app
# Token avec durée personnaliséekubectl create token app-sa -n mon-app --duration=24hLa 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é :
kubectl create token app-sa -n mon-app | cut -d. -f1 | base64 -d# {"alg":"RS256","kid":"LxkUHA9ITF5w3mg80D102dT48j1E4k1DsNIgUcHOrRg"}Le payload (deuxième segment) contient les claims standard : aud
(audience), exp (expiration), iss (issuer), sub (sujet) et un bloc
kubernetes.io qui rattache le token au namespace et au ServiceAccount.
Signature externe via KMS (GA en Kubernetes 1.36)
Section intitulée « Signature externe via KMS (GA en Kubernetes 1.36) »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 (KEP-5066) : 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.
Architecture
Section intitulée « Architecture »┌──────────────────────────┐ ┌─────────────────────┐│ kube-apiserver │ signer │ Service de signature││ --service-account- │ ───────►│ (Vault, KMS, …) ││ signing-endpoint=... │ via │ ││ │ UDS │ clé privée jamais ││ │ ◄───────│ exposée au control│└──────────────────────────┘ token │ plane │ signé └─────────────────────┘Configurer l'API server
Section intitulée « Configurer l'API server »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: DirectoryLe 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.
Compatibilité avec les tokens existants
Section intitulée « Compatibilité avec les tokens existants »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.
Éviter les anciens tokens en Secret
Section intitulée « Éviter les anciens tokens en Secret »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
apiVersion: v1kind: Secretmetadata: name: app-sa-token annotations: kubernetes.io/service-account.name: app-satype: kubernetes.io/service-account-tokenDésactiver le montage de token
Section intitulée « Désactiver le montage de token »Quand désactiver ?
Section intitulée « Quand désactiver ? »La checklist sécurité Kubernetes recommande de ne pas monter de token dans les Pods qui n'en ont pas besoin. Exemples :
| Type de workload | Besoin 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 |
Désactiver au niveau Pod
Section intitulée « Désactiver au niveau Pod »apiVersion: v1kind: Podmetadata: name: frontendspec: serviceAccountName: frontend-sa automountServiceAccountToken: false containers: - name: nginx image: nginx:1.25.4Désactiver au niveau ServiceAccount
Section intitulée « Désactiver au niveau ServiceAccount »Pour définir un comportement par défaut pour tous les Pods utilisant ce ServiceAccount :
apiVersion: v1kind: ServiceAccountmetadata: name: frontend-sa namespace: mon-appautomountServiceAccountToken: falseExemple complet
Section intitulée « Exemple complet »-
Créez les ressources RBAC
rbac-complet.yaml apiVersion: v1kind: ServiceAccountmetadata:name: app-sanamespace: mon-app---apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata:name: pod-readernamespace: mon-apprules:- apiGroups: [""]resources: ["pods"]verbs: ["get", "list", "watch"]---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: read-podsnamespace: mon-appsubjects:- kind: ServiceAccountname: app-sanamespace: mon-approleRef:kind: Rolename: pod-readerapiGroup: rbac.authorization.k8s.ioFenêtre de terminal kubectl apply -f rbac-complet.yaml -
Déployez votre application
deployment.yaml apiVersion: apps/v1kind: Deploymentmetadata:name: mon-appnamespace: mon-appspec:replicas: 1selector:matchLabels:app: mon-apptemplate:metadata:labels:app: mon-appspec:serviceAccountName: app-sacontainers:- name: appimage: bitnami/kubectl:1.29.0command: ["sleep", "3600"] -
Vérifiez les permissions
Fenêtre de terminal # Ce que le ServiceAccount peut fairekubectl auth can-i list pods \--as=system:serviceaccount:mon-app:app-sa \-n mon-app# Résultat: yes# Ce qu'il ne peut PAS fairekubectl auth can-i delete pods \--as=system:serviceaccount:mon-app:app-sa \-n mon-app# Résultat: no
Cas d'usage courants
Section intitulée « Cas d'usage courants »Application qui lit des ConfigMaps
Section intitulée « Application qui lit des ConfigMaps »rules:- apiGroups: [""] resources: ["configmaps"] verbs: ["get", "list", "watch"]Opérateur qui gère des Deployments
Section intitulée « Opérateur qui gère des Deployments »rules:- apiGroups: ["apps"] resources: ["deployments"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]- apiGroups: [""] resources: ["events"] verbs: ["create", "patch"]Accès à des Secrets spécifiques uniquement
Section intitulée « Accès à des Secrets spécifiques uniquement »rules:- apiGroups: [""] resources: ["secrets"] resourceNames: ["app-credentials", "db-password"] verbs: ["get"]Bonnes pratiques
Section intitulée « Bonnes pratiques »Organisation
Section intitulée « Organisation »- Un ServiceAccount par application — Pas de partage entre applications différentes
- Convention de nommage —
<app>-sapour identifier facilement - Documentation — Annotez vos ServiceAccounts avec leur usage
Sécurité
Section intitulée « Sécurité »- Principe du moindre privilège — N'accordez que les permissions strictement nécessaires
- Évitez
*dans les verbes — Listez explicitement les actions autorisées - Utilisez resourceNames quand possible — Limitez l'accès à des ressources spécifiques
- Préférez Role à ClusterRole — Scope namespace sauf besoin cluster-wide
- Désactivez automount si inutile — Réduisez la surface d'attaque
- Préférez les tokens projetés — Évitez les tokens statiques en Secret
- Revoyez régulièrement les permissions — Les besoins évoluent
- Utilisez
kubectl auth can-i— Testez ce qu'un ServiceAccount peut faire - Activez l'audit logging — Tracez les actions sur l'API
Débugger RBAC
Section intitulée « Débugger RBAC »# Lister toutes les permissions d'un ServiceAccountkubectl auth can-i --list \ --as=system:serviceaccount:mon-app:app-sa \ -n mon-app
# Tester une permission spécifiquekubectl auth can-i create deployments \ --as=system:serviceaccount:mon-app:app-sa \ -n mon-app
# Voir les RoleBindings d'un namespacekubectl get rolebindings -n mon-app -o wide
# Voir les ClusterRoleBindings qui concernent un ServiceAccountkubectl get clusterrolebindings -o wide | grep app-sa
# Créer un token pour testerkubectl create token app-sa -n mon-appComprendre les Admission Controllers
Section intitulée « Comprendre les Admission Controllers »Le flux complet d'une requête API
Section intitulée « Le flux complet d'une requête API »Quand vous créez un Pod, la requête passe par 3 étapes :
┌──────────────────────────────────────────────────────────────────┐│ API Server Request Flow │├──────────────────────────────────────────────────────────────────┤│ 1. AUTHENTICATION : Qui êtes-vous ? ││ → Token ServiceAccount, certificat, OIDC... ││ ││ 2. AUTHORIZATION : Avez-vous le droit (RBAC) ? ││ → Role/ClusterRole vérifié ││ ││ 3. ADMISSION CONTROL : La ressource est-elle conforme ? ││ → Validating/Mutating webhooks, PSA, quotas... │└──────────────────────────────────────────────────────────────────┘Pourquoi RBAC OK ≠ Pod créé
Section intitulée « Pourquoi RBAC OK ≠ Pod créé »| Problème | RBAC | Admission | Résultat |
|---|---|---|---|
| Pas de Role pour créer des Pods | ❌ | — | Forbidden |
| Pod privilégié dans namespace restricted | ✅ | ❌ PSA | Rejected |
| ResourceQuota dépassé | ✅ | ❌ Quota | Rejected |
| Image non signée | ✅ | ❌ Policy | Rejected |
Pod Security Admission (PSA)
Section intitulée « Pod Security Admission (PSA) »PSA remplace les anciennes PodSecurityPolicies. Il applique les Pod Security Standards (PSS) au niveau namespace :
| Niveau | Ce qui est autorisé | Cas d'usage |
|---|---|---|
privileged | Tout | Pods système, debug |
baseline | Pas de privileges dangereux | Applications standards |
restricted | Configuration la plus sécurisée | Production, multi-tenant |
# Vérifier le niveau PSA d'un namespacekubectl get namespace mon-app -o yaml | grep pod-securitySi votre Pod est refusé avec une erreur mentionnant pod-security.kubernetes.io, c'est PSA qui bloque.
Diagnostiquer un refus Admission
Section intitulée « Diagnostiquer un refus Admission »# L'erreur apparaît dans le message de rejetkubectl 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"Ce que le développeur doit savoir
Section intitulée « Ce que le développeur doit savoir »| Admission Controller | Ce qu'il vérifie | Comment s'adapter |
|---|---|---|
| PSA | Privileges, capabilities, volumes | Respecter les Pod Security Standards |
| ResourceQuota | CPU/mémoire du namespace | Vérifier les quotas disponibles |
| LimitRange | Requests/limits par Pod | Définir requests/limits conformes |
| ValidatingWebhook | Règles custom (Kyverno, Gatekeeper) | Consulter les policies actives |
À retenir
Section intitulée « À retenir »| Concept | Utilisation |
|---|---|
| ServiceAccount | Identité d'un workload dans Kubernetes |
| Role | Permissions dans un namespace |
| ClusterRole | Définition de permissions réutilisable |
| RoleBinding | Associe un rôle à un sujet dans un namespace |
| ClusterRoleBinding | Associe un rôle à un sujet pour tout le cluster |
serviceAccountName | Spécifie l'identité du Pod |
automountServiceAccountToken | Contrôle le montage du token |
kubectl create token | Cré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.
Testez vos connaissances
Section intitulée « Testez vos connaissances »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