Introduction
L'automatisation CI/CD des comptes de service Kubernetes transforme la gestion manuelle des identités en un pipeline reproductible, mais un pipeline qui applique du YAML sans vérification n'est qu'un script. Ce guide offre aux développeurs, consultants DevOps et équipes plateforme de startups un chemin pratique allant de l'observation de l'état initial au changement vérifié pour les comptes de service, leurs rôles, liaisons et la gestion des jetons.
Nous nous concentrons sur la boucle opérationnelle quotidienne : inspecter l'état actuel, appliquer le plus petit changement justifié, vérifier le résultat et savoir comment récupérer. Vous trouverez des commandes kubectl concrètes, des vérifications adaptées aux versions et des exemples de manifestes pour chaque étape. Les exemples supposent un cluster Kubernetes fonctionnel (v1.24 ou ultérieure) et un namespace nommé payments, sauf indication contraire. L'objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des espaces réservés plutôt que des secrets, vérifier le résultat et documenter la récupération avant qu'un incident ne force la décision.
Inventaire des versions et de l'environnement
Avant de toucher aux comptes de service, enregistrez les versions du plan de contrôle et des API du cluster. De nombreux échecs CI/CD surviennent parce que le client kubectl local, l'API du cluster ou l'apiVersion d'un manifeste ne concordent pas. Commencez par des commandes en lecture seule et capturez la sortie avec des horodatages.
Vérifier la version du cluster et du client
Exécutez kubectl version --short (ou kubectl version sur les clients récents) pour voir les versions du client et du serveur. Par exemple :
$ kubectl version --short
Client Version: v1.28.2
Server Version: v1.28.1
Si votre pipeline cible un cluster avec une version d'API plus ancienne, le manifeste échouera. Les comptes de service, rôles et liaisons de rôles sont des objets stables v1. Mais les API de demande de jetons diffèrent : l'API TokenRequest est disponible depuis la v1.20, et les jetons de compte de service hérités basés sur Secret ne sont plus créés automatiquement depuis la v1.24. Utilisez kubectl api-versions | grep authentication pour confirmer les API liées aux jetons.
Inspecter les comptes de service existants et leurs dépendances
Listez les comptes de service dans le namespace cible :
kubectl get serviceaccounts -n payments
Sortie attendue si seul le compte par défaut existe :
NAME SECRETS AGE
default 0 45d
Si un pipeline CI/CD attend un compte de service spécifique, confirmez son existence avec kubectl get serviceaccount ci-deployer -n payments -o yaml. Le YAML montrera ses annotations, les secrets d'extraction d'images et tout jeton généré automatiquement. Enregistrez les objets RBAC associés : les rôles (kubectl get roles -n payments), les liaisons de rôles (kubectl get rolebindings -n payments) et les secrets si vous montez encore des jetons hérités (kubectl get secrets -n payments | grep ci-deployer).
Exemple de capture de l'état initial
Enregistrez une capture de la configuration d'identité actuelle avant tout changement. C'est votre référence de récupération :
mkdir -p /tmp/sa-baseline && cd /tmp/sa-baseline
kubectl get serviceaccount ci-deployer -n payments -o yaml > sa-before.yaml
kubectl get role ci-deployer-role -n payments -o yaml > role-before.yaml
kubectl get rolebinding ci-deployer-binding -n payments -o yaml > binding-before.yaml
Utilisez des horodatages dans les noms de fichiers ou un commit git pour figer l'état initial. Si le changement échoue, kubectl apply -f sa-before.yaml restaure le compte de service précédent. Le chemin de récupération est clair avant de modifier quoi que ce soit.
Chemin de configuration sûre
Les comptes de service sont inoffensifs sans rôles ni liaisons, mais une liaison mal configurée peut accorder un accès non intentionnel à un pod. Le chemin sûr consiste à créer ou mettre à jour un objet à la fois, à vérifier son effet, puis à passer à l'étape suivante. Cette section couvre la séquence recommandée pour un compte de service CI/CD typique.
Étape 1 : Définir le compte de service avec des métadonnées minimales
Créez un compte de service pour un pipeline de déploiement qui déploiera des applications dans le namespace payments. Appliquez ce YAML :
# sa-ci-deployer.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: ci-deployer
namespace: payments
labels:
app.kubernetes.io/name: payments
app.kubernetes.io/component: deployer
Appliquez et vérifiez le résultat :
kubectl apply -f sa-ci-deployer.yaml
kubectl get serviceaccount ci-deployer -n payments -o wide
Sortie attendue sans secrets (depuis la v1.24) :
NAME SECRETS AGE
ci-deployer 0 2m
Ne définissez pas automountServiceAccountToken: false à moins d'être absolument certain que la charge de travail n'a jamais besoin de s'authentifier auprès de l'API Kubernetes. Pour les tâches CI/CD, le jeton est généralement requis, laissez donc la valeur par défaut true.
Étape 2 : Créer un rôle avec le moindre privilège
Définissez un rôle qui permet au système CI/CD de gérer uniquement les déploiements, services et configmaps dans payments. C'est un rôle limité, pas à l'échelle du cluster. Appliquez ce YAML :
# role-ci-deployer.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ci-deployer-role
namespace: payments
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["services", "configmaps"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
Appliquez et inspectez le rôle :
kubectl apply -f role-ci-deployer.yaml
kubectl describe role ci-deployer-role -n payments
La sortie attendue inclut chaque règle avec les ressources et les verbes. Si vous devez autoriser le pipeline à mettre à l'échelle des déploiements, ajoutez "scale" aux verbes pour deployments/scale sous apps.
Étape 3 : Lier le rôle au compte de service
Un rôle est inerte tant qu'il n'est pas lié. Utilisez une RoleBinding pour connecter le compte de service au rôle dans le même namespace :
# rolebinding-ci-deployer.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ci-deployer-binding
namespace: payments
subjects:
- kind: ServiceAccount
name: ci-deployer
namespace: payments
roleRef:
kind: Role
name: ci-deployer-role
apiGroup: rbac.authorization.k8s.io
Appliquez la liaison :
kubectl apply -f rolebinding-ci-deployer.yaml
kubectl get rolebinding ci-deployer-binding -n payments -o wide
Vérifiez que le sujet est correct :
kubectl describe rolebinding ci-deployer-binding -n payments
Recherchez une ligne similaire à :
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount ci-deployer payments
Si le sujet montre un namespace ou un type différent, la liaison n'accordera pas les permissions. Corrigez avant de continuer.
Vérification et diagnostics
Après avoir appliqué le rôle et la liaison, vous devez prouver que le compte de service possède réellement les permissions prévues et qu'un pod l'utilisant peut effectuer les actions autorisées. Ne supposez pas le succès à partir de la sortie de kubectl apply.
Vérifier les permissions avec kubectl auth can-i
Utilisez kubectl auth can-i avec --as pour simuler le compte de service. Par exemple, vérifiez si le compte CI/CD peut créer des déploiements dans payments :
kubectl auth can-i create deployments --as=system:serviceaccount:payments:ci-deployer -n payments
Résultat attendu si le rôle est correct :
yes
Vérifiez une action interdite, comme la suppression d'un secret :
kubectl auth can-i delete secrets --as=system:serviceaccount:payments:ci-deployer -n payments
Résultat attendu :
no
Si vous obtenez yes pour une action non intentionnelle, passez en revue les règles du rôle et les éventuels rôles de cluster liés à ce compte de service.
Vérifier qu'un pod peut utiliser le jeton du compte de service
Créez un pod temporaire qui utilise le compte de service et tente un appel à l'API Kubernetes. Enregistrez le fichier suivant sous pod-test-sa.yaml :
apiVersion: v1
kind: Pod
metadata:
name: sa-token-test
namespace: payments
spec:
serviceAccountName: ci-deployer
containers:
- name: kubectl
image: bitnami/kubectl:latest
command: ["sleep", "3600"]
restartPolicy: Never
Lancez le pod, exécutez une commande à l'intérieur et inspectez le jeton monté :
kubectl apply -f pod-test-sa.yaml
kubectl wait --for=condition=Ready pod/sa-token-test -n payments --timeout=60s
kubectl exec -it sa-token-test -n payments -- sh
# dans le conteneur
cat /var/run/secrets/kubernetes.io/serviceaccount/token
Le jeton doit être une longue chaîne JWT. Tentez un appel à l'API :
kubectl exec -it sa-token-test -n payments -- sh -c 'kubectl auth can-i list deployments -n payments --token=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)'
Sortie attendue : yes. Un no peut indiquer que le jeton du compte de service n'est pas projeté ou que le rôle ne possède pas la permission.
Déboguer les problèmes courants
- Le pod ne peut pas lister les déploiements mais
kubectl auth can-irenvoie oui : Le compte de service du pod n'est peut-être pas correctement spécifié dans la spécification du pod. Vérifiez aveckubectl get pod sa-token-test -n payments -o jsonpath='{.spec.serviceAccountName}'pour confirmer qu'il correspond. - Jeton expiré ou vide : Depuis la v1.24, les comptes de service ne créent plus de secrets à longue durée de vie par défaut. Le jeton projeté est à courte durée de vie et automatiquement renouvelé. Pour le CI/CD, utilisez une spécification de pod qui demande un jeton avec une expiration plus longue via
automountServiceAccountTokenou utilisez l'API TokenRequest. Vous pouvez aussi créer manuellement un secret de typekubernetes.io/service-account-token, mais préférez le jeton projeté. - Refus RBAC dans les journaux du cluster : Activez temporairement la journalisation d'audit pour voir pourquoi une requête a été refusée. Pour un cluster EKS, vous pouvez utiliser CloudTrail. Pour un cluster auto-géré, consultez les journaux d'audit de
kube-apiserver. Une requête refusée typique montrera l'utilisateur commesystem:serviceaccount:payments:ci-deployeret le verbe/ressource manquant.
Modes de défaillance et récupération
Même avec un YAML correct, l'automatisation CI/CD peut échouer en raison de l'absence du namespace, d'une mauvaise configuration de la liaison ou de problèmes de jetons. Cette section décrit les modes de défaillance courants, comment les détecter et les étapes exactes de récupération.
Défaillance 1 : Le namespace n'existe pas
Si le pipeline applique un manifeste avec namespace: payments mais que le namespace n'a jamais été créé, kubectl renvoie une erreur du type :
Error from server (NotFound): namespaces "payments" not found
Détection : Le job CI/CD échoue immédiatement à l'application. Dans un système GitOps comme Argo CD, le statut de synchronisation indique Unknown ou Missing pour le namespace.
Récupération : Créez le namespace et réappliquez les manifestes :
kubectl create namespace payments
kubectl apply -f sa-ci-deployer.yaml -f role-ci-deployer.yaml -f rolebinding-ci-deployer.yaml
Prévenez ce problème en ajoutant une étape de création du namespace au début du pipeline ou en utilisant un manifeste à l'échelle du cluster qui inclut le namespace.
Défaillance 2 : La liaison de rôle pointe vers un autre compte de service
Une erreur courante consiste à lier un rôle au mauvais sujet. Par exemple, le sujet de la liaison pourrait avoir name: default au lieu de ci-deployer. Le pod démarrera sans erreur mais tout appel API nécessitant des permissions échouera avec 403 Forbidden.
Détection : Exécutez kubectl auth can-i pour le compte de service prévu (comme indiqué dans la section Vérification et diagnostics) et vérifiez le sujet de la liaison avec kubectl get rolebinding ci-deployer-binding -n payments -o yaml. Regardez le tableau subjects.
Récupération : Corrigez le sujet dans le YAML de la RoleBinding et réappliquez :
subjects:
- kind: ServiceAccount
name: ci-deployer # corrigé de default
namespace: payments
Puis réappliquez :
kubectl apply -f rolebinding-ci-deployer.yaml
Vérifiez à nouveau avec kubectl auth can-i.
Défaillance 3 : Jeton secret hérité manquant après une mise à niveau du cluster
Si vous avez effectué une mise à niveau de Kubernetes v1.23 vers v1.24 ou ultérieure, les comptes de service existants peuvent perdre leurs secrets créés automatiquement. Un pipeline qui référence un secret par nom pour un jeton de compte de service échouera à le trouver.
Détection : Les journaux du pipeline affichent une erreur comme Secret "ci-deployer-token-abcde" not found. kubectl get serviceaccount ci-deployer -n payments -o yaml ne liste plus le secret sous secrets.
Récupération : Utilisez le jeton projeté à la place. Si vous avez absolument besoin d'un jeton à longue durée de vie, créez un secret manuellement et liez-le au compte de service :
# sa-token-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: ci-deployer-token
namespace: payments
annotations:
kubernetes.io/service-account.name: ci-deployer
type: kubernetes.io/service-account-token
Puis patchez le compte de service pour inclure le secret :
kubectl apply -f sa-token-secret.yaml
kubectl patch serviceaccount ci-deployer -n payments -p '{"secrets": [{"name": "ci-deployer-token"}]}'
Cependant, cette approche comporte des risques de sécurité et est déconseillée. Préférez mettre à jour le système CI/CD pour s'authentifier via le jeton projeté ou utiliser un jeton à courte durée de vie obtenu à partir de l'API TokenRequest.
Stratégie de retour en arrière
Parce que vous avez enregistré les fichiers YAML de l'état initial au début, le retour en arrière est un simple kubectl apply de l'état précédent. Par exemple, pour annuler un changement de rôle :
kubectl apply -f /tmp/sa-baseline/role-before.yaml
Si le changement a été appliqué via un pipeline, utilisez la fonction de retour en arrière du pipeline ou un commit git de réversion. Réexécutez toujours l'étape de vérification après le retour en arrière pour confirmer que les permissions précédentes sont restaurées.
Liste de contrôle des opérations
Utilisez cette liste de contrôle avant, pendant et après tout changement de compte de service en CI/CD. Elle est conçue pour être collée dans un runbook ou un modèle de ticket et remplie avec des valeurs concrètes.
Liste de contrôle avant changement
kubectl get serviceaccount ci-deployer -n payments -o yaml > /tmp/sa-baseline/sa-before.yaml kubectl get role ci-deployer-role -n payments -o yaml > /tmp/sa-baseline/role-before.yaml kubectl get rolebinding ci-deployer-binding -n payments -o yaml > /tmp/sa-baseline/binding-before.yaml
- [ ] Confirmer la version du cluster avec
kubectl version --shortet noter toute différence d'API. - [ ] Vérifier que le namespace cible existe :
kubectl get namespace payments. - [ ] Lister les comptes de service et objets RBAC actuels dans le namespace :
kubectl get sa,role,rolebinding -n payments. - [ ] Enregistrer le YAML de l'état initial pour les objets spécifiques que vous allez modifier :
- [ ] Confirmer que le changement est limité à un seul namespace ou ensemble d'objets.
- [ ] Noter la procédure de récupération : restaurer le YAML de l'état initial.
Liste de contrôle d'exécution du changement
- [ ] Appliquer le manifeste du compte de service :
kubectl apply -f sa-ci-deployer.yaml - [ ] Vérifier que le compte de service est créé :
kubectl get serviceaccount ci-deployer -n payments - [ ] Appliquer le manifeste du rôle :
kubectl apply -f role-ci-deployer.yaml - [ ] Vérifier les règles du rôle :
kubectl describe role ci-deployer-role -n payments - [ ] Appliquer la liaison de rôle :
kubectl apply -f rolebinding-ci-deployer.yaml - [ ] Vérifier le sujet de la liaison :
kubectl get rolebinding ci-deployer-binding -n payments -o yaml - [ ] Tester les permissions avec
kubectl auth can-ipour au moins une action autorisée et une action refusée. - [ ] (Optionnel) Lancer un pod temporaire utilisant le compte de service pour tester l'accès basé sur le jeton.
Liste de contrôle de vérification après changement
- [ ] Confirmer que les résultats de
kubectl auth can-icorrespondent aux attentes pour toutes les actions clés. - [ ] Vérifier qu'aucune permission à l'échelle du cluster non intentionnelle n'a été accordée (
kubectl get clusterrolebinding -o yaml | grep ci-deployerne doit rien renvoyer). - [ ] Mettre à jour la documentation avec le nouveau nom du compte de service, les permissions et un exemple d'utilisation.
- [ ] Étiqueter le changement dans git pour l'auditabilité.
- [ ] Si le changement fait partie d'un pipeline CI/CD, exécuter l'étape de vérification propre au pipeline (par exemple, un déploiement de test utilisant le compte de service).
Exemple de liste de contrôle remplie pour une mise à niveau de pipeline de déploiement
Voici un exemple de liste de contrôle complétée pour un changement spécifique : création d'un nouveau compte de service ci-deployer pour le pipeline de déploiement du backend des paiements.
| Élément | Vérification | Sortie ou note |
|---|---|---|
| Version du cluster | kubectl version --short | v1.28.1 |
| Le namespace existe | kubectl get namespace payments | Actif |
| État initial enregistré | commit git 4f2a1c | Fichiers dans /tmp/sa-baseline |
| SA appliqué | kubectl apply -f sa-ci-deployer.yaml | serviceaccount/ci-deployer created |
| Rôle appliqué | kubectl apply -f role-ci-deployer.yaml | role.rbac.authorization.k8s.io/ci-deployer-role created |
| Liaison appliquée | kubectl apply -f rolebinding-ci-deployer.yaml | rolebinding.rbac.authorization.k8s.io/ci-deployer-binding created |
| Action autorisée | kubectl auth can-i create deployments --as=... -n payments | yes |
| Action refusée | kubectl auth can-i delete secrets --as=... -n payments | no |
| Test de fumée du pipeline | Exécuter le job de déploiement | Déploiement réussi |
Conclusion
L'automatisation CI/CD des comptes de service Kubernetes n'a de valeur que si chaque étape est liée à une version, observable et réversible. Copier une commande sans vérifier les prérequis et la sortie attendue n'est pas une procédure d'exploitation ; c'est un pari.
Commencez par une vérification à faible risque : choisissez un compte de service, enregistrez son état actuel avec les commandes de base, exécutez les vérifications documentées, comparez le résultat avec le signal attendu et passez en revue les dépendances telles que les rôles, les liaisons de rôles et les secrets.
Un flux de travail technique fiable rend la défaillance visible, protège les valeurs sensibles, limite les changements à la ressource prévue et définit la vérification de récupération avant qu'un incident ne force la décision. Utilisez la liste de contrôle de ce guide comme un document vivant : ajustez-la à mesure que votre cluster évolue et que votre pipeline CI/CD mûrit.
Votre prochaine étape consiste à tester ce processus dans un namespace de développement. Créez un compte de service de test, liez un rôle minimal, exécutez les commandes de vérification et cassez intentionnellement une liaison pour vous entraîner à la récupération. Une fois que la boucle vous semble naturelle, appliquez la même rigueur aux changements de production.