Sécurité de Kubernetes dans le cloud Azure – partie 5 – Sécuriser les secrets
Dans une application Cloud native native exécutée dans Kubernetes, il convient de porter une attention particulière à la gestion des secrets. Les secrets sont des paramètres de configuration sensibles tels que des mot de passe, des chaînes de connexion aux datastores ou encore des clés d’API.
Par définition, ces éléments ne devraient jamais se retrouver packagés avec le code dans une image de conteneur. La séparation stricte du Code de la Configuration étant une des 12 règles consistuant les 12 factors apps.
Cela tombe bien, Kubernetes dispose de ressources spécifiques pour cela : les configmaps et les secrets. Basiquement les secrets sont très similaires aux configmaps mais sont spécialement dédiés au stockage des données confidentielles.
Du coup, le problème est réglé ? Oui et non 🙂
Tout d’abord il faut savoir que ces informations sensibles sont stockées non chiffrées dans le datastore (etcd) de l’API Server, elles sont simplement stockées encodées en base64. Cela signifie que quiconque ayant des droits d’accès sur l’API Server peut récupérer ou modifier un secret ! Encore pire, tout utilisateur autorisé à déployer un pod (ou un deployment) dans un namespace, peut utiliser ses privilèges pour lire n’importe quel secret dans ce namespace.
Bref, cela n’est pas rassurant et il faut se poser la question sur les risques potentiels (c’est traité dans la documentation officielle de Kubernetes)

Du coup la documentation officielle de Kubernetes recommande :
1- D’activer le chiffrement au repos (at rest) et de bien gérer les clés de chiffrement associées (backup, rotation). Azure Kubernetes Service étant un service géré, ce chiffrement at rest est déjà implémenté et géré par les équipes Microsoft
2- Limiter, grâce au RBAC de Kubernetes, les privilèges des humains, préférer et encourager l’approche automatisée avec des mécanismes type pipeline de déploiements continus (idéalement avec une approche GitOps et des revues de changement faits par des paris lors des Pull Request). Pour vous aider dans la gestion du RBAC de Kubernetes, il est possible avec AKS d’utiliser Azure RBAC for Kubernetes Authorization
Est il cependant possible de faire mieux et d’externaliser le stockage et la gestion des secrets ailleurs ?
La réponse est oui et plusieurs solutions sont utilisables. Dans un environnement Azure, deux solutions sont, à mon avis, à retenir :
1- Azure Key Vault : service managé Azure destiné à stocker de manière sécurisée des secrets, clés cryptographiques ou encore des certificats. Au delà du stockage sécurisé, Azure Key Vault apporte : le contrôle granulaire des accès, la journalisation (en vue de traçabilité) et la séparation des rôles et responsabilités (les Dev/Ops ne gèrent plus les secrets, ils y font simplement référence dans leurs codes). J’ai publié récemment une vidéo d’introduction à Azure Key Vault pour ceux voulant découvrir ce service.
2- HashiCorp Vault : ici deux options sont possible : utiliser une solution Vault managée HashiCorp Cloud Platform, actuellement sur AWS (et prochainement disponible dans Azure) ou opérer sa (ses) propre(s) instance(s) sous la forme de machines virtuelles ou de pods dans Kubernetes (même si cette approche n’est pas la plus recommandable en production du fait de la complexité pour la déployer, sécuriser et maintenir en condition opérationnelle). Pour les environnements de production, privilégiez une approche service managé car la vie est… trop courte 🙂

Comment utiliser ces solutions dans un environnement Kubernetes ?
Pour Hashicorp Vault, plusieurs implémentations sont possibles :
- Les secrets peuvent être injectés dans les pods Kubernetes via un sidecar Vault Agent Injector . cf. https://learn.hashicorp.com/tutorials/vault/kubernetes-sidecar
- Les secrets peuvent être attachés en tant que volume éphémères via l’utilisation d’une extension Secret Store driver pour Container Storage Interface (CSI). cf. https://learn.hashicorp.com/tutorials/vault/kubernetes-secret-store-driver
Pour Azure Key Vault, là encore plusieurs options s’offrent à vous :
- La première consiste à utiliser dans le code des applications les API spécifiques d’accès à Azure Key Vault. Pour aider les développeurs à utiliser au mieux Azure Key Vault, un guide spécifique est disponible dans la documentation Azure.
- La seconde est d’attacher les secrets en tant que volume éphémères via l’utilisation de l’Azure Key Vault Provider for Secrets Store CSI Driver.
Azure Kubernetes Service dispose désormais d’un add-on permettant l’installation aisée de ce secret CSI Store Driver.

Cet add-on Secret Store CSI driver va instancier des pods aks-secret-store-xxxx dans le namespace kube-system

Ces pods sont gérés via des DaemonSet et seront soit des pods linux, soit des pods Windows en fonction du système d’exploitation des node pools.

Une fois ces composants installés sur le cluster AKS (le secret Store driver est aussi utilisable dans d’autres distributions Kubernetes cf. le GitHub du Secret Store CSI Driver), il faut créer une identité qui sera utilisée pour définir les permissions d’accès à l’Azure Key Vault (via le RBAC d’Azure ou les Access Policies d’Azure Key Vault).
Cette identité peut être associée aux worker nodes (VMScaleSet via les user-assigned ou les system-assigned managed identity) ou aux pods (via les Azure Active Directory pod-managed identities)
Ici par exemple, je vais utiliser la user managed identity de mon cluster AKS (pour être plus précis, la managed identity liée au kubelet présent sur chacune des VM node workers, c’est à dire le VMScaleSet de mon cluster). La commande suivante permet via la CLI Azure de récupérer le ClientID de cette identité:

Une autre façon de récupérer cette information est d’aller (via le portail Azure) dans le resource group contenant les ressources du cluster AKS (MC_nomduRessourceGroupAKS_nomducluster_region) et de regarder les propriétés des managed identities associées aux nodes pools.


Passons ensuite du côté d’Azure Key Vault dans lequel je crée un secret (une chaine de caractères) appelé stansecret.

Via les access policies d’Azure Key Vault, je donne l’autorisation à l’identité de mon kubelet de lire les secrets dans cet Azure Key Vault.

Reste ensuite à définir une Secret Provider Class via un manifest YAML avec le nom de l’Azure Key Vault, la managed identity et les objets (secrets, clés, certificats) à utiliser dans l’Azure Key Vault.

Une fois le manifest correctement renseigné, le déployer dans le cluster Kubernetes

Il reste à tester en déployant un pod qui va monter dans son système de fichier le secret présent dans l’Azure Key Vault


Le volume associé à la Secret Provider Class est bien monté. Il est possible de vérifier simplement la présence et la valeur des objets issus d’Azure Key Vault (ici juste un secret)


Voilà, le secret stocké dans l’Azure Key Vault est désormais accessible à l’application tournant dans le pod.
Pour aller plus loin sur le sujet : https://docs.microsoft.com/en-us/azure/aks/csi-secrets-store-driver
Voilà ! Désormais vous avez les clés pour sécuriser vos secrets dans les applications exécutées sur Kubernetes.
— Stanislas Quastana —