
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=24hÉ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-appÀ 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.