Aller au contenu

Réduire RBAC Kubernetes et bloquer les pods dangereux

Réduire RBAC Kubernetes et bloquer les pods dangereux

Section intitulée « Réduire RBAC Kubernetes et bloquer les pods dangereux »

Un cluster Kubernetes devient compromettant dès qu’un compte de service reçoit plus de droits que son contrôleur n’en exige réellement. Le contrôle d’admission complète le RBAC (Role-Based Access Control) en refusant les objets dangereux avant qu’ils n’atteignent les nœuds, là où une erreur de manifeste cesse d’être théorique.

→ Lire l’explication complète de la marmotte

RBAC Kubernetes : le privilège global est une dette exploitable

Section intitulée « RBAC Kubernetes : le privilège global est une dette exploitable »

Le RBAC associe une identité à des verbes (get, list, create, patch, delete) et à des ressources Kubernetes. Une identité peut être un utilisateur, un groupe ou un compte de service (ServiceAccount), identité attribuée à un pod. Un Role limite les droits à un espace de noms (namespace) ; un ClusterRole peut couvrir tout le cluster ou décrire des droits réutilisables. Un RoleBinding applique une autorisation dans un espace de noms, y compris lorsqu’il référence un ClusterRole. Un ClusterRoleBinding, lui, rend cette autorisation globale.

La distinction n’est pas cosmétique. Accorder cluster-admin à un compte de service autorise pratiquement toute action sur l’interface de programmation du cluster, y compris la lecture de secrets, la création de charges de travail privilégiées et la modification des mécanismes d’autorisation. Un pod compromis portant ce jeton devient un poste d’administration. Le conteneur n’a pas besoin d’une évasion sophistiquée : l’interface du cluster livre déjà les clés du local.

Les exemples de documentation sont fréquemment écrits pour éliminer les erreurs de démarrage, pas pour établir une frontière de sécurité. cluster-admin résout une erreur d’autorisation en une ligne, ce qui explique son succès persistant dans les dépôts d’exemples. Cela résout aussi le problème de la serrure en supprimant la porte. Vingt ans d’exploitation apprennent qu’un droit temporaire ne disparaît jamais spontanément : il se fossilise dans un manifeste, puis devient une dépendance non documentée.

Les permissions permettant l’escalade doivent être traitées comme administratives, même sans libellé spectaculaire. La création ou modification de Role, ClusterRole, RoleBinding et ClusterRoleBinding permet d’accorder de nouveaux droits. La création de pods avec hostPath, privileged: true, un compte de service choisi ou des montages de secrets donne accès à des données ou capacités externes. Les verbes impersonate, bind et escalate ont précisément été conçus pour contrôler ces chemins. Les accorder à une automatisation applicative exige une justification écrite et une surveillance dédiée.

La première frontière doit rester le namespace. Un déploiement applicatif doit obtenir uniquement les ressources et verbes requis dans son namespace : lire quelques ConfigMap, créer ses Lease d’élection, mettre à jour un objet précis. Les contrôleurs réellement transverses, tels qu’un opérateur de sauvegarde ou un contrôleur d’entrée, justifient des droits de cluster. Le fait qu’un logiciel soit emballé dans un paquet populaire ne constitue pas une justification technique.

Cette séparation complète l’architecture IAM mais ne la remplace pas. L’authentification fédérée détermine qui atteint l’interface Kubernetes ; le RBAC décide ce que cette identité peut faire une fois admise. Une fédération irréprochable avec cluster-admin partout reste une autorisation totale, emballée dans un jeton mieux signé.

Audit des rôles et migration hors de cluster-admin

Section intitulée « Audit des rôles et migration hors de cluster-admin »

Commencer par inventorier les liaisons globales, pas par réécrire des manifestes au jugé. Les objets à examiner sont les ClusterRoleBinding, les RoleBinding qui référencent cluster-admin, les comptes de service montés automatiquement dans les pods et les règles contenant des jokers (*) pour les groupes d’API, ressources ou verbes. Un joker dans une ressource évolutive accorde aussi les ressources créées après l’audit. C’est une permission à durée indéterminée, ce qui est une façon élégante de dire « surprise future ».

kubectl-who-can identifie les sujets autorisés sur une ressource. rakkess expose les droits effectifs par identité. rbac-police détecte des motifs connus, dont les liaisons à cluster-admin, les accès aux secrets et certaines possibilités d’escalade. Aucun de ces outils ne comprend l’intention métier : ils produisent une liste de décisions à traiter, pas une absolution automatique. Les intégrer dans le contrôle des manifestes évite au moins de recréer la dette à chaque livraison.

