Secrets zéro-config : Key Vault + Managed Identity
appsettings.json finit dans l'historique Git, donc compromis. La parade idiomatique sur Azure : Key Vault pour stocker les secrets, Managed Identity pour y accéder sans mot de passe. Une fois les deux branchés, ni votre configuration ni votre code ne contiennent la moindre chaîne sensible.
Le secret qui sert à lire les secrets
IDENTITY_ENDPOINT sur App Service et Container Apps, l'IMDS 169.254.169.254 sur une VM) que le SDK interroge. Rien de sensible ne touche le code ni la config.
DefaultAzureCredential enchaîne plusieurs sources d'authentification et retient la première qui répond. En cloud, c'est l'identité managée ; en local, un outil de développeur. Le même binaire fonctionne des deux côtés.
GetSecretAsync renvoie un Response<KeyVaultSecret> : secret.Value porte la chaîne, secret.Properties porte les métadonnées (version, date d'expiration, état d'activation). Chaque appel touche le vault, un point sur lequel je reviens plus bas.
System-assigned ou user-assigned
DefaultAzureCredential ne sait pas laquelle utiliser. Il faut lui indiquer le clientId via DefaultAzureCredentialOptions { ManagedIdentityClientId = "..." } .
Key Vault comme provider de configuration
SecretClient à la main partout, branchez Key Vault directement sur le système de configuration ASP.NET Core. Tous les secrets deviennent des entrées de configuration ordinaires, fusionnées avec appsettings.json et les variables d'environnement.
AddAzureKeyVault vit dans le paquet Azure.Extensions.AspNetCore.Configuration.Secrets . La convention de nommage compte : Key Vault interdit le : dans un nom de secret, donc on écrit -- , que le KeyVaultSecretManager par défaut retraduit en séparateur de section. Db--ConnectionString devient Db:ConnectionString , exactement comme le reste de votre config typée liée par IOptions<T> .
RBAC plutôt que les access policies
enableRbacAuthorization ). Préférez le RBAC Azure : il utilise les mêmes rôles et le même audit que le reste de vos ressources, là où les anciennes access policies vivent dans un coin isolé du vault.
$PRINCIPAL_ID est l' objectId de l'identité managée, renvoyé à son activation sur la ressource. Le moindre privilège se lit dans le scope autant que dans le rôle : cadrez l'attribution sur un seul vault, pas sur le resource group entier.
Rotation et cache
AzureKeyVaultConfigurationOptions.ReloadInterval : passez-lui un TimeSpan et il repioche les secrets à intervalle régulier. C'est du polling , pas du push : Key Vault ne prévient pas l'app d'un changement, l'app interroge. Un intervalle de quelques minutes est un compromis raisonnable entre fraîcheur et volume d'appels.
GetSecret frappe le vault, qui applique un throttling (de l'ordre de quelques milliers de transactions par tranche de dix secondes, tous secrets confondus). Lire un secret à chaque requête HTTP est un anti-pattern : chargez-le au démarrage, ou mettez-le en cache avec une durée de vie, et laissez le ReloadInterval gérer la rotation. Le SecretClient ne met rien en cache pour vous.
Dev local et cloud, le même code
DefaultAzureCredential récupère le token de l'identité managée. Sur votre poste, il descend la chaîne jusqu'à trouver une session de développeur : l' Azure CLI ( az login ), Visual Studio, ou l'Azure Developer CLI. Aucune variable ni fichier de secret à gérer en local.
DefaultAzureCredentialOptions , ce qui accélère aussi le démarrage.
Key Vault et Managed Identity retirent les secrets du code et de la config : ils vivent dans le vault, l'accès passe par une identité de plateforme, et la rotation ne demande pas de redéploiement. Il ne reste rien à protéger dans le dépôt.