Aller au contenu
English
Conteneurs & Orchestration medium

Sécurité Helm : droits RBAC et secrets de release

55 min de lecture

logo helm

Helm n'a aucun droit à lui : il agit avec votre identité Kubernetes, et ne peut donc rien faire que vous ne puissiez déjà faire. Ce guide établit ce point par l'expérience, puis traite ce qu'il implique de moins évident : Helm conserve dans le cluster les values de chaque révision, y compris celles que vous préféreriez oublier.

  • Établir avec quelle identité Helm applique ses manifestes
  • Prévoir si une installation passera, avant de la lancer
  • Distinguer les droits de l'opérateur de ceux que le chart demande
  • Situer où Helm range l'état des releases, et qui peut le lire
  • Comprendre pourquoi une value sensible survit dans l'historique
  • Savoir installer et mettre à jour une release (voir Lifecycle)
  • Les notions Kubernetes de Role, ClusterRole et ServiceAccount
  • Un cluster où vous pouvez usurper une identité (--as), ce que permet un cluster local

Helm v3 et v4 n'ont pas de composant serveur. Il n'y a ni agent installé dans le cluster, ni compte de service dédié : le binaire lit votre kubeconfig et parle à l'API server en votre nom. Vous pouvez le vérifier sur n'importe quel cluster :

Fenêtre de terminal
kubectl get serviceaccounts -A | grep -i helm
kubectl get deployments -A | grep -i tiller

Les deux commandes ne rendent rien. Cette absence est le point le plus important de ce guide, et c'est une rupture avec Helm 2 : celui-ci installait Tiller, un composant serveur qui agissait avec ses propres droits, souvent cluster-admin. N'importe qui pouvant parler à Tiller héritait alors de ces droits, ce qui en avait fait le principal reproche fait à Helm 2.

La conséquence pratique tient en une phrase : si votre kubectl ne peut pas créer une ressource, votre helm install ne le pourra pas non plus. Aucun drapeau, aucune option ne contourne cela.

kubectl auth can-i répond exactement à la question que pose une installation, et il le fait sans rien créer :

Fenêtre de terminal
kubectl auth can-i create deployments -n demo
kubectl auth can-i create clusterroles

C'est le premier réflexe devant un chart tiers dont vous avez lu l'inventaire des ressources, comme le montre la leçon sur l'inspection des charts : un chart qui déclare un ClusterRole exige un droit à l'échelle du cluster, que la plupart des comptes applicatifs n'ont pas.

Prenons un utilisateur autorisé sur tout dans son namespace, mais sans aucun droit à l'échelle du cluster :

Fenêtre de terminal
kubectl auth can-i create deployments -n demo --as=dev-restreint # yes
kubectl auth can-i create clusterroles --as=dev-restreint # no

Un chart qui ne crée qu'une ConfigMap s'installe sans difficulté sous cette identité :

Fenêtre de terminal
helm install s1 ./simple -n demo --kube-as-user dev-restreint
STATUS: deployed

Ajoutez un ClusterRole au même chart, ne changez rien d'autre, et l'installation s'arrête :

Error: INSTALLATION FAILED: unable to continue with install: could not get
information about the resource ClusterRole "helm-rbac-lecteur" in namespace "":
clusterroles.rbac.authorization.k8s.io "helm-rbac-lecteur" is forbidden:
User "dev-restreint" cannot get resource "clusterroles" in API group
"rbac.authorization.k8s.io" at the cluster scope

Le message nomme l'utilisateur, la ressource et la portée. Le même chart, lancé avec une identité d'administration, s'installe et crée le ClusterRole. Rien dans Helm n'a changé : seule l'identité a changé.

C'est la confusion la plus fréquente sur ce sujet, et elle porte à conséquence.

Identité de l'opérateurServiceAccount du chart
Qui ?vous, ou l'agent de CIles Pods déployés
Défini où ?dans le kubeconfigdans les templates du chart
Sert à quoi ?créer les ressourcesappeler l'API depuis l'application
Quand ?pendant install et upgradependant toute la vie des Pods

Les deux sont indépendantes. Un chart peut créer un ServiceAccount très restreint pour son application tout en exigeant, pour être installé, des droits étendus. Et l'inverse existe : une installation anodine peut déployer un Pod qui, lui, obtient des droits considérables.

La question de sécurité utile porte donc sur les deux, et elle se lit dans le rendu, jamais dans le Chart.yaml.

Helm ne garde aucun état sur votre poste. Tout vit dans le cluster, dans des Secrets du namespace de la release, à raison d'un par révision :

Fenêtre de terminal
kubectl get secret -n demo | grep sh.helm.release
sh.helm.release.v1.mon-app.v1
sh.helm.release.v1.mon-app.v2
sh.helm.release.v1.mon-app.v3

Ce choix explique des comportements vus ailleurs dans ce parcours : helm list ne montre que le namespace courant parce qu'il liste des Secrets, et helm get manifest fonctionne depuis n'importe quelle machine parce qu'il lit le cluster, pas vos fichiers.

Le contenu de chaque Secret est le manifeste appliqué et les values utilisées, compressés. Ce n'est pas un détail d'implémentation : c'est l'endroit où finissent les valeurs que vous passez, et il survit à tout sauf à la suppression de la révision.

Le Secret n'est pas le seul pilote de stockage possible. La variable d'environnement HELM_DRIVER accepte secret, la valeur par défaut, mais aussi configmap, memory et sql. Le passage à sql répond à un problème précis : la taille maximale d'un Secret, que dépassent les très gros charts ou les historiques longs.

Changer de pilote ne change rien au raisonnement de sécurité de cette leçon, si ce n'est le lieu où regarder. Un stockage en configmap est même moins protégé que le défaut, puisque les ConfigMaps échappent aux politiques qui restreignent spécifiquement la lecture des Secrets.

C'est le point que ce guide existe pour établir. Passer un mot de passe en --set, puis le changer au déploiement suivant, ne le fait pas disparaître : l'ancienne révision le conserve, et elle reste interrogeable.

La démonstration tient en trois commandes. Un déploiement avec une valeur sensible, un second qui la remplace, puis la lecture de l'historique :

Fenêtre de terminal
helm upgrade mon-app ./chart -n demo --set motDePasse=SECRET-V2
helm upgrade mon-app ./chart -n demo --set motDePasse=autre-chose
Fenêtre de terminal
helm get values mon-app -n demo
USER-SUPPLIED VALUES:
motDePasse: autre-chose

Jusqu'ici, rien d'inquiétant. Mais l'historique répond aussi :

Fenêtre de terminal
helm get values mon-app -n demo --revision 3
USER-SUPPLIED VALUES:
motDePasse: SECRET-V2

La valeur remplacée est toujours là, dans le Secret sh.helm.release.v1.mon-app.v3, et elle y restera tant que cette révision existe.

Toute personne disposant du droit de lire les Secrets du namespace. C'est un droit très banal, souvent accordé aux développeurs de l'application :

Fenêtre de terminal
kubectl auth can-i get secrets -n demo --as=dev-restreint # yes

Autrement dit, un droit de lecture sur les Secrets d'un namespace vaut lecture de toutes les values de toutes les révisions des releases qui s'y trouvent. Y compris celles déployées il y a six mois par quelqu'un d'autre.

Ne pas mettre le secret dans les values. C'est la seule parade complète. Le chart référence un Secret Kubernetes existant par son nom, et la valeur n'entre jamais dans Helm :

env:
- name: MOT_DE_PASSE
valueFrom:
secretKeyRef:
name: mon-app-identifiants
key: motDePasse

Le Secret est alors créé et pivoté hors du cycle de vie de la release, par un gestionnaire de secrets, un opérateur comme External Secrets, ou une commande d'administration. Helm ne voit jamais que son nom.

Borner l'historique, avec --history-max. Cela ne protège rien, mais réduit la fenêtre : une valeur qui a quitté l'historique n'est plus lisible.

Traiter les droits sur les Secrets du namespace comme des droits sensibles. Beaucoup d'équipes les accordent largement en pensant ne donner accès qu'aux secrets applicatifs.

Objectif : constater qu'un même chart passe ou échoue selon l'identité, puis retrouver une valeur que vous croyiez remplacée.

  1. Créer un utilisateur limité à un namespace

    Fenêtre de terminal
    kubectl create namespace demo

    Déclarez un Role donnant tous les droits dans ce namespace seulement, et liez-le à un utilisateur dev-restreint. Vérifiez ensuite ce qu'il peut faire :

    Fenêtre de terminal
    kubectl auth can-i create deployments -n demo --as=dev-restreint
    kubectl auth can-i create clusterroles --as=dev-restreint

    La première commande doit répondre yes, la seconde no.

  2. Installer un chart sans ressource cluster

    Fenêtre de terminal
    helm install s1 ./simple -n demo --kube-as-user dev-restreint

    Le déploiement passe : le chart ne demande rien qui dépasse le namespace.

  3. Ajouter un ClusterRole au chart, et rien d'autre

    Relancez l'installation sous la même identité. Elle échoue, et le message nomme l'utilisateur, la ressource et la portée.

  4. Rejouer avec votre identité habituelle

    Fenêtre de terminal
    helm install s3 ./simple -n demo

    Le même chart s'installe. Seule l'identité a changé.

  5. Faire disparaître une valeur, puis la retrouver

    Fenêtre de terminal
    helm upgrade s3 ./simple -n demo --set motDePasse=SECRET-V2
    helm upgrade s3 ./simple -n demo --set motDePasse=autre-chose
    helm get values s3 -n demo
    helm get values s3 -n demo --revision 2

    La dernière commande rend la valeur que vous pensiez avoir remplacée.

  6. Nettoyer

    Fenêtre de terminal
    helm uninstall s1 s3 -n demo
    kubectl delete namespace demo
    kubectl delete clusterrole helm-rbac-lecteur
  • Helm n'a pas d'identité propre : il agit avec celle du kubeconfig, et n'élève aucun privilège
  • Helm 2 et son composant Tiller faisaient exception, et c'est ce qui leur était reproché
  • kubectl auth can-i répond avant l'installation à ce que le message d'erreur dirait après
  • L'identité de l'opérateur et le ServiceAccount du chart sont deux choses indépendantes
  • Helm stocke un Secret par révision dans le namespace, contenant manifeste et values
  • helm get values --revision N rend les values d'une ancienne révision, secrets compris
  • Lire les Secrets d'un namespace vaut lecture de toutes les values de toutes les révisions
  • La seule parade complète est de ne pas faire entrer le secret dans les values

Six questions sur ce que Helm peut et ne peut pas faire en votre nom : ce qu'il advient d'un chart réclamant un ClusterRole sous une identité restreinte, ce que Tiller changeait en Helm 2, et où finit une value sensible que vous croyiez remplacée.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

7 questions
5 min.
80% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

  • Packaging et promotion en CI/CD : les mêmes questions de droits se posent à l'agent d'intégration continue, qui détient souvent une identité bien plus large que la vôtre.
  • Migrer vers Helm v4 : le passage au Server-Side Apply change le gestionnaire qui détient chaque champ, ce qui se lit dans les managedFields.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn