Blog sur Kubernetes

Blog sur Kubernetes

Contexte

Auteurs : Jim Angel (Google), Pushkar Joglekar (VMware), et Savitha Raghunathan (Red Hat)

Le 3 août 2021, la National Security Agency (NSA) et l’Agence de cybersécurité et de sécurité des infrastructures (CISA) des États-Unis ont publié un guide intitulé “Kubernetes Hardening Guidance”. Ce guide détaille les menaces pesant sur les environnements Kubernetes et fournit des conseils de configuration sécurisée pour minimiser les risques.

Les sections suivantes de ce blog sont en corrélation avec les sections du guide NSA/CISA. Les sections manquantes sont omises en raison des opportunités limitées d’ajouter du contenu supplémentaire.

Note : Ce billet de blog ne remplace pas la lecture du guide. Il est recommandé de lire le guide publié avant de continuer, car le contenu suivant est complémentaire.

Introduction et modèle de menace

Il convient de noter que les menaces identifiées comme importantes par la NSA/CISA, ou le public visé par ce guide, peuvent être différentes des menaces jugées importantes par d’autres utilisateurs d’entreprise de Kubernetes. Cette section est néanmoins utile pour les organisations concernées par la protection des données, le vol de ressources et l’indisponibilité des services.

Le guide met en évidence les trois sources de compromission suivantes :

  • Risques liés à la chaîne d’approvisionnement
  • Acteurs malveillants
  • Menaces internes (administrateurs, utilisateurs ou fournisseurs de services cloud)

Le modèle de menace tente de prendre du recul et d’examiner les menaces qui existent non seulement à l’intérieur du périmètre d’un cluster Kubernetes, mais aussi dans l’infrastructure sous-jacente et les charges de travail environnantes que Kubernetes ne gère pas.

Par exemple, lorsque des charges de travail en dehors du cluster partagent le même réseau physique, elles ont accès au kubelet et aux composants du plan de contrôle : etcd, gestionnaire de contrôle, planificateur et serveur API. Par conséquent, le guide recommande d’avoir une isolation au niveau du réseau séparant les clusters Kubernetes des autres charges de travail qui n’ont pas besoin de se connecter aux nœuds du plan de contrôle de Kubernetes. Plus précisément, le planificateur, le gestionnaire de contrôle et etcd doivent seulement être accessibles au serveur API. Toutes les interactions avec Kubernetes depuis l’extérieur du cluster peuvent se faire en fournissant un accès au port du serveur API.

La liste des ports et protocoles pour chacun de ces composants est définie dans les “Ports and Protocols” de la documentation Kubernetes.

Note spéciale : kube-scheduler et kube-controller-manager utilisent des ports différents de ceux mentionnés dans le guide.

La section de modélisation des menaces du document CNCF Cloud Native Security Whitepaper + Map offre une autre perspective pour modéliser les menaces de Kubernetes, avec une approche axée sur le cloud natif.

Sécurité des pods Kubernetes

Par défaut, Kubernetes ne garantit pas une isolation stricte des charges de travail entre les pods s’exécutant sur le même nœud d’un cluster. Cependant, le guide propose plusieurs techniques pour améliorer l’isolation existante et réduire la surface d’attaque en cas de compromission.

Conteneurs “Non-root” et moteurs de conteneur “rootless”

Plusieurs bonnes pratiques liées au principe de sécurité de moindre privilège, c’est-à-dire fournir uniquement les permissions nécessaires ; ni plus, ni moins, méritent un second regard.

Le guide recommande de définir un utilisateur non-root au moment de la construction de l’image du conteneur plutôt que de s’appuyer sur le paramètre runAsUser au moment de l’exécution dans la spécification du Pod. Il s’agit d’une bonne pratique qui offre un certain niveau de défense en profondeur. Par exemple, si l’image du conteneur est construite avec l’utilisateur 10001 et que la spécification du Pod oublie d’ajouter le champ runAsUser dans son objet Deployment, cela peut entraîner certains cas particuliers qui méritent d’être explorés :

  1. Les pods peuvent échouer au démarrage si l’utilisateur défini au moment de la construction est différent de celui défini dans la spécification du pod et que certains fichiers sont donc inaccessibles.
  2. Les pods peuvent se retrouver à partager involontairement des identifiants d’utilisateur (UID). Cela peut poser problème même si les identifiants d’utilisateur sont différents de zéro, dans une situation où une évasion du conteneur vers le système de fichiers hôte est possible. Une fois que l’attaquant a accès au système de fichiers hôte, il a accès à toutes les ressources de fichiers appartenant à d’autres pods non liés qui partagent le même UID.
  3. Les pods peuvent se retrouver à partager des identifiants d’utilisateur avec d’autres processus au niveau du nœud qui ne sont pas gérés par Kubernetes, tels que les démons de niveau nœud pour l’audit, l’analyse des vulnérabilités, la télémétrie. La menace est similaire à celle mentionnée ci-dessus, car l’accès au système de fichiers hôte permet à l’attaquant d’avoir un accès complet à ces démons de niveau nœud sans avoir besoin d’être root sur le nœud.

Cependant, aucun de ces cas n’aura un impact aussi grave qu’un conteneur s’exécutant en tant qu’utilisateur root et capable de s’évader en tant qu’utilisateur root sur l’hôte, ce qui permet à l’attaquant de prendre le contrôle total du nœud de travail, et de se déplacer latéralement vers d’autres noeuds de travail ou de contrôle.

Kubernetes 1.22 a introduit une fonctionnalité alpha qui réduit spécifiquement l’impact d’un composant du plan de contrôle s’exécutant en tant qu’utilisateur root vers un utilisateur non-root grâce aux espaces de noms utilisateur.

Cette prise en charge (en version alpha) des espaces de noms utilisateur / mode sans root est disponible avec les runtimes de conteneur suivants :

  • Docker Engine
  • Podman

Certaines distributions prennent en charge l’exécution en mode sans root, comme les suivantes :

  • kind
  • k3s
  • Usernetes

Systèmes de fichiers de conteneur immuables

Le guide “Kubernetes Hardening Guidance” souligne une fonctionnalité souvent négligée : readOnlyRootFileSystem, avec un exemple concret dans l’annexe B. Cette fonctionnalité limite l’exécution et la manipulation des conteneurs lors de l’exécution. Toute activité de lecture/écriture peut ensuite être limitée à quelques répertoires en utilisant des montages de volumes tmpfs.

Cependant, certaines applications qui modifient le système de fichiers du conteneur lors de l’exécution, comme l’explosion d’un fichier WAR ou JAR au démarrage du conteneur, pourraient rencontrer des problèmes lors de l’activation de cette fonctionnalité. Pour éviter ce problème, il est conseillé de limiter au minimum les modifications du système de fichiers lors de l’exécution.

Création d’images de conteneur sécurisées

Le “Kubernetes Hardening Guidance” recommande également d’exécuter un analyseur au moment du déploiement en tant que contrôleur d’admission, afin d’empêcher l’exécution de pods vulnérables ou mal configurés dans le cluster. Théoriquement, cela semble être une bonne approche, mais il y a plusieurs points à considérer avant de pouvoir le mettre en pratique :

  • Selon la largeur de bande du réseau, les ressources disponibles et le choix de l’analyseur, la recherche de vulnérabilités pour une image peut prendre un temps indéterminé. Cela peut entraîner des temps de démarrage des pods plus lents ou imprévisibles, ce qui peut entraîner des pics d’indisponibilité lorsque les applications sont soumises à une charge maximale.
  • Si la politique qui permet ou refuse le démarrage du pod est basée sur des données incorrectes ou incomplètes, cela peut entraîner plusieurs résultats faux positifs ou faux négatifs, par exemple :
    • Dans une image de conteneur, le package openssl est détecté comme vulnérable. Cependant, l’application est écrite en Go et utilise le package crypto Go pour TLS. Par conséquent, cette vulnérabilité n’est pas dans le chemin d’exécution du code et n’a donc qu’un impact minimal si elle reste non corrigée.
    • Une vulnérabilité est détectée dans le package openssl d’une image de base Debian. Cependant, la communauté Debian upstream considère cela comme une vulnérabilité de faible impact et ne publie donc pas de correctif pour cette vulnérabilité. Le propriétaire de cette image se retrouve désormais avec une vulnérabilité qui ne peut pas être corrigée et un cluster qui n’autorise pas l’exécution de l’image en raison d’une politique prédéfinie qui ne tient pas compte de la disponibilité ou non d’une correction pour une vulnérabilité.
    • Une application Go est construite sur une image distroless, mais elle est compilée avec une version Go qui utilise une bibliothèque standard vulnérable. L’analyseur n’a pas de visibilité sur la version de Go mais seulement sur les packages au niveau du système d’exploitation. Il autorise donc le pod à s’exécuter dans le cluster malgré la présence d’une image contenant un binaire d’application construit sur un Go vulnérable.

Il est clair que s’appuyer sur des analyseurs de vulnérabilités est une bonne idée, mais les définitions des politiques doivent être suffisamment flexibles pour permettre :

  • La création de listes d’exceptions pour les images ou les vulnérabilités grâce à l’utilisation d’étiquettes.
  • Le remplacement de la gravité par un score de risque basé sur l’impact d’une vulnérabilité.
  • L’application des mêmes politiques au moment de la construction pour détecter les images vulnérables avec des vulnérabilités corrigibles avant leur déploiement dans les clusters Kubernetes.

Des considérations spécifiques, telles que le téléchargement hors ligne de la base de données des vulnérabilités, peuvent également être nécessaires si les clusters fonctionnent dans un environnement déconnecté et que les analyseurs nécessitent un accès à Internet pour mettre à jour la base de données des vulnérabilités.

Politiques de sécurité des pods

Depuis Kubernetes v1.21, l’API PodSecurityPolicy et les fonctionnalités associées sont obsolètes, mais une partie des recommandations de cette section s’appliquera encore pendant les prochaines années, jusqu’à ce que les opérateurs de clusters mettent à niveau leurs clusters vers des versions plus récentes de Kubernetes.

Le projet Kubernetes travaille sur un remplacement pour PodSecurityPolicy. Kubernetes v1.22 inclut une fonctionnalité alpha appelée Pod Security Admission qui vise à permettre d’imposer un niveau minimal d’isolement entre les pods.

Les niveaux d’isolement intégrés de Pod Security Admission sont dérivés des standards de sécurité des pods, qui constituent un surensemble de tous les composants mentionnés dans le tableau I de la page 10 du guide.

Des informations sur la migration de PodSecurityPolicy vers la fonctionnalité Pod Security Admission intégrée sont disponibles dans le document “Migrate from PodSecurityPolicy to the Built-In PodSecurity Admission Controller”.

Un comportement important mentionné dans le guide et qui reste le même entre Pod Security Policy et son remplacement est que l’application de l’un ou l’autre de ces mécanismes n’affecte pas les pods déjà en cours d’exécution. Avec PodSecurityPolicy et Pod Security Admission, l’application des règles se fait lors de la création des pods.

Renforcement des moteurs de conteneur

Certaines charges de travail de conteneurs sont moins fiables que d’autres mais peuvent avoir besoin de s’exécuter dans le même cluster. Dans ces cas, les exécuter sur des nœuds dédiés incluant des moteurs de conteneur renforcés, offrant des limites d’isolation des pods plus strictes, peut constituer un contrôle de sécurité utile.