La migration doit être progressive et observable. Créer d’abord un Role nommé pour une fonction, avec apiGroups, resources, verbs et éventuellement resourceNames explicites. Lier ce rôle au compte de service cible avec un RoleBinding dans le namespace concerné. Exécuter les flux applicatifs, observer les refus Forbidden dans les journaux de l’interface Kubernetes, puis ajouter le droit manquant le plus étroit possible. Retirer enfin l’ancienne liaison large. Remplacer d’abord cluster-admin par un autre rôle global vague revient à changer l’étiquette du poison.

Désactiver le montage automatique des jetons de comptes de service (automountServiceAccountToken: false) pour les pods qui n’appellent pas l’interface Kubernetes. Pour les autres, utiliser un jeton projeté à durée limitée, avec une audience définie. Cette mesure réduit la valeur d’un accès au système de fichiers du conteneur, mais elle ne corrige aucun droit excessif déjà accordé au compte.

Exemple reproductible : rôle scopé et vérification des droits

Section intitulée « Exemple reproductible : rôle scopé et vérification des droits »

L’exemple suivant remplace une permission globale par un rôle limité au namespace paiement. Le compte de service peut lire les configurations et mettre à jour un verrou d’élection nommé worker-lock, sans lire les secrets ni créer de pods.

Fenêtre de terminal
# Créer le namespace et le compte de service ciblé.
kubectl create namespace paiement
kubectl -n paiement create serviceaccount worker
# Appliquer un Role limité à des ressources et verbes explicitement nommés.
kubectl apply -f - <<'EOF'
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: worker-runtime
namespace: paiement
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: ["coordination.k8s.io"]
resources: ["leases"]
resourceNames: ["worker-lock"]
verbs: ["get", "create", "update", "patch"]
EOF
# Lier ce rôle au seul compte de service concerné.
kubectl -n paiement create rolebinding worker-runtime \
--role=worker-runtime \
--serviceaccount=paiement:worker
# Vérifier une permission attendue puis un refus attendu.
kubectl auth can-i get configmaps \
--as=system:serviceaccount:paiement:worker -n paiement
kubectl auth can-i get secrets \
--as=system:serviceaccount:paiement:worker -n paiement

La dernière commande doit répondre no. Si elle répond yes, une autre liaison accorde le droit ou l’identité testée n’est pas celle réellement utilisée. Le test doit être exécuté pour chaque namespace et chaque compte de service critique. Les tests unitaires n’observent généralement pas cette matrice, car l’autorisation ne se teste pas par télépathie.

Admission control : refuser les objets dangereux avant exécution

Section intitulée « Admission control : refuser les objets dangereux avant exécution »

Le contrôle d’admission intervient après l’authentification et l’autorisation, avant la persistance d’un objet dans l’état du cluster. Les contrôleurs de mutation peuvent compléter une ressource, par exemple ajouter des limites ; les contrôleurs de validation acceptent ou refusent la requête finale. L’ordre compte : une validation évalue l’objet après mutation. Une règle qui exige une limite de mémoire sans mutateur associé bloque donc les charges qui ne la déclarent pas.

Kubernetes fournit l’admission de sécurité des pods (Pod Security Admission). Les niveaux baseline et restricted bloquent plusieurs privilèges dangereux selon des règles intégrées. Depuis Kubernetes 1.25, les anciennes politiques de sécurité des pods ont été supprimées : compter sur elles dans un manifeste hérité revient à installer un extincteur retiré du bâtiment. Étiqueter les namespaces avec un mode d’application restricted est un minimum pour les charges applicatives, avec des exceptions isolées et documentées pour les composants système.

Ce mécanisme intégré ne couvre pas toutes les règles locales. Déployer Kyverno ou OPA (Open Policy Agent) Gatekeeper ajoute des politiques propres à l’organisation. Kyverno est le choix pragmatique lorsque les équipes manipulent déjà des manifestes Kubernetes : ses règles déclaratives et ses rapports facilitent l’adoption. Gatekeeper convient lorsqu’un patrimoine de politiques Rego existe déjà ou quand la même logique doit être partagée avec d’autres moteurs Open Policy Agent. Le compromis est net : chaque exception contrôlée coûte du temps de conception et de support, mais empêcher un montage du système hôte coûte beaucoup moins qu’analyser son exploitation.

Bloquer par défaut les pods privilégiés, hostNetwork, hostPID, hostIPC, les montages hostPath, les capacités Linux ajoutées et l’exécution en utilisateur racine. Interdire explicitement le socket Docker (/var/run/docker.sock) et les sockets de moteurs compatibles. Sur un nœud, ce montage donne généralement le contrôle du moteur de conteneurs et, par conséquent, du nœud. Docker n’est plus le moteur par défaut de nombreux clusters, mais le socket monté reste une relique suffisamment toxique pour mériter un refus explicite.

