Le paradoxe classique de la gestion des secrets : vous centralisez vos mots de passe dans Azure Key Vault… mais pour y accéder depuis Kubernetes, il faut un credential. Et ce credential-là, où le stockez-vous ?
Workload Identity supprime le problème à la racine. Le cluster AKS signe des tokens OIDC pour ses ServiceAccounts ; Microsoft Entra ID apprend à leur faire confiance ; le pod échange son token contre un token Entra ID — et accède au Key Vault. Aucune clé, aucun certificat, aucun secret d’amorçage stocké dans le cluster.
Cet article déroule le montage complet, tel que nous l’avons industrialisé dans une démo publique où External Secrets Operator (ESO) synchronise des mots de passe PostgreSQL depuis trois coffres (Key Vault, HashiCorp Vault, AWS Secrets Manager).
Le concept : échanger un token Kubernetes contre un token Entra ID
Deux options du cluster AKS font tout le travail :
az aks create -g $RG -n $AKS \
--enable-oidc-issuer \
--enable-workload-identity \
...
--enable-oidc-issuerexpose un issuer OIDC public : une URL qui publie les clés de signature des tokens de ServiceAccounts du cluster ;--enable-workload-identityinjecte dans les pods concernés un token projeté et les variables d’environnement attendues par les SDK Azure.
À partir de là, un token de ServiceAccount devient une preuve d’identité vérifiable de l’extérieur : Entra ID peut valider sa signature en interrogeant l’issuer, comme n’importe quel fournisseur OIDC.
C’est exactement le même principe qu’IRSA côté AWS — nous l’avons d’ailleurs appliqué à AWS Secrets Manager depuis ce même cluster AKS.
L’identité managée : une identité dédiée, pas un compte partagé
On crée une User Assigned Managed Identity dédiée au besoin (ici : la lecture des secrets par ESO) :
az identity create -g $RG -n id-eso-demo
UAMI_CLIENT_ID=$(az identity show -g $RG -n id-eso-demo --query clientId -o tsv)
UAMI_PRINCIPAL_ID=$(az identity show -g $RG -n id-eso-demo --query principalId -o tsv)
Deux identifiants qu’on confond souvent :
clientId— l’identifiant d’application, celui qu’on annote sur le ServiceAccount ;principalId— l’identifiant du service principal, celui qu’on utilise pour les attributions RBAC.
Une identité dédiée par usage : c’est ce qui permet un périmètre de droits minimal et un audit lisible.
Le RBAC Key Vault : lecture seule, sur le bon scope
az role assignment create \
--assignee-object-id $UAMI_PRINCIPAL_ID --assignee-principal-type ServicePrincipal \
--role "Key Vault Secrets User" \
--scope $(az keyvault show -g $RG -n $KV --query id -o tsv)
- « Key Vault Secrets User » : lecture seule des secrets (plan données) — c’est tout ce dont ESO a besoin ;
- « Key Vault Secrets Officer » : lecture/écriture — réservé à l’humain (ou au pipeline) qui pousse les secrets.
Le scope est le vault lui-même, pas le resource group : moindre privilège, toujours.
Le federated credential : la ligne de confiance
C’est la pièce centrale du montage — la déclaration qui dit à Entra ID « ce ServiceAccount Kubernetes est cette identité managée » :
az identity federated-credential create \
--name fc-eso --identity-name id-eso-demo -g $RG \
--issuer $(az aks show -g $RG -n $AKS --query oidcIssuerProfile.issuerUrl -o tsv) \
--subject "system:serviceaccount:eso-demo:eso-sa" \
--audience api://AzureADTokenExchange
Trois paramètres, trois verrous :
- issuer : seul ce cluster peut émettre les tokens acceptés ;
- subject : seul le ServiceAccount
eso-sadu namespaceeso-demoest reconnu — pas un autre SA, pas un autre namespace ; - audience :
api://AzureADTokenExchange, l’audience dédiée à l’échange de tokens.
Le moindre écart sur le
subject(faute de frappe, mauvais namespace) produit une erreurAADSTS70021: No matching federated identity record found— c’est le premier endroit à vérifier en cas de panne.
Côté cluster : un ServiceAccount annoté, et c’est tout
apiVersion: v1
kind: ServiceAccount
metadata:
name: eso-sa
namespace: eso-demo
annotations:
azure.workload.identity/client-id: "<clientId de l'identité managée>"
labels:
azure.workload.identity/use: "true"
Le SecretStore d’External Secrets Operator référence ce SA et déclare l’authentification Workload Identity :
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
name: azure-store
namespace: eso-demo
spec:
provider:
azurekv:
authType: WorkloadIdentity
vaultUrl: "https://kv-eso-demo.vault.azure.net/"
tenantId: "<tenant-id>"
serviceAccountRef:
name: eso-sa
À partir de là, chaque ExternalSecret adossé à ce store lit le Key Vault et matérialise un Secret Kubernetes — templable (type basic-auth, URL de connexion, etc.), resynchronisé périodiquement, rotation comprise : changez le mot de passe dans le coffre, ESO propage.
Déboguer : les trois pannes classiques
| Symptôme | Cause probable |
|---|---|
AADSTS70021: No matching federated identity record |
le subject du federated credential ne correspond pas à system:serviceaccount:<ns>:<sa>, ou mauvais issuer |
403 Forbidden sur le Key Vault |
rôle « Key Vault Secrets User » absent, mauvais scope, ou vault resté en access policies au lieu de RBAC |
| Token non injecté dans le pod | label azure.workload.identity/use: "true" absent du SA (ou du pod), ou add-on Workload Identity non activé |
Le réflexe : kubectl describe secretstore puis kubectl describe externalsecret — les conditions et events d’ESO pointent presque toujours la brique fautive.
Ce qu’il faut retenir
| Brique | Rôle |
|---|---|
| OIDC issuer AKS | rend les tokens de SA vérifiables de l’extérieur |
| Identité managée dédiée | porte les droits, un usage = une identité |
| Rôle « Key Vault Secrets User » | lecture seule, scope réduit au vault |
| Federated credential | la confiance issuer + subject + audience |
| SA annoté + SecretStore | le câblage côté cluster, sans aucun secret |
Le montage tient en une vingtaine de lignes de CLI et deux manifests — l’intégralité est rejouable depuis la démo eso-aks-demo (script mise run azure-setup, idempotent). Et si votre plateforme parle aussi à AWS, le même principe s’applique à Secrets Manager — avec quelques pièges spécifiques que nous avons documentés.
Pour aller plus loin sur la trajectoire plateforme, voir aussi Kubernetes pour l’entreprise.