## Introduction Les erreurs de configuration de seccomp dans Kubernetes peuvent casser silencieusement des applications ou exposer des charges de travail à un risque inutile. Seccomp (secure computing mode) est une fonctionnalité du noyau Linux qui limite les appels système qu'un processus peut effectuer, offrant une couche de défense critique pour les conteneurs. Cependant, même les équipes de plateforme expérimentées trébuchent lorsqu'elles activent seccomp : un fichier de profil manquant sur un nœud empêchera les pods de démarrer, une politique trop restrictive peut faire planter une application à 3 h du matin, et un paramètre Unconfined passé inaperçu peut laisser un conteneur grand ouvert. Ce guide aide les praticiens à éviter les pièges les plus courants lors de l'activation et de la configuration de seccomp dans Kubernetes. Vous apprendrez à valider les profils, à implémenter les changements en toute sécurité, à vérifier l'application et à revenir en arrière si nécessaire. Chaque section comprend des commandes concrètes, des extraits de configuration et des sorties attendues afin que vous puissiez appliquer les conseils directement à vos propres clusters. En suivant les exemples pratiques et les listes de contrôle, vous pouvez intégrer seccomp à votre posture de sécurité en toute confiance et sans temps d'arrêt inutile. ## Inventaire des versions et de l'environnement Avant de configurer seccomp, comprenez vos versions de Kubernetes et du runtime de conteneurs, car le support et les valeurs par défaut varient considérablement d'une version à l'autre. Par exemple, seccomp est devenu généralement disponible dans Kubernetes 1.19, mais le champ seccompProfile dans le contexte de sécurité du pod est en version bêta depuis 1.19 et stable depuis 1.25. Le runtime de conteneurs compte également : containerd, CRI-O et Docker supportent tous seccomp, mais la façon de configurer les profils par défaut diffère. Sauter cette étape d'inventaire est une source fréquente de confusion lorsqu'un profil fonctionne sur un nœud mais échoue sur un autre. ### Prérequis - Cluster Kubernetes version 1.19 ou ultérieure (seccomp GA en 1.19 ; recommandé 1.25+ pour une API stable). - Runtime de conteneurs supportant seccomp : containerd 1.3+, CRI-O 1.17+ ou Docker 19.03+ avec une configuration appropriée. - Capacité à créer ou modifier des contextes de sécurité de pod et des profils seccomp. - Accès aux journaux du cluster et au système de fichiers des nœuds pour le débogage. - kubectl et jq installés sur votre poste de travail pour interroger les spécifications des pods. ### Vérifier la version de Kubernetes Exécutez la commande suivante pour vérifier la version du serveur Kubernetes : kubectl version --short Sortie attendue (exemple) : Client Version: v1.27.3 Server Version: v1.27.3 Si la version de votre serveur est inférieure à 1.19, seccomp n'est pas supporté de la même manière et vous devriez effectuer une mise à niveau avant de poursuivre. Si vous êtes entre 1.19 et 1.24, le champ seccompProfile est en version bêta et peut nécessiter l'activation d'une porte de fonctionnalité dans certaines distributions gérées ; vérifiez donc auprès de votre fournisseur. ### Vérifier le support de seccomp par le runtime de conteneurs Pour containerd, vérifiez la configuration du runtime. Sur un nœud, inspectez le fichier de configuration de containerd (généralement /etc/containerd/config.toml ). Assurez-vous que le profil seccomp par défaut est activé. Voici une section minimale pertinente : [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = true NoNewPrivileges = true # Seccomp est activé par défaut s'il n'est pas désactivé. Si vous voyez une ligne comme disable_seccomp = true , alors seccomp est désactivé pour tous les conteneurs utilisant ce runtime. Supprimez-la ou mettez-la à false et redémarrez containerd : sudo systemctl restart containerd Pour Docker, seccomp est activé par défaut avec le profil par défaut. Vous pouvez vérifier en exécutant un conteneur et en vérifiant son statut seccomp : docker info | grep seccomp Sortie attendue : Security Options: seccomp Profile: default ### Inventorier l'utilisation existante de seccomp Listez les pods avec des profils seccomp appliqués à l'aide d'un script personnalisé ou d'une inspection manuelle. Voici une méthode rapide utilisant kubectl et jq : kubectl get pods -A -o json | jq -r '.items[] | select(.spec.securityContext.seccompProfile != null) | .metadata.namespace + "/" + .metadata.name' Si aucun pod n'utilise seccomp, la sortie sera vide. Sinon, vous verrez une liste de pods avec des profils seccomp. Cet inventaire est utile pour comprendre votre exposition actuelle et pour planifier un déploiement. Vous pouvez également vérifier les contextes de sécurité au niveau des conteneurs, pas seulement au niveau du pod : kubectl get pods -A -o json | jq -r '.items[] | . as $pod | .spec.containers[]? | select(.securityContext.seccompProfile != null) | $pod.metadata.namespace + "/" + $pod.metadata.name + " (conteneur : " + .name + ")"' ## Chemin de configuration sécurisé Une approche d'implémentation ciblée minimise les risques. Commencez par une seule charge de travail dans un espace de noms hors production, en étendant progressivement après validation. Cette section décrit le processus étape par étape avec des exemples concrets. ### Comprendre les types de profils seccomp Kubernetes supporte trois types de profils seccomp : - RuntimeDefault : Utilise le profil seccomp par défaut du runtime de conteneurs. C'est le point de départ recommandé car il équilibre sécurité et compatibilité. Le profil par défaut bloque généralement environ 44 appels système et est maintenu par le projet du runtime. - Localhost : Utilise un fichier de profil personnalisé présent sur le nœud sous /var/lib/kubelet/seccomp/ . Cela donne un contrôle fin mais nécessite de gérer le fichier sur chaque nœud. - Unconfined : Désactive complètement seccomp. À éviter sauf en cas d'absolue nécessité car cela supprime la couche de filtrage des appels système. ### Étape 1 : Appliquer RuntimeDefault à un pod de test Créez un manifeste de pod simple test-pod.yaml : apiVersion: v1 kind: Pod metadata: name: seccomp-test spec: securityContext: seccompProfile: type: RuntimeDefault containers: - name: test image: busybox command: ["sleep", "3600"] Appliquez-le : kubectl apply -f test-pod.yaml Vérifiez que le pod fonctionne sans problème : kubectl get pod seccomp-test Résultat attendu : le statut du pod est Running . Si ce n'est pas le cas, vérifiez les événements avec kubectl describe pod seccomp-test pour diagnostiquer. Ce test simple confirme que le profil par défaut du runtime n'interfère pas avec votre charge de travail de base. ### Étape 2 : Créer un profil seccomp personnalisé Les profils personnalisés permettent un contrôle fin. Voici un exemple de profil custom-profile.json qui refuse l'appel système chmod tout en autorisant tout le reste par défaut : { "defaultAction": "SCMP_ACT_ALLOW", "architectures": [ "SCMP_ARCH_X86_64", "SCMP_ARCH_X86", "SCMP_ARCH_X32" ], "syscalls": [ { "names": ["chmod"], "action": "SCMP_ACT_ERRNO" } ] } Placez ce fichier sur chaque nœud du cluster à /var/lib/kubelet/seccomp/custom-profile.json . Assurez-vous que le fichier est lisible par le kubelet. En général, le kubelet s'exécute en tant que root, mais vérifiez les permissions avec : sudo chmod 644 /var/lib/kubelet/seccomp/custom-profile.json Si vous avez de nombreux nœuds, utilisez un outil de gestion de configuration comme Ansible, Puppet ou un DaemonSet pour distribuer le fichier. Une erreur courante est de placer le profil sur un seul nœud et de s'étonner ensuite que les pods ne parviennent pas à se planifier sur d'autres nœuds. Dans un cluster multi-nœuds, vous devez copier le fichier sur chaque nœud susceptible d'exécuter le pod. ### Étape 3 : Tester le profil personnalisé avec un pod Modifiez le manifeste du pod pour utiliser le profil localhost : apiVersion: v1 kind: Pod metadata: name: seccomp-custom-test spec: securityContext: seccompProfile: type: Localhost localhostProfile: custom-profile.json containers: - name: test image: busybox command: ["sleep", "3600"] Appliquez et testez : kubectl apply -f seccomp-custom-test.yaml kubectl exec -it seccomp-custom-test -- chmod 777 /tmp Sortie attendue : la commande chmod échoue avec Operation not permitted car l'appel système est bloqué. Le pod lui-même reste en cours d'exécution. Cela confirme que le profil personnalisé est bien appliqué. Par exemple : chmod: /tmp: Operation not permitted command terminated with exit code 1 ### Étape 4 : Étendre progressivement Après avoir validé le profil sur le pod de test, envisagez de l'appliquer à un ensemble de charges de travail similaires dans un espace de noms de staging. Surveillez les échecs avant de passer en production. Une approche pratique consiste à utiliser un sélecteur d'étiquette sur votre déploiement et à patcher le contexte de sécurité. Par exemple, si vous avez un déploiement nommé webapp dans l'espace de noms staging : kubectl patch deployment webapp -n staging -p '{"spec":{"template":{"spec":{"securityContext":{"seccompProfile":{"type":"RuntimeDefault"}}}}}}' Ensuite, surveillez le déploiement : kubectl rollout status deployment/webapp -n staging Si le déploiement réussit et que l'application se comporte normalement, vous pouvez remplacer RuntimeDefault par votre profil localhost personnalisé lors d'un patch ultérieur. Ayez toujours un plan de retour en arrière, que nous couvrons dans une section ultérieure.
Question rapide 1 sur 2 Quelle est la version de Kubernetes requise pour que seccomp soit généralement disponible ? - Kubernetes 1.19 - Kubernetes 1.25 - Kubernetes 1.27 - Kubernetes 1.31
La référence indique que seccomp est devenu généralement disponible dans Kubernetes 1.19.
## Vérification et diagnostics Vérifier que seccomp est appliqué et diagnostiquer les problèmes sont essentiels. Utilisez les techniques suivantes. ### Vérifier le contexte de sécurité du pod Inspectez le contexte de sécurité du pod en cours d'exécution pour confirmer que seccomp est défini : kubectl get pod seccomp-custom-test -o jsonpath='{.spec.securityContext.seccompProfile}' Sortie attendue pour un profil localhost : {"type":"Localhost","localhostProfile":"custom-profile.json"} Pour un réglage au niveau du conteneur, utilisez : kubectl get pod seccomp-custom-test -o jsonpath='{.spec.containers[0].securityContext.seccompProfile}' ### Tester le blocage des appels système Utilisez kubectl exec pour exécuter une commande qui devrait être bloquée. Pour notre profil personnalisé qui refuse chmod : kubectl exec seccomp-custom-test -- chmod 777 /tmp Sortie attendue : chmod: /tmp: Operation not permitted Cela confirme que le profil est actif. Vous pouvez aussi tester avec un appel système qui devrait être autorisé pour vous assurer que le profil n'est pas trop large. Par exemple, ls /tmp devrait réussir : kubectl exec seccomp-custom-test -- ls /tmp ### Inspecter les journaux du runtime de conteneurs Si un pod ne démarre pas à cause de seccomp, vérifiez les journaux du runtime sur le nœud. Pour containerd : journalctl -u containerd | grep seccomp Recherchez des messages indiquant des erreurs de chargement de profil ou des refus d'appels système. Par exemple : level=error msg="failed to load seccomp profile" error="open /var/lib/kubelet/seccomp/custom-profile.json: no such file or directory" Pour Docker, vérifiez : journalctl -u docker | grep seccomp ### Examiner les événements du pod Utilisez kubectl describe pod pour voir les événements liés aux échecs de seccomp, comme un échec de création de conteneur avec un message sur un profil seccomp invalide. Par exemple : Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning Failed 10s kubelet Error: failed to generate container "test" spec: failed to generate seccomp spec: unable to load seccomp profile "/var/lib/kubelet/seccomp/custom-profile.json": open /var/lib/kubelet/seccomp/custom-profile.json: no such file or directory Cet événement indique clairement un fichier de profil manquant sur le nœud. ## Modes de défaillance et récupération Malgré une planification minutieuse, des échecs peuvent survenir. Comprendre les modes de défaillance courants aide à une récupération rapide. Cette section énumère les problèmes les plus fréquents et fournit des étapes de remédiation pas à pas. ### Modes de défaillance courants - Fichier de profil manquant : Pour les profils Localhost , si le fichier n'est pas présent sur le nœud, le conteneur ne démarrera pas avec une erreur comme cannot load seccomp profile . Cela arrive souvent lorsque les profils sont copiés manuellement sur seulement quelques nœuds. - JSON de profil invalide : Des erreurs de syntaxe dans le JSON, comme une virgule manquante ou une action inconnue, peuvent entraîner des échecs d'analyse du profil. Le pod échouera avec une erreur similaire au cas de fichier manquant. - Profil trop restrictif : Bloquer des appels système nécessaires peut faire planter des applications en cours d'exécution. Par exemple, bloquer openat empêchera l'application de lire un fichier, et bloquer clone l'empêchera de créer des threads ou des processus. - Architecture incompatible : Des profils spécifiant des architectures non supportées par l'hôte peuvent causer des problèmes. Si votre nœud est ARM64 mais que le profil ne liste que SCMP_ARCH_X86_64 , le profil peut ne pas se charger ou se comporter de manière inattendue. - Incompatibilité de version du noyau : Certaines actions seccomp, comme SCMP_ACT_LOG (qui journalise l'appel système mais l'autorise), nécessitent des versions plus récentes du noyau. Si le noyau ne supporte pas l'action, le profil sera rejeté. ### Étapes de récupération Si un pod ne démarre pas, vérifiez d'abord le statut et les événements du pod : kubectl describe pod Pour un fichier de profil manquant, l'événement affichera une erreur similaire à : Error: failed to generate container "..." spec: failed to generate seccomp spec: unable to load seccomp profile "/var/lib/kubelet/seccomp/custom-profile.json": open /var/lib/kubelet/seccomp/custom-profile.json: no such file or directory Si l'erreur est due à un JSON invalide, le message peut indiquer failed to parse seccomp profile ou similaire. ### Revenir à RuntimeDefault Pour récupérer rapidement, changez le profil seccomp du pod en RuntimeDefault ou supprimez-le entièrement. Mettez à jour le manifeste et appliquez : securityContext: seccompProfile: type: RuntimeDefault Ou pour un déploiement existant, patchez : kubectl patch deployment myapp -p '{"spec":{"template":{"spec":{"securityContext":{"seccompProfile":{"type":"RuntimeDefault"}}}}}}' Cela déclenchera une mise à jour continue avec le profil plus sûr. Vous pouvez également passer à Unconfined si vous avez besoin d'une solution de secours immédiate, mais cela devrait être temporaire et suivi d'une correction appropriée. ### Vérifier le succès du retour en arrière Vérifiez que les pods fonctionnent et qu'aucun événement lié à seccomp ne se produit : kubectl get pods -l app=myapp kubectl describe pod Assurez-vous que le pod est Running et qu'aucun événement d'erreur n'est présent. Vous pouvez également vérifier le profil seccomp sur le nouveau pod : kubectl get pod -o jsonpath='{.spec.securityContext.seccompProfile}' Sortie attendue pour RuntimeDefault : {"type":"RuntimeDefault"} ## Erreurs courantes et comment les éviter En plus des modes de défaillance ci-dessus, voici quelques erreurs subtiles que les praticiens commettent souvent lors de la configuration de seccomp dans Kubernetes. ### Erreur 1 : Supposer que RuntimeDefault est toujours le meilleur choix RuntimeDefault est un bon point de départ, mais ce n'est pas une solution miracle. Le profil par défaut varie selon les runtimes de conteneurs et les versions. Par exemple, le profil par défaut de Docker peut différer de celui de containerd. Si vous avez besoin d'un comportement cohérent dans votre cluster, envisagez de créer un profil personnalisé explicitement défini et versionné. ### Erreur 2 : Ne pas tester dans un environnement de staging De nombreuses équipes passent directement en production avec un profil personnalisé et découvrent ensuite que l'application a besoin d'un appel système qui était bloqué. Testez toujours dans un environnement de staging qui reflète la production autant que possible. Utilisez des outils comme strace pour capturer les appels système effectués par votre application sous charge normale, puis construisez votre profil en conséquence. ### Erreur 3 : Oublier de mettre à jour les profils après des changements d'application Les applications évoluent et de nouvelles fonctionnalités peuvent nécessiter des appels système supplémentaires. Si vous ne mettez pas à jour votre profil seccomp lorsque vous mettez à jour l'application, vous risquez d'introduire des échecs. Intégrez la révision du profil seccomp dans votre processus de gestion des changements. ### Erreur 4 : Placer des profils personnalisés uniquement sur certains nœuds Comme mentionné précédemment, un profil Localhost doit exister sur chaque nœud pouvant exécuter le pod. Dans un cluster avec auto-scaling des nœuds ou des pools de nœuds hétérogènes, il est facile d'oublier un nœud. Utilisez un DaemonSet ou un outil de gestion de configuration pour garantir que le fichier est présent sur tous les nœuds. ### Erreur 5 : Utiliser Unconfined inutilement Définir seccompProfile.type : Unconfined désactive seccomp pour ce pod ou conteneur. Cela devrait être évité sauf si vous avez une raison très spécifique, comme une application héritée qui ne peut fonctionner sous aucun profil. Même dans ce cas, envisagez d'utiliser un profil personnalisé avec SCMP_ACT_ALLOW comme action par défaut pour documenter explicitement ce qui est autorisé. ### Erreur 6 : Ignorer les réglages au niveau du conteneur Seccomp peut être défini au niveau du pod ou au niveau de chaque conteneur. Si les deux sont définis, le réglage au niveau du conteneur prime sur celui au niveau du pod. Cela peut conduire à des surprises si vous vous attendez à ce que tous les conteneurs d'un pod aient le même profil. Soyez explicite sur l'endroit où vous définissez seccomp et auditez les deux niveaux.
Question rapide 2 sur 2 Quelle fonctionnalité du noyau Linux Kubernetes utilise-t-il pour filtrer les appels système ? - SELinux - AppArmor - Seccomp - Capabilities
Le passage cite seccomp comme une fonctionnalité qui filtre les appels système qu'un processus peut effectuer.
## Sujets avancés Une fois à l'aise avec la configuration de base de seccomp, vous pouvez explorer des techniques plus avancées pour améliorer la sécurité et la gérabilité. ### Utiliser les profils seccomp avec journalisation d'audit Les noyaux plus récents supportent l'action SCMP_ACT_LOG , qui journalise l'appel système sans le bloquer. C'est utile lors du développement de profils pour découvrir quels appels système une application utilise sans la casser. Par exemple, vous pouvez commencer avec un profil qui journalise tous les appels système, puis les convertir progressivement en SCMP_ACT_ALLOW ou SCMP_ACT_ERRNO . Notez que SCMP_ACT_LOG nécessite le noyau 4.14 ou ultérieur et le support du runtime de conteneurs. Extrait d'exemple : { "defaultAction": "SCMP_ACT_LOG", "architectures": ["SCMP_ARCH_X86_64"], "syscalls": [] } Appliquez ce profil à un pod de test et surveillez les journaux du runtime pour voir les appels système effectués. Ensuite, construisez un profil qui autorise les appels système nécessaires et bloque tout le reste avec un refus par défaut. ### Utiliser les annotations de spécification du runtime OCI Pour un contrôle avancé, vous pouvez utiliser directement les annotations de spécification du runtime OCI dans le manifeste du pod. Cependant, cela n'est pas recommandé pour la plupart des utilisateurs car c'est moins portable et peut être déprécié. Si vous avez besoin de ce niveau de contrôle, consultez la documentation de votre runtime de conteneurs. ### Intégrer seccomp avec des moteurs de politique Des moteurs de politique comme Open Policy Agent (OPA) Gatekeeper ou Kyverno peuvent appliquer des politiques seccomp dans tout votre cluster. Par exemple, vous pouvez écrire une politique qui exige que tous les pods aient un profil seccomp défini et rejette tout pod utilisant Unconfined . Cela aide à maintenir la cohérence et à prévenir les erreurs de configuration. Une politique Kyverno simple pourrait ressembler à ceci : apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-seccomp spec: validationFailureAction: enforce rules: - name: check-seccomp match: resources: kinds: - Pod validate: message: "Le profil seccomp doit être défini sur RuntimeDefault ou Localhost" pattern: spec: securityContext: seccompProfile: type: "RuntimeDefault | Localhost" C'est un moyen puissant de garantir qu'aucune charge de travail ne s'exécute sans seccomp. ## Liste de contrôle opérationnelle Utilisez la liste de contrôle suivante pour les opérations en cours et les révisions des configurations seccomp. ### Liste de contrôle avant déploiement - [ ] Confirmer que la version de Kubernetes supporte seccomp (>=1.19, recommandé 1.25+). - [ ] Vérifier le support de seccomp par le runtime de conteneurs et le profil par défaut. - [ ] Identifier les charges de travail cibles et leurs appels système requis (utiliser strace ou des journaux d'audit). - [ ] Créer ou obtenir des profils seccomp et les tester dans un environnement de staging. - [ ] S'assurer que les profils personnalisés sont présents sur tous les nœuds concernés avec les bonnes permissions (par exemple, 644). - [ ] Mettre en place une surveillance des redémarrages de pods et des événements liés à seccomp. ### Pendant le déploiement - [ ] Commencer par un petit pilote (un pod ou un seul espace de noms). - [ ] Appliquer d'abord RuntimeDefault , puis utiliser progressivement des profils personnalisés. - [ ] Surveiller les journaux d'application pour détecter des refus d'appels système inattendus. - [ ] Utiliser des outils de surveillance pour suivre les redémarrages et les erreurs de pods. - [ ] Garder un plan de retour en arrière prêt (par exemple, patcher vers RuntimeDefault ). ### Vérification après déploiement - [ ] Vérifier que le profil seccomp est défini dans la spécification du pod (au niveau du pod et du conteneur). - [ ] Tester que les appels système bloqués produisent les erreurs attendues (par exemple, chmod échoue avec Operation not permitted ). - [ ] Vérifier les journaux du runtime pour des messages liés à seccomp. - [ ] S'assurer qu'il n'y a pas d'erreurs d'application inattendues dans les journaux. ### Révision régulière - [ ] Auditer périodiquement les profils seccomp pour les changements nécessaires dus aux mises à jour d'application. - [ ] Retester les profils en staging avant les changements en production. - [ ] Conserver une documentation des profils et de leur objectif. - [ ] Réviser les contextes de sécurité des pods pour des réglages Unconfined accidentels à l'aide d'une requête comme : kubectl get pods -A -o json | jq -r '.items[] | select(.spec.securityContext.seccompProfile.type == "Unconfined") | .metadata.namespace + "/" + .metadata.name' ### Réponse aux incidents - [ ] Si un pod échoue, revenir immédiatement à RuntimeDefault ou supprimer seccomp. - [ ] Enquêter sur la cause et ajuster le profil en conséquence. - [ ] Redéployer avec un profil corrigé après test. - [ ] Documenter l'incident et mettre à jour le profil et les procédures. ## Conclusion Seccomp est un contrôle de sécurité précieux, mais les erreurs de configuration peuvent causer des perturbations. En comprenant les erreurs courantes, en suivant un chemin de configuration sécurisé, en vérifiant l'application et en ayant des plans de récupération, vous pouvez utiliser efficacement seccomp pour renforcer vos charges de travail Kubernetes. Commencez par RuntimeDefault , introduisez progressivement des profils personnalisés à petite échelle et ayez toujours un plan de retour en arrière. Utilisez les listes de contrôle fournies pour maintenir une posture seccomp robuste à mesure que votre cluster évolue. Rappelez-vous que seccomp n'est qu'une couche de défense ; combinez-le avec d'autres contrôles de sécurité tels que des normes de sécurité de pod restrictives, des conteneurs non-root et des politiques réseau pour une stratégie de sécurité complète. Avec une planification et des tests minutieux, seccomp peut réduire considérablement la surface d'attaque de vos applications conteneurisées sans sacrifier la fiabilité.