Imposer aussi requests et limits pour le processeur et la mémoire. L’absence de limites n’accorde pas des privilèges système, mais elle permet à une charge défaillante ou hostile d’épuiser un nœud et de provoquer une indisponibilité latérale. Définir des quotas de namespace (ResourceQuota) et des plages autorisées (LimitRange) complète cette validation. Une politique qui ajoute automatiquement des valeurs est acceptable pour les valeurs par défaut non sensibles ; une politique de sécurité doit refuser les écarts, sinon l’exception implicite devient le produit.

Exploitation des politiques, échecs et limites de sécurité

Section intitulée « Exploitation des politiques, échecs et limites de sécurité »

Un contrôleur d’admission est une dépendance de disponibilité du chemin de déploiement. Définir explicitement son comportement en cas d’indisponibilité : failurePolicy: Fail pour les règles qui empêchent une élévation de privilège, Ignore uniquement pour les contrôles non bloquants. Le mode permissif maintient les livraisons pendant une panne, mais transforme aussi cette panne en fenêtre d’attaque. Ce choix doit être assumé, pas hérité d’une valeur d’exemple.

Déployer toute nouvelle règle en audit, examiner les violations, corriger les manifestes puis passer en blocage. Conserver les exceptions dans des politiques nominatives avec date de révision, namespace et motif technique. Une exclusion globale de namespace pour « faire passer la livraison » annule le contrôle pour toutes les charges futures de cet espace. Les exceptions sans échéance sont des politiques, avec moins de tests et davantage de honte.

Superviser les refus d’admission, les modifications de liaisons RBAC, les créations de comptes de service et les accès anormaux à l’interface Kubernetes. Les journaux d’audit doivent être exportés hors du cluster ou vers un stockage protégé, faute de quoi un administrateur compromis peut effacer les traces locales. Sauvegarder les manifestes de rôles et de politiques avec la configuration déclarative, puis tester leur restauration dans un environnement séparé. Restaurer les données sans restaurer les garde-fous recrée un cluster fonctionnel, donc vulnérable.

Ni le RBAC ni l’admission control ne garantissent l’absence de compromission applicative, la sécurité d’une image, l’isolation parfaite du noyau ou la protection d’un secret lu légitimement. Une identité autorisée à lire un secret peut l’exfiltrer, même sous la plus élégante des politiques. Le reste doit venir du durcissement des nœuds, de la signature et analyse des images, des politiques réseau et de la gestion des secrets, sujets à raccorder aux fondations d’architecture cyber et à la sécurité des conteneurs et réseaux.

Sans rôles réduits ni contrôle d’admission, la porte de la ruche reste ouverte : le moindre conteneur compromis fournit un jeton équivalent à un accès d’administration, et rien ne distingue plus une action légitime d’une action hostile. La traçabilité s’effondre en premier : puisque tous les comptes de service peuvent tout, aucun refus n’est jamais journalisé et le périmètre d’un incident devient indéterminable, ce qui impose la rotation de l’ensemble des secrets du cluster après la compromission d’un seul pod. La reprise hérite du même défaut : réappliquer les manifestes réinstalle les liaisons globales et les montages hôtes, donc restaure le cluster et la faille en même temps. S’ajoute un coût silencieux : sans refus à l’admission, les charges sans limites saturent un nœud et dégradent des applications voisines qui n’ont rien demandé.

Kubernetes est un système qui lance et administre des programmes regroupés dans des conteneurs. Chaque programme peut recevoir une identité. Les règles d’autorisation déterminent ensuite quelles actions cette identité peut demander au système : lire une configuration, modifier un objet ou créer un autre programme.

Le problème apparaît lorsqu’une identité reçoit tous les droits alors qu’elle n’en utilise que quelques-uns. Si un attaquant prend le contrôle du programme associé, il récupère aussi ces droits. Il peut alors lire des informations secrètes, modifier d’autres programmes ou donner encore plus de droits à son propre compte. Il faut donc créer des autorisations limitées à un espace de travail, à des actions précises et aux données réellement nécessaires.

Avant de créer un programme, Kubernetes peut aussi vérifier sa description. Ce contrôle peut refuser un programme qui demande des privilèges trop élevés, qui accède directement au système de la machine hôte ou qui ne fixe aucune limite de mémoire et de processeur. Certaines règles peuvent compléter une description, mais les règles de sécurité doivent surtout bloquer ce qui est interdit.

Si le service qui vérifie ces règles tombe en panne, il faut choisir entre arrêter les créations de programmes ou les laisser passer sans contrôle. Pour les interdictions de sécurité, arrêter est le bon choix. Les refus, changements de droits et exceptions doivent être enregistrés, surveillés et revus régulièrement.

À lire aussi

Pages voisines

: les deux pages se citent l’une l’autre.