Kubernetes : qu’est-ce qui va remplacer les PodSecurityPolicies ?
Pour appliquer la sécurité sur Kubernetes, il est nécessaire d’appliquer des bonnes pratiques :
- Sur les images
- Sur vos descripteurs de déploiement
- Sur votre cluster
- Sur les machines du cluster
Dans cet article, nous vous proposons de découvrir les Pod Security Standards qui sont en bêta depuis la version 1.23 de Kubernetes et qui ont pour objectif de remplacer les Pod Security Policies.
Si vous souhaitez creuser l’aspect application de politique de sécurité sur les descripteurs de déploiement que vous appliquez sur Kubernetes, cet article est fait pour vous !
Introduction
Nous commencerons par une présentation du principe des Pod Security Policies, suivi de quelques rappels sur le principe des Admission Controllers Kubernetes.
Nous verrons alors les problèmes liés aux Pod Security Policies qui ont mené à leur dépréciation.
Nous pourrons alors introduire la notion de Pod Security Standards qui viennent les remplacer et découvrir leur fonctionnement à travers un exemple de mise en place.
Nous terminerons par quelques bonnes pratiques à appliquer lors de leur utilisation.
Principe des Pod Security Policies
Si vous déployez des applications sur Kubernetes, vous avez peut-être déjà utilisé la propriété securityContext dans vos descripteurs de Pod. Ce mécanisme permet d’ajouter des informations aux Pods et Deployment afin, notamment, de préciser l’utilisateur avec lequel le conteneur s’exécutera, si le conteneur est privilégié, si le processus principal du conteneur a besoin de capabilities Linux particulières, etc.
En revanche, ce procédé fonctionne sur la bonne volonté des personnes qui vont créer les descripteurs des applications à déployer sur le Cluster.
Pour garantir la sécurité, un mécanisme supplémentaire est nécessaire pour imposer certaines valeurs de configurations pour les propriétés du securityContext.
Ce mécanisme s’appuie sur un type de ressource particulier : Les PodSecurityPolicies (PSP).
Voici un exemple de PodSecurityPolicy qui interdit :
- d’exécuter des conteneurs en mode privilégié
- de monter des répertoires de l’hôte dans les conteneurs
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: example
spec:
privileged: false # Don't allow privileged pods!
seLinux:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
runAsUser:
rule: RunAsAny
fsGroup:
rule: RunAsAny
volumes:
- 'configMap'
- 'emptyDir'
- 'projected'
- 'secret'
- 'downwardAPI'
- 'persistentVolumeClaim'
# Don't allow to mount hostPath volume types and expose host dirs in
# containers
# - 'hostPath'
Pour valider ou interdire la création des Pods, l’API Server s’appuie sur le mécanisme des Admission Controller. Ce processus est visible dans l’étape “Validating admission” du schéma ci-dessous qui indique les différentes tâches exécutées par l’API Server Kubernetes sur les requêtes entrantes.
Ainsi parmi, la liste des Admission Controller, il en existe un qui porte le même nom que la ressource Pod Security Policy et qui sera chargée de valider la création d’un Pod en fonction des valeurs présentes dans le securityContext et des Pod Security Policies pour lesquels l’utilisateur courant a le droit “use”.
Problèmes des Pod Security Policies
Les Pod Security Policies ont été introduites en bêta dans la version v1.3 de Kubernetes. Elles sont restées pendant très longtemps en bêta car il était très difficile d’identifier leur portée et de stabiliser leur contenu. Par exemple, est-ce qu’il faut y inclure les types de volumes disponibles ? Toutes les propriétés des securityContext ? D’autres éléments du descripteur de Pod ?
Comment fait-on pour gérer les évolutions des descripteurs et d’éventuelles nouvelles propriétés liées à la sécurité ?
Les difficultés à trouver un consensus autour de ces questions ont amené le SIG Security à déprécier les Pod Security Policies au profit :
- D’un mécanisme plus simple et plus évolutif, mais moins configurable directement intégré à Kubernetes (Pod Security Standards)
- La possibilité de se baser sur des produits externes pour implémenter des politiques de sécurité plus complexes (Open Policy Agent / Gatekeeper)
L’ensemble de ces éléments est décrit dans le document produit par le SIG Security qui explique la dépréciation de cette ressource.
En avril 2021, le SIG Security a publié un article dévoilant le futur de la sécurité des Pods avec les Pod Security Standards. Ce mécanisme arrive en bêta dans la version 1.23 de Kubernetes, nous allons donc vous le présenter ainsi que sa mise en œuvre dans la suite de cet article.
Principe des Pod Security Standards
Les Pod Security Standards proposent trois profils de sécurité à appliquer aux Pods :
- Privilégié (privileged) : profil permissif, permettant notamment de monter des répertoires de la machine hôte, d’exécuter le conteneur en mode privilégié, …; ce profil est à réserver aux Pods systèmes ou d’infrastructure de votre cluster.
- De base (baseline) : profil de base, restreint au minimum, empêchant l’augmentation de privilèges et adapté pour les valeurs de configurations de Pods par défaut.
- Restreint (restricted) : profil fortement restreint, adapté lorsque vous souhaitez mettre en place un durcissement pour l’exécution de Pods
Pour avoir le détail complet par profil, vous pouvez vous référer à la documentation officielle.
Ces profils de sécurité s’appliqueront à la portée d’un Namespace. C’est-à-dire que Kubernetes appliquera le même profil pour tous les Pods du Namespace.
En pratique, pour appliquer ces profils de sécurité, Kubernetes va également s’appuyer sur un Admission Controller qui ira chercher une annotation particulière sur le namespace indiquant :
- Le profil de sécurité à appliquer au namespace
- Le mode d’action à adopter
Le mode d’action en cas de non-respect du profil sera à choisir parmi :
- warn : le client est alerté par un warning lors de la création de la ressource
- audit : une annotation est ajoutée sur l’événement d’audit de création du Pod
- enforce : la création du Pod échoue avec un message d’erreur
L’annotation à utiliser sera de la forme :
pod-security.kubernetes.io/<MODE>: <PROFIL>
Le plugin Pod Security de l’Admission Controller est disponible en alpha et derrière un feature gate à partir de la version 1.22 de Kubernetes. Pour l’activer il faudra donc ajouter un paramètre au lancement de l’API Server : --feature-gates="...,PodSecurity=true"
À partir de la version 1.23, la fonctionnalité est passée en bêta et est disponible par défaut.
Nous allons maintenant voir plus concrètement comment les mettre en place avec quelques exemples.
Exemple de mise en place
Avant de commencer nous pouvons vérifier que le cluster est bien, a minima, en version 1.23 :
$ kubectl version
[snip]
Server Version: version.Info{Major:"1", Minor:"23", [snip]
Pour tester les Pod Security Standards nous pouvons commencer par créer trois namespaces pour chacun des réglages disponibles, ainsi :
$ kubectl create namespace baseline
$ kubectl create namespace privileged
$ kubectl create namespace restricted
Ensuite nous ajoutons les labels correspondants aux policies, tels que documentés dans https://kubernetes.io/docs/concepts/security/pod-security-admission/#pod-security-admission-labels-for-namespaces , nous allons faire du enforce
mais il aussi possible de commencer par warn
(visible lors du kubectl) ou audit
(visible dans l’audit log, voir plus loin pour les détails) :
$ kubectl label namespaces baseline pod-security.kubernetes.io/enforce=baseline
$ kubectl label namespaces privileged pod-security.kubernetes.io/enforce=privileged
$ kubectl label namespaces restricted pod-security.kubernetes.io/enforce=restricted
Si vous souhaitez modifier un label existant il faut ajouter --overwrite=true
.
Pour lister les namespaces avec leurs labels, exécuter :
$ kubectl get namespace --label-columns=pod-security.kubernetes.io/enforce
NAME STATUS AGE ENFORCE
default Active 29h
kube-system Active 29h
kube-public Active 29h
kube-node-lease Active 29h
baseline Active 31s baseline
privileged Active 31s privileged
restricted Active 31s restricted
Nous pouvons ensuite déployer un pod demandant des accès privilégiés dans chaque namespace pour observer l’effet de ces Pod Security Standards, root-shell-pod.yaml :
kind: Pod
apiVersion: v1
metadata:
name: root-shell
spec:
containers:
- name: root-shell
image: debian
command: [ "bash", "-c", "sleep infinity" ]
securityContext:
privileged: true
Dans le namespace privileged, il est créé :
$ kubectl apply -f root-shell-pod.yaml -n privileged
pod/root-shell created
$ kubectl exec -n privileged root-shell – whoami
root
$ kubectl exec -n privileged root-shell – id
uid=0(root) gid=0(root) groups=0(root)
En baseline, il est refusé :
$ kubectl apply -f root-shell-pod.yaml -n baseline
Error from server (Forbidden): error when creating "shell-pod.yaml": pods "shell" is forbidden: violates PodSecurity "baseline:latest": privileged (container "shell" must not set securityContext.privileged=true)
En restricted, il est refusé avec encore plus d’explications :
$ kubectl apply -f root-shell-pod.yaml -n restricted
Error from server (Forbidden): error when creating "shell-pod.yaml": pods "shell" is forbidden: violates PodSecurity "restricted:latest": privileged (container "shell" must not set securityContext.privileged=true), allowPrivilegeEscalation != false (container "shell" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "shell" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "shell" must set securityContext.runAsNonRoot=true), runAsUser=0 (container "shell" must not set runAsUser=0), seccompProfile (pod or container "shell" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
Pour tester de manière plus poussée les capacités disponibles à vos Pods impactés par les Pod Security Standards vous pouvez jeter un oeil à amicontained https://github.com/genuinetools/amicontained
Mise en place et bonnes pratiques
Un premier élément à souligner est le fait que lors de la préparation de votre cluster, vous devriez déjà identifier des Namespaces destinés :
- Aux composants de Kubernetes
- Aux middleware complémentaires (Collecteurs de métriques et logs, Ingress controller, etc)
- Aux applications des utilisateurs
Vous devrez alors appliquer une politique de gestion des rôles afin de restreindre fortement les utilisateurs en mesure d’accéder et d’appliquer des modifications aux Namespaces réservés aux usages autres qu’applicatif. Vous pourrez alors appliquer un profil plus permissif pour ces Namespaces afin de faire en sorte que les composants qui le nécessitent puissent s’exécuter correctement.
Pour les autres Namespaces, l’objectif devrait être de viser le plus haut niveau de sécurité en équilibrant ce besoin avec les modifications nécessaires à appliquer à vos applications.
Que puis-je faire quand j’ai déjà un cluster Kubernetes en place qui applique peu de règles de sécurité ?
Dans ce cas, il est possible de définir le mode d’action à audit et d’outiller la collecte de ces journaux d’audits afin de se faire une idée claire des modifications à apporter pour atteindre un niveau de sécurité acceptable.
Conclusion
L’objectif des Pod Security Standards est de fournir un moyen plus simple de mettre en place une politique de sécurité à vos applications déployées sur Kubernetes afin d’éviter des problèmes de sécurité liés à une mauvaise configuration ou à un élément de configuration qui ne serait pas pris en charge lors d’une évolution de Kubernetes.
En revanche, cette évolution se fait au prix de la flexibilité et du périmètre couvert par cette fonctionnalité. Si vous souhaitez avoir la main de façon plus précise et plus large sur les politiques de sécurité à appliquer sur votre cluster Kubernetes, je vous invite à jeter un coup d’œil à Open Policy Agent et son déploiement dans Kubernetes avec GateKeeper.
Cet article a été co-écrit avec Arthur Lutz.