## 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-i renvoie oui : Le compte de service du pod n'est peut-être pas correctement spécifié dans la spécification du pod. Vérifiez avec kubectl 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 automountServiceAccountToken ou utilisez l'API TokenRequest. Vous pouvez aussi créer manuellement un secret de type kubernetes.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 comme system:serviceaccount:payments:ci-deployer et 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 --short et 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-i pour 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-i correspondent 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-deployer ne 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 |