Kubernetes prend en charge une API appelée RuntimeClass qui est stable / GA (et donc activée par défaut) depuis Kubernetes v1.20. RuntimeClass vous permet de vous assurer que les pods nécessitant une isolation renforcée sont planifiés sur des nœuds qui peuvent l’offrir.

Certains projets tiers que vous pouvez utiliser conjointement avec RuntimeClass sont :

  • kata containers
  • gvisor

Comme discuté ici et dans le guide, de nombreuses fonctionnalités et outils existent dans et autour de Kubernetes qui peuvent améliorer les limites d’isolation entre les pods. En fonction des menaces pertinentes et de la posture de risque, vous devriez les choisir au lieu de tenter d’appliquer toutes les recommandations. Cependant, l’isolement au niveau du cluster, c’est-à-dire l’exécution de charges de travail dans des clusters dédiés, reste le mécanisme d’isolement des charges de travail le plus strict, malgré les améliorations mentionnées précédemment ici et dans le guide.

Séparation et renforcement du réseau

Le réseau Kubernetes peut être délicat, et cette section met l’accent sur la façon de sécuriser et de renforcer les configurations pertinentes. Le guide identifie les points clés suivants :

  • Utilisation des NetworkPolicies pour créer une isolation entre les ressources.
  • Sécurisation du plan de contrôle.
  • Chiffrement du trafic et des données sensibles.

Network Policies

Les policies réseau peuvent être créées à l’aide de plugins réseau. Afin de faciliter la création et la visualisation pour les utilisateurs, Cilium propose un outil GUI web. Cette interface web vous permet de créer des NetworkPolicies Kubernetes (une API générique qui nécessite néanmoins un plugin CNI compatible) et/ou des policies de réseau Cilium (CiliumClusterwideNetworkPolicy et CiliumNetworkPolicy, qui ne fonctionnent que dans les clusters qui utilisent le plugin Cilium CNI). Vous pouvez utiliser ces APIs pour restreindre le trafic réseau entre les pods et, par conséquent, réduire le vecteur d’attaque.

Un autre scénario intéressant à explorer est l’utilisation des adresses IP externes. Certains services, lorsqu’ils sont mal configurés, peuvent créer des adresses IP externes aléatoires. Un attaquant peut exploiter cette mauvaise configuration et intercepter facilement le trafic. Cette vulnérabilité a été signalée dans CVE-2020-8554. L’utilisation de l’externalip-webhook peut atténuer cette vulnérabilité en empêchant les services d’utiliser des adresses IP externes aléatoires. externalip-webhook permet uniquement de créer des services qui n’ont pas besoin d’adresses IP externes ou dont les adresses IP externes se trouvent dans la plage spécifiée par l’administrateur.

CVE-2020-8554 – Le serveur API Kubernetes dans toutes les versions permet à un attaquant capable de créer un service ClusterIP et de définir le champ spec.externalIPs, d’intercepter le trafic vers cette adresse IP. De plus, un attaquant capable de mettre à jour le statut d’un service LoadBalancer (ce qui est considéré comme une opération privilégiée et ne devrait normalement pas être accordé aux utilisateurs) peut également le faire.

Politiques de ressources

En plus de la configuration des quotas de ressources et des limites, il convient de limiter le nombre d’identifiants de processus (PIDs) qu’un pod donné peut utiliser et de réserver certains PIDs pour une utilisation au niveau du nœud afin d’éviter l’épuisement des ressources. Vous trouverez plus de détails sur l’application de ces limites dans Process ID Limits And Reservations.

Renforcement du plan de contrôle

Dans la section suivante, le guide aborde le renforcement du plan de contrôle. Il est important de noter que, à partir de Kubernetes 1.20, le port non sécurisé de l’API server a été supprimé.

Etcd

En règle générale, le serveur etcd doit être configuré pour faire confiance uniquement aux certificats attribués au serveur API. Cela limite la surface d’attaque et empêche un attaquant malveillant d’accéder au cluster. Il peut également être bénéfique d’utiliser une autorité de certification distincte pour etcd, car par défaut, il fait confiance à tous les certificats émis par l’autorité de certification racine.

Fichiers kubeconfig

En plus de spécifier le token et les certificats directement, le fichier .kubeconfig prend en charge la récupération dynamique des jetons temporaires à l’aide de plugins d’authentification. Méfiez-vous de la possibilité d’exécution de code shell malveillant dans un fichier kubeconfig. Une fois que les attaquants ont accès au cluster, ils peuvent voler des clés SSH/des secrets ou plus encore.

Secrets

Les Secrets Kubernetes sont la manière native de gérer les secrets en tant qu’objet API Kubernetes. Cependant, dans certains scénarios, tels que le désir d’avoir une seule source de vérité pour tous les secrets d’application, qu’ils s’exécutent sur Kubernetes ou non, les secrets peuvent être gérés de manière non liée à Kubernetes et consommés par les pods via des side-cars ou des init-containers, avec une utilisation minimale de l’API Secrets Kubernetes.

Des fournisseurs de secrets externes et csi-secrets-store sont quelques-unes de ces alternatives aux Secrets Kubernetes.

Audit des journaux

Le guide NSA/CISA met l’accent sur la surveillance et l’alerte basée sur les journaux. Les points clés comprennent le journalisation au niveau de l’hôte, au niveau de l’application et sur le cloud. Lorsque vous utilisez Kubernetes en production, il est important de comprendre qui est responsable et qui est responsable de chaque couche de journalisation.

Audit de l’API Kubernetes

Un domaine qui mérite davantage d’attention est ce qui devrait exactement déclencher une alerte ou être enregistré dans les journaux. Le document propose une politique d’audit type dans l’annexe L: Audit Policy, qui enregistre tous les RequestResponse, y compris les métadonnées et les corps de demande/réponse. Bien que cela puisse être utile pour une démo, cela peut ne pas être pratique en production.

Chaque organisation doit évaluer son propre modèle de menace et créer une politique d’audit qui complète ou facilite la résolution des problèmes en cas d’incident. Réfléchissez à la façon dont quelqu’un pourrait attaquer votre organisation et quel journal d’audit pourrait l’identifier. Vous pouvez consulter des options plus avancées pour ajuster les journaux d’audit dans la documentation officielle sur l’audit. Il est crucial de régler vos journaux d’audit pour n’inclure que les événements correspondant à votre modèle de menace. Une politique d’audit minimale qui enregistre tout au niveau des métadonnées peut également constituer un bon point de départ.

Les configurations de journalisation d’audit peuvent également être testées avec kind en suivant ces instructions.

Flux de journaux et audit en continu

La journalisation est importante pour la détection des menaces et des anomalies. Comme le précise le guide, il est préférable de scanner et d’alerter sur les journaux en temps réel et de protéger les journaux contre les altérations en cas de compromission. Il est important de réfléchir aux différents niveaux de journalisation et d’identifier les zones critiques telles que les points d’API.

L’audit des journaux de l’API Kubernetes peut être diffusé vers un webhook, et un exemple est donné dans l’annexe N: Configuration du webhook. L’utilisation d’un webhook pourrait être une méthode permettant de stocker les journaux hors cluster et/ou de centraliser tous les journaux d’audit. Une fois que les journaux sont gérés de manière centralisée, recherchez la possibilité d’activer des alertes en fonction des événements critiques. Assurez-vous également de comprendre quelle est la référence pour les activités normales.

Identification des alertes

Bien que le guide souligne l’importance des notifications, il n’existe pas de liste d’événements à alerter de manière générale. Les exigences en matière d’alerte varient en fonction de vos propres besoins et de votre modèle de menace. Voici quelques exemples d’événements :

  • Modifications du securityContext d’un Pod
  • Mises à jour des configurations des contrôleurs d’admission
  • Accès à certains fichiers/URL

Ressources supplémentaires sur la journalisation

  • Seccomp Security Profiles and You: A Practical Guide – Duffie Cooley
  • TGI Kubernetes 119: Gatekeeper and OPA
  • Abusing The Lack of Kubernetes Auditing Policies
  • Enable seccomp for all workloads with a new v1.22 alpha feature
  • This Week in Cloud Native: Auditing / Pod Security

Pratiques de mise à niveau et de sécurité des applications

Kubernetes publie trois versions par an, ce qui implique un travail lié à la mise à niveau pour les personnes utilisant des clusters de production. En plus de cela, les opérateurs doivent régulièrement mettre à niveau le système d’exploitation sous-jacent des nœuds et les applications en cours d’exécution. Il s’agit d’une meilleure pratique pour garantir une assistance continue et réduire la probabilité de bugs ou de vulnérabilités.

Kubernetes prend en charge les trois versions stables les plus récentes. Bien que chaque version de Kubernetes soit soumise à un grand nombre de tests avant d’être publiée, certaines équipes ne se sentent pas à l’aise de fonctionner avec la dernière version stable tant qu’un certain temps ne s’est pas écoulé. Peu importe la version que vous utilisez, assurez-vous que les mises à jour de correctifs sont fréquentes ou automatiques. Vous trouverez plus d’informations dans les pages de la politique de désynchronisation des versions.

Lorsque vous réfléchissez à la manière dont vous gérerez les mises à niveau du système d’exploitation des nœuds, envisagez de mettre en place des nœuds éphémères. Avoir la possibilité de détruire et d’ajouter des nœuds permet à votre équipe de réagir plus rapidement aux problèmes de nœuds. De plus, le fait d’avoir des déploiements capables de tolérer l’instabilité des nœuds (et une culture qui encourage des déploiements fréquents) permet de faciliter les mises à niveau des clusters.

De plus, il convient de souligner, à partir du guide, que des analyses de vulnérabilités périodiques et des tests de pénétration peuvent être effectués sur les différents composants du système pour rechercher proactivement des configurations non sécurisées et des vulnérabilités.

Recherche d’informations sur les versions et la sécurité

Pour trouver les versions de Kubernetes supportées les plus récentes, consultez https://k8s.io/releases, qui inclut les versions mineures. Il est bon de rester à jour avec les correctifs mineurs de votre version.

Si vous utilisez une offre Kubernetes gérée, recherchez leur documentation de version et trouvez leurs différents canaux de sécurité.

Abonnez-vous à la liste de diffusion Kubernetes Announce. Cette liste de diffusion est consultable pour des termes tels que “Security Advisories”. Vous pouvez configurer des alertes et des notifications par e-mail tant que vous savez sur quels mots clés alerter.

Conclusion

En conclusion, il est fantastique de voir des praticiens de la sécurité partager un niveau de détail si poussé dans le domaine public. Ce guide souligne davantage l’adoption généralisée de Kubernetes et la nécessité continue de se concentrer sur la sécurisation des clusters Kubernetes et des conteneurs d’application qui s’y exécutent. Quelques semaines seulement après la publication du guide, un outil open source appelé kubescape, qui permet de valider un cluster par rapport à ce guide, est devenu disponible.

Cet outil peut être un excellent point de départ pour vérifier l’état actuel de vos clusters, après quoi vous pouvez utiliser les informations de ce billet de blog et du guide pour évaluer les améliorations qui peuvent être apportées.

Enfin, il convient de souligner que toutes les mesures de contrôle de ce guide ne seront pas pertinentes pour tous les praticiens. La meilleure façon de savoir quelles mesures de contrôle sont importantes est de se fier au modèle de menace de votre propre environnement Kubernetes.

Un merci spécial à Rory McCune (@raesene) pour ses contributions à ce billet de blog.