Un pod a besoin d'accéder à une API GCP — Cloud Storage, Pub/Sub, Secret Manager. Historiquement, la réponse était simple : exporter une clé JSON de service account, la monter comme Secret Kubernetes, et laisser le pod s'authentifier avec. Cette réponse est aussi le problème.
Le problème des clés de service account statiques
Une clé JSON exportée n'est pas une preuve d'identité liée au pod — c'est un fichier.
Un fichier que n'importe qui disposant d'un accès kubectl peut lire
(kubectl get secret -o yaml suffit), copier, et réutiliser depuis n'importe
où : un poste local, un autre cluster, une machine hors du périmètre GCP.
Pire, ces clés sont statiques et longue durée. Elles restent valides jusqu'à révocation manuelle, sans lien avec le cycle de vie du pod qui les utilise. Un pod supprimé depuis des mois peut avoir laissé une clé toujours active quelque part.
Workload Identity : lier une identité Kubernetes à une identité GCP
Workload Identity supprime le fichier de l'équation. Au lieu de distribuer une clé, il crée un lien IAM direct entre un Kubernetes Service Account (KSA) et un Google Service Account (GSA). Le pod s'authentifie avec son KSA ; GKE échange cette identité contre un jeton GCP de courte durée, émis dynamiquement via le metadata server du nœud — jamais stocké sur disque, jamais exporté.
Configuration en 5 étapes
1. Activer Workload Identity sur le cluster, avec le pool au format PROJECT_ID.svc.id.goog :
gcloud container clusters update my-cluster \
--workload-pool=my-gcp-project.svc.id.goog
2. Créer le Google Service Account (GSA) avec les rôles IAM nécessaires :
gcloud iam service-accounts create orders-gsa \
--display-name="Orders Service Account"
3. Créer le binding IAM reliant le KSA au GSA via roles/iam.workloadIdentityUser :
gcloud iam service-accounts add-iam-policy-binding \
orders-gsa@my-gcp-project.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:my-gcp-project.svc.id.goog[production/orders-ksa]"
4. Annoter le Kubernetes Service Account avec la référence au GSA :
kubectl annotate serviceaccount orders-ksa \
-n production \
iam.gke.io/gcp-service-account=orders-gsa@my-gcp-project.iam.gserviceaccount.com
5. Déployer le pod avec ce KSA — aucun Secret, aucune clé montée :
apiVersion: v1
kind: ServiceAccount
metadata:
name: orders-ksa
namespace: production
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders-processor
namespace: production
spec:
template:
spec:
serviceAccountName: orders-ksa
containers:
- name: orders-processor
image: gcr.io/my-gcp-project/orders-processor:latest
Le détail de sécurité qui change tout
Le binding IAM ne cible pas juste un GSA — il cible une paire précise
namespace + nom de KSA. Un pod dans le namespace staging
avec un service account nommé orders-ksa n'hérite d'aucun droit, même si le
nom est identique à celui de production, tant qu'aucun binding explicite
ne l'autorise. L'isolation est portée par Kubernetes lui-même, pas par une convention
de nommage ou une discipline d'équipe.
Ce que ça change concrètement
- Zéro fichier de clé statique : rien à exporter, rien à monter, rien à exfiltrer.
- Jetons éphémères : liés au cycle de vie du pod, pas à un fichier qui survit indéfiniment.
- Binding précis par namespace : pas de sur-privilège accidentel entre environnements.
- Moins de rotation manuelle : pas de clé à faire tourner, pas d'audit de fichiers exportés.
- Compatible Workload Identity Federation : même logique extensible à des charges hors GKE.
La clé de service account exportée a longtemps été la solution par défaut. Sur GKE, elle est aujourd'hui l'exception à justifier — pas la règle à appliquer.