Introduction
Les commandes de contexte de sécurité Kubernetes sont fondamentales pour exécuter des charges de travail avec le moindre privilège. Un contexte de sécurité définit les paramètres de privilèges et de contrôle d'accès pour un Pod ou un conteneur, notamment les identifiants d'utilisateur et de groupe, les capacités Linux, les profils seccomp et les options SELinux. Ce guide fournit des commandes et des exemples pratiques pour aider les opérateurs, les développeurs et les ingénieurs DevOps à configurer et vérifier les contextes de sécurité de manière sûre et efficace.
L'objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des variables fictives plutôt que des secrets, vérifier le résultat et documenter comment récupérer si l'état attendu n'est pas atteint. À la fin de cet article, vous serez en mesure d'inspecter les contextes de sécurité actuels, d'appliquer les paramètres appropriés et de résoudre les problèmes courants en toute confiance.
Inventaire de la version et de l'environnement
Avant de modifier un contexte de sécurité, vous devez comprendre votre environnement et son état actuel. Cette section explique comment inventorier votre cluster, identifier les composants pertinents et vérifier la version de Kubernetes.
Étape 1 : Vérifier la version de Kubernetes et la prise en charge de l'API
Les champs de contexte de sécurité ont évolué au fil des versions de Kubernetes. Confirmez toujours la version de votre cluster et la disponibilité de l'API avant d'appliquer des manifestes.
kubectl version --short
Exemple de sortie :
Client Version: v1.28.2
Server Version: v1.28.3
Notes de compatibilité clés :
runAsUser,runAsGroup,fsGroupetsupplementalGroupssont stables et disponibles dans toutes les versions prises en charge.seccompProfileest devenu GA en v1.19 ; utilisezsecurityContext.seccompProfile.typeplutôt que des annotations.allowPrivilegeEscalationest stable ; définissez-le àfalsechaque fois que possible.- Le champ
capabilitiesest stable ; préférez la listedropàadd. windowsOptionsconcerne les conteneurs Windows (par exemple,runAsUserName).
Étape 2 : Inventorier les contextes de sécurité existants
Avant de modifier quoi que ce soit, observez les Pods existants et leurs paramètres de sécurité. Cette étape en lecture seule vous aide à comprendre la posture de risque actuelle.
Listez tous les Pods avec une sortie large pour voir le placement des nœuds et l'état :
kubectl get pods -A -o wide
Pour inspecter le contexte de sécurité complet d'un Pod spécifique, utilisez kubectl get avec une sortie YAML ou JSON. Par exemple, pour afficher le contexte de sécurité d'un Pod nommé nginx-secure dans l'espace de noms default :
kubectl get pod nginx-secure -n default -o yaml
Recherchez la section securityContext au niveau du Pod et du conteneur. Voici un extrait d'un Pod avec un contexte restrictif :
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: nginx
image: nginx:1.25
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
runAsNonRoot: true
runAsUser: 1000
Vous pouvez également utiliser kubectl describe pour voir les événements et repérer rapidement les problèmes liés à la sécurité, comme un Pod qui ne démarre pas à cause d'un utilisateur non root ou de capacités manquantes.
Étape 3 : Vérifier les prérequis
Les contextes de sécurité dépendent du runtime de conteneur et des fonctionnalités du système d'exploitation. Assurez-vous que :
- Le runtime de conteneur (containerd, CRI-O) prend en charge les champs que vous comptez utiliser.
- Si vous utilisez des profils seccomp, le fichier de profil est présent sur le nœud ou chargé en tant que ressource personnalisée.
- Les politiques SELinux ou AppArmor sont alignées avec vos paramètres.
- Le compte de service du Pod a la permission pour toutes les ressources supplémentaires, bien que les modifications du contexte de sécurité ne nécessitent pas de RBAC supplémentaire.
Une vérification rapide du support seccomp :
kubectl get nodes -o jsonpath='{.items[*].metadata.name}' | xargs -I {} kubectl get node {} -o jsonpath='{.status.nodeInfo.containerRuntimeVersion}' && echo
Exemple de sortie : containerd://1.7.2
Chemin de configuration sûr
Maintenant que vous avez observé l'environnement, vous pouvez effectuer des modifications minimes et justifiées. Cette section fournit des exemples concrets pour les configurations de contexte de sécurité courantes, en mettant l'accent sur une approche de moindre privilège.
Principes généraux
- Appliquez un changement à la fois.
- Définissez toujours
runAsNonRoot: truesauf si le conteneur a réellement besoin de root. - Utilisez des identifiants
runAsUseretrunAsGroupspécifiques pour éviter de dépendre des valeurs par défaut de l'image. - Supprimez toutes les capacités et n'ajoutez que celles qui sont nécessaires.
- Définissez
allowPrivilegeEscalation: false. - Utilisez un profil seccomp par défaut du runtime (
RuntimeDefault) comme base ; envisagez un profil personnalisé pour un contrôle plus strict. - Évitez les conteneurs privilégiés ; si c'est inévitable, définissez
privileged: falsepartout ailleurs.
Exemple 1 : Exécuter en tant qu'utilisateur non root
Une exigence stricte courante : le conteneur ne doit pas s'exécuter en tant que root. Créez un manifeste de Pod avec un contexte de sécurité qui définit un utilisateur non root.
Enregistrez le fichier suivant sous nonroot-pod.yaml :
apiVersion: v1
kind: Pod
metadata:
name: nonroot-demo
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
containers:
- name: app
image: alpine:3.19
command: ["sleep", "3600"]
securityContext:
allowPrivilegeEscalation: false
Appliquez-le :
kubectl apply -f nonroot-pod.yaml
Sortie attendue :
pod/nonroot-demo created
Vérifiez que le Pod est en cours d'exécution et que les processus du conteneur ne sont pas root :
kubectl exec nonroot-demo -- id
Sortie attendue (si l'utilisateur 1000 existe dans le conteneur) :
uid=1000 gid=3000 groups=3000,2000
Si l'image ne définit pas l'utilisateur 1000, le conteneur peut échouer avec container has runAsNonRoot and image will run as root, ce qui indique que vous devez choisir une image de base différente ou créer l'utilisateur dans l'image.
Exemple 2 : Supprimer toutes les capacités et n'ajouter que celles nécessaires
Les capacités Linux accordent des privilèges fins. Supprimer toutes les capacités et n'ajouter que celles nécessaires réduit les risques.
Créez capabilities-pod.yaml :
apiVersion: v1
kind: Pod
metadata:
name: capabilities-demo
spec:
containers:
- name: net-admin
image: alpine:3.19
command: ["sleep", "3600"]
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
Appliquez et vérifiez :
kubectl apply -f capabilities-pod.yaml
kubectl exec capabilities-demo -- capsh --print | grep Current
La sortie attendue montre uniquement les capacités autorisées, y compris net_bind_service.
Exemple 3 : Appliquer un profil seccomp
Seccomp restreint les appels système. Commencez par le défaut du runtime, puis envisagez un profil personnalisé.
Seccomp au niveau du Pod (s'applique à tous les conteneurs) :
apiVersion: v1
kind: Pod
metadata:
name: seccomp-demo
spec:
securityContext:
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: alpine:3.19
command: ["sleep", "3600"]
Pour un profil personnalisé plus strict, créez un profil Localhost sur le nœud. Exemple de profil refusant chmod :
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": ["chmod", "fchmod", "fchmodat"],
"action": "SCMP_ACT_ERRNO"
}
]
}
Enregistrez-le sous custom-seccomp.json sur le nœud, puis référencez-le :
securityContext:
seccompProfile:
type: Localhost
localhostProfile: custom-seccomp.json
Appliquez et testez en tentant chmod à l'intérieur du conteneur ; cela devrait échouer avec Operation not permitted.
Étape 4 : Vérifier après application
Après chaque modification, vérifiez que le Pod démarre et se comporte comme prévu. Utilisez kubectl get pods pour vérifier l'état, kubectl describe pour les événements et kubectl logs pour les erreurs d'application. Pour un test fonctionnel rapide, utilisez kubectl exec pour exécuter des commandes à l'intérieur du conteneur.
Pour les déploiements, utilisez kubectl rollout status pour vous assurer que le déploiement se termine :
kubectl rollout status deployment/nginx-secure -n default
Sortie attendue : deployment "nginx-secure" successfully rolled out
Vérification et diagnostics
Cette section explique comment vérifier que les contextes de sécurité fonctionnent comme prévu et comment diagnostiquer les problèmes lorsqu'ils ne le font pas.
Vérifier les paramètres de sécurité réels au moment de l'exécution
Vous pouvez inspecter le contexte de sécurité effectif d'un conteneur en cours d'exécution en regardant les attributs de processus ou en utilisant kubectl exec pour interroger l'environnement.
Par exemple, pour vérifier l'utilisateur et les groupes :
kubectl exec -it nonroot-demo -- id
Sortie attendue : uid=1000 gid=3000 groups=2000 (ou similaire, selon l'image).
Pour vérifier les capacités à l'intérieur du conteneur, utilisez capsh (peut nécessiter une installation) :
kubectl exec capabilities-demo -- capsh --print
Recherchez la ligne de capacités Current:.
Pour vérifier le mode seccomp, utilisez kubectl get pod avec JSONPath ou inspectez le runtime de conteneur. Par exemple :
kubectl get pod seccomp-demo -o jsonpath='{.spec.securityContext.seccompProfile.type}'
Sortie attendue : RuntimeDefault
Diagnostiquer les échecs courants
1. Le conteneur échoue avec CreateContainerConfigError
Souvent causé par des champs de contexte de sécurité invalides. Utilisez kubectl describe pod <nom> pour voir l'événement. Erreur courante : invalid value: 0: must be greater than or equal to 1 pour runAsUser. Corrigez en définissant un UID valide.
2. Pod bloqué dans ContainerCreating ou CrashLoopBackOff
Peut être dû à un profil seccomp introuvable. Vérifiez les événements :
kubectl describe pod seccomp-demo
Recherchez : cannot load seccomp profile. Corrigez en vous assurant que le fichier de profil existe sur le nœud et a les bonnes permissions.
3. Permission refusée à l'intérieur du conteneur malgré le non-root
Si le conteneur ne peut pas écrire sur un volume, assurez-vous que fsGroup est défini sur le groupe propriétaire du volume, ou utilisez un groupe supplémentaire. Par exemple :
securityContext:
fsGroup: 2000
runAsUser: 1000
runAsGroup: 3000
supplementalGroups: [2000]
4. La liaison réseau échoue
Si l'application doit se lier à un port inférieur à 1024, ajoutez la capacité NET_BIND_SERVICE comme montré précédemment. Alternativement, configurez l'application pour utiliser un port plus élevé.
5. Le conteneur ne peut pas utiliser setuid ou effectuer des opérations privilégiées
C'est attendu lorsque allowPrivilegeEscalation: false et que les capacités sont supprimées. Si c'est vraiment nécessaire, ajoutez la capacité spécifique, mais préférez modifier l'application pour l'éviter.
Journalisation et surveillance
Les échecs de contexte de sécurité apparaissent souvent dans les journaux du conteneur ou les événements. Utilisez kubectl logs --previous pour voir les derniers journaux d'un conteneur planté :
kubectl logs nonroot-demo --previous
Pour une surveillance continue, envisagez de mettre en place une journalisation d'audit ou un moteur de politique comme OPA Gatekeeper ou Kyverno pour appliquer les contextes de sécurité.
Modes de défaillance et récupération
Même avec une planification minutieuse, les choses peuvent mal tourner. Cette section décrit les scénarios de défaillance courants, leurs symptômes et les étapes de récupération.
Scénario 1 : Le Pod refuse de démarrer en raison du contexte de sécurité
Symptôme : L'état du Pod est CreateContainerConfigError ou Error.
Diagnostic : Exécutez kubectl describe pod <nom> et recherchez les événements indiquant des valeurs de champs invalides, un profil seccomp manquant ou des options non prises en charge.
Récupération : Modifiez le Pod ou le déploiement pour corriger le contexte de sécurité. Par exemple, si runAsUser: 0 avec runAsNonRoot: true, changez runAsUser pour un UID non nul ou supprimez runAsNonRoot. Ensuite, supprimez et recréez le Pod (ou déployez le déploiement).
Scénario 2 : L'application échoue à l'exécution en raison de permissions manquantes
Symptôme : Le conteneur démarre mais l'application se termine avec des erreurs de permission ou plante.
Diagnostic : Vérifiez les journaux du conteneur avec kubectl logs <pod>. Recherchez des messages comme « permission denied » ou « operation not permitted ».
Récupération : Déterminez quel changement de capacité ou d'utilisateur est nécessaire. Accordez le privilège supplémentaire minimal. Par exemple, si l'application a besoin de modifier l'heure système, ajoutez la capacité SYS_TIME. Mettez à jour le manifeste et appliquez.
Scénario 3 : Le déploiement d'un changement de contexte de sécurité provoque une interruption
Symptôme : Après la mise à jour d'un déploiement avec un nouveau contexte de sécurité, les nouveaux Pods échouent et les anciens Pods sont terminés, laissant aucune réplique disponible.
Diagnostic : Vérifiez kubectl rollout status deployment/<nom> pour le message d'échec. Inspectez les nouveaux Pods avec kubectl describe et kubectl logs.
Récupération : Revenez immédiatement à la révision précédente :
kubectl rollout undo deployment/nginx-secure
Ensuite, déboguez le problème dans un espace de noms séparé ou avec un seul Pod avant de réappliquer.
Scénario 4 : Le profil seccomp bloque les appels système requis
Symptôme : Le conteneur échoue avec une erreur (souvent EPERM ou EACCES) sur une opération spécifique.
Diagnostic : Vérifiez les journaux de l'application ou utilisez strace si disponible. Vérifiez également le profil seccomp appliqué : kubectl get pod <nom> -o jsonpath='{.spec.securityContext.seccompProfile}'.
Récupération : Modifiez le profil seccomp personnalisé pour autoriser l'appel système nécessaire, ou passez temporairement à RuntimeDefault pour les tests. Rechargez le profil et redémarrez le Pod.
Bonnes pratiques générales de récupération
- Ayez toujours un plan de retour en arrière : utilisez des manifestes versionnés, GitOps, ou au moins
kubectl rollout undo. - Testez les changements dans un environnement de préproduction d'abord.
- Gardez une sauvegarde de la spécification du Pod d'origine :
kubectl get pod <nom> -o yaml > pod-backup.yamlavant de le modifier. - Documentez la défaillance et la récupération dans votre manuel d'exploitation.
Liste de contrôle des opérations
Utilisez la liste de contrôle suivante avant et après avoir modifié les contextes de sécurité en production.
Avant d'appliquer les changements
- [ ] Confirmez que la version de Kubernetes prend en charge les champs de contexte de sécurité que vous prévoyez d'utiliser.
- [ ] Vérifiez le contexte de sécurité actuel :
kubectl get pod <nom> -o yaml. - [ ] Identifiez l'utilisateur et le groupe d'exécution du conteneur :
kubectl exec <pod> -- id(s'il est en cours d'exécution). - [ ] Listez les capacités actuelles :
kubectl exec <pod> -- capsh --print(si disponible). - [ ] Vérifiez l'état du profil seccomp :
kubectl get pod <nom> -o jsonpath='{.spec.securityContext.seccompProfile}'. - [ ] Sauvegardez le YAML du Pod/Déploiement :
kubectl get <ressource> <nom> -o yaml > backup.yaml. - [ ] Déterminez les privilèges minimaux requis (utilisateur, capacités, etc.) en consultant la documentation de l'application ou en testant localement.
- [ ] Préparez une commande de retour en arrière :
kubectl rollout undo deployment/<nom>ou gardez le YAML d'origine prêt. - [ ] Informez les membres de l'équipe concernés de la fenêtre de changement.
Après avoir appliqué les changements
- [ ] Vérifiez l'état du Pod :
kubectl get pods -n <namespace> -o wide. - [ ] Vérifiez que le contexte de sécurité est correctement défini :
kubectl get pod <nom> -o yaml | grep -A10 securityContext. - [ ] Confirmez que le conteneur s'exécute avec l'utilisateur attendu :
kubectl exec <pod> -- id. - [ ] Validez les capacités :
kubectl exec <pod> -- capsh --print(si disponible). - [ ] Vérifiez les journaux de l'application pour les erreurs :
kubectl logs <pod>. - [ ] Testez les fonctionnalités critiques (par exemple, un contrôle de santé HTTP).
- [ ] Surveillez pendant quelques minutes :
kubectl get pods -w. - [ ] Mettez à jour la documentation et les manuels d'exploitation avec la nouvelle configuration.
- [ ] Supprimez tous les outils de diagnostic ou permissions temporaires.
Exemple de liste de contrôle remplie pour une charge de travail réelle
Supposons que vous sécurisez un déploiement Nginx dans l'espace de noms web.
- État actuel : Pod
nginx-6d4b7c9f8-abcdes'exécutant en tant que root, pas de seccomp, toutes les capacités. - État souhaité : S'exécuter en tant qu'UID 1000, supprimer toutes les capacités, seccomp RuntimeDefault.
- Sauvegarde :
kubectl get deployment nginx -n web -o yaml > nginx-deployment-backup.yaml. - Appliquer le changement : Modifiez le déploiement pour ajouter le contexte de sécurité.
- Déploiement :
kubectl rollout status deployment/nginx -n web. - Vérifier :
kubectl exec -n web <nouveau-pod> -- idrenvoieuid=1000. - Tester :
curlle service ; attendez un HTTP 200. - Retour en arrière si nécessaire :
kubectl rollout undo deployment/nginx -n web.
Gardez cette liste de contrôle comme modèle et adaptez-la à votre flux de travail.
Conclusion
Les commandes de contexte de sécurité Kubernetes sont essentielles pour durcir vos charges de travail. En suivant une approche structurée—inventorier l'environnement, apporter des modifications minimes, vérifier les résultats et planifier la récupération—vous pouvez réduire la surface d'attaque sans sacrifier la fonctionnalité.
Commencez par les bases : exécutez les conteneurs en tant que non-root, supprimez les capacités inutiles et appliquez un profil seccomp. Utilisez les commandes et les exemples de ce guide pour inspecter et ajuster vos contextes de sécurité en toute sécurité. Rappelez-vous que la sécurité est un processus continu ; examinez régulièrement vos configurations et restez à jour avec les versions de Kubernetes.
Pour en savoir plus, explorez la documentation Kubernetes sur les normes de sécurité des Pods, l'admission de sécurité des Pods et des outils comme kube-bench pour auditer la posture de sécurité de votre cluster.