Aller au contenu
Conteneurs & Orchestration medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

ServiceAccounts pour développeurs

16 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é
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 forcément 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

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

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

RBAC (Role-Based Access Control) définit ce que le ServiceAccount peut faire.

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

Pour un accès global (monitoring, opérateur, controller manager), utilisez ClusterRoleBinding :

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

Spécifiez le ServiceAccount dans le spec du Pod :

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

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)

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

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

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
pod-sans-token.yaml
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
serviceAccountName: frontend-sa
automountServiceAccountToken: false
containers:
- name: nginx
image: nginx:1.25.4

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
  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: bitnami/kubectl:1.29.0
    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
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "patch"]
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["app-credentials", "db-password"]
verbs: ["get"]
  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
  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
  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
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
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 site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn