Introduction
La gestion sécurisée des secrets dans Kubernetes est crucial pour maintenir la sécurité dans nos applications. Dans cet article, je vais donc présenter la gestion des secrets dans Kubernetes en utilisant External Secrets Operator et Azure Key Vault via une authentification par workload identity. Ceci dans le but d’avoir une solution robuste et sécurisé.
Contexte
J’ai mis en place cette solution dans le cadre d’un projet d’une semaine durant mon master. Le but était le déploiement d’une stack applicative dans le cloud via un workflow GitOps. Le projet est disponible ici.
Dans ce projet, un cluster Azure Kubernetes Service (AKS) était déployé via terraform avec la configuration suivante requise pour mettre en place la solution :
|
|
⬆️ Permet d’activer l’émetteur OIDC (OpenID Connect) du cluster AKS. Cela signifie que le cluster AKS génère une URL d’émission de token OIDC, essentiel pour la relation de confiance que je vous présente plus tard dans cet article.
L’OIDC est un protocole d’authentification moderne qui repose sur le standard OAuth 2.0. Il permet à des applications de vérifier l’identité d’un utilisateur en s’appuyant sur un fournisseur d’identité et de récupérer des informations sur cet utilisateur de manière sécurisée.
|
|
⬆️ Active la fonctionnalité Azure Workload Identity, pour permettre aux pods Kubernetes d’accéder aux ressources Azure en utilisant les identités managées.
Composants
- External Secret Operator (ESO) : Opérateur Kubernetes qui permet d’intégrer un système de gestion des secrets externes.
- Azure Key Vault : Service cloud Azure permettant de stocker les secrets et d’y accéder en toute sécurité.
- Workload Identity : Méthode pour s’authentifier à une ressource Azure sans explicitement configurer des identifiants
Azure Key Vault
Dès que le cluster AKS est opérationnel, il faut déployer la ressource Azure Key Vault. Pour ce faire, j’ai utilisé terraform afin de pouvoir faire de l’IaC pour fiabiliser et automatiser mon déploiement. Pour le vault ainsi que les autres ressources Azure, j’ai utilisé le provider terraform azurerm.
Le code suivant va permettre la création du vault dans le resource group et la location défini avec le RBAC (Role Based Access Control) activé pour manager les accès et le SKU (Stock Keeping Unit) sur standard. D’autres arguments sont disponibles, mais j’ai préféré simplifier au vu de la durée du projet afin d’avoir un POC rapidement.
|
|
Une fois le vault déployé, on peut mettre ses secrets dedans via l’UI ou la CLI d’azure.

Azure Vault UI
Managed Identity
Une fois le vault déployé, il va falloir associer le rôle à la bonne identité afin de pouvoir accéder à nos secrets au travers de celle-ci.
Kubelet Identity
Lors de la création d’un cluster AKS, une managed identity de type user assigned va être créée dans le resource group, celui-ci est géré automatique par Azure et permet de stocker les ressources infrastructures réelles nécessaires au fonctionnement du cluster AKS. Cette identité managée se nomme kubelet_identity et elle va permettre à kubelet présent sur les nœuds du cluster d’accéder à d’autre ressource Azure. C’est au travers de cette identité que je vais pouvoir accéder au vault.

Interaction entre Kubelet Identity et les ressources Azure
J’ai assigné à cette identité les droits de lecture sur les secrets présents dans le vault grâce au rôle Key Vault Secrets User
:
|
|
Fédération d’identié
Lorsque les bons droits sont assignés, il va falloir lier cette identité à un service account dans Kubernetes afin de pouvoir accéder aux données de mon vault dans Azure.
Pour ce faire, il faut utiliser une federated identity credential qui va permettre de déléguer l’authentification à un fournisseur d’identité externe dans mon cas le cluster AKS et ainsi créer une relation de confiance entre AKS et l’identité managée dans Microsoft Entra ID.
|
|
Ici l’audience représente le destinataire prévu du jeton émis par l’émetteur de l’OIDC, le subject correspond à l’identité de l’entité (le service account dans mon cas) à laquelle l’identité fédérée est associée et issuer est l’URL d’émetteur OIDC du cluster AKS.
Diagramme de séquence
Voici un diagramme un peu plus précis sur le mécanisme de connexion au Vault via identité managée et fédération :

Diagramme de séquence pour la connexion au Vault
External Secrets Operator
Désormais, il faut mettre en place l’opérateur Kubernetes, External Secrets Operator (ESO) afin de pouvoir effectuer la connexion au vault via le provider Azure Key Vault fourni par ESO. Pour se faire des Customs Resources Definitions (CRD) existe et elles vont permettre de définir comment accéder au vault (Secret Store) et quels sont les données à récupérer (External Secret).
Secret Store
Dans cette ressource, il faut spécifier l’URL du vault, l’id du tenant Azure, le type d’authentification et le service account associé. C’est avec le secret store que je vais pouvoir me connecter à Azure Key Vault.
|
|
External Secret
Cette ressource va permettre de définir quel secret j’ai besoin de synchroniser entre le vault et le secret Kubernetes. Il faut définir le secret store à utiliser, notre secret cible dans Kubernetes et les secrets à récupérer depuis le vault Azure.
|
|
Service Account
Il faut également créer le service account en lui ajoutant l’annotation suivante afin de l’associer à l’ID de l’identité : Kubelet Identity.
|
|
Déploiement
Pour la partie déploiement, je suis aussi passé par du terraform en utilisant le provider helm et kubectl. Ceci permet d’avoir une infrastructure unifiée et automatisée de bout en bout.

Déploiement avec terraform
ESO
Pour ESO, une chart helm est fourni dans la documentation, celle-ci est déployée dans le namespace external-secrets
. Cette ressource terraform attend la fin du déploiement du cluster AKS pour être créée grâce au depend_on = [azurerm_kubernetes_cluster.aks]
.
|
|

Déploiement des pods ESO
Une fois ESO déployé, il faut créer nos CRD afin de configurer la connexion au vault et les secrets à récupérer mais également le service account. Tout ceci à l’aide de manifests Kubernetes qui permettent de déclarer les ressources en yaml.
CRD et Service Account
Pour les manifests, l’utilisation du provider terraform kubectl va me permettre d’utiliser des variables des ressources terraform directement dans les manifests pour avoir quelque chose de dynamique, comme on peut voir dans ce manifest. Ceci évite alors de mettre des informations sensibles en dur dans les manifests.
|
|
Les 3 ressources terraform sont déclarées, elles correspondent aux 3 manifests / ressources Kubernetes qu’il faut créer dans le cluster pour configurer et utiliser ESO.
Résultat
La connexion à Azure Key Vault est validé. Ceci grâce à la ressource secret-store.

Connexion à Azure Key Vault avec le secret store
Une fois connecté au vault, la synchronisation des secrets va s’effectuer. On peut le voir sur la resource external-secret qui est dans l’état SecretSynced
. Ceci va donc récupérer les secrets du vault et les mettre dans un secret Kubernetes.

Synchronisation des secrets en le vault et Kubernetes
Le secret a bien été crée et il est bien présent dans Kubernetes comme on peut le voir. Pour cette démonstration les passwords sont tous les mêmes, ce qui est bien sûr à ne pas faire dans un environnement de production.

Secret Kubernetes
Conclusion
La mise en place de cette solution sur un temps restreint a été un réel challenge pour moi, car je n’avais jamais réalisé ceci auparavant. J’ai pu travailler et approfondir mes compétences sur Azure et plus spécifiquement les rôles et identités de ce cloud provider.
L’objectif a été atteint, et la complexité de la solution m’a motivé à rédiger cet article, premièrement afin d’avoir une trace de cette réalisation en faisant un retour d’expérience, mais également dans le but de pouvoir aider les personnes qui tomberont tôt ou tard dessus.