Appliquer une authentification forte pour toutes les requêtes du serveur API.
Définir les flags `kube-apiserver` : `--anonymous-auth=false` pour rejeter les requêtes non authentifiées, et `--client-ca-file` pour appliquer la validation du certificat client (mTLS).
Pourquoi: Ces flags sont des contrôles fondamentaux pour éliminer l'accès anonyme et appliquer une communication authentifiée et chiffrée avec le serveur API.
Sécuriser le magasin d'état etcd du cluster contre l'accès non autorisé et le vol de données.
Configurer etcd avec mTLS pour toutes les communications client et peer (`--cert-file`, `--key-file`, `--peer-cert-file`). Activer le chiffrement des secrets au repos via le flag `--encryption-provider-config` du serveur API.
Pourquoi: etcd contient tous les secrets du cluster. Le chiffrement des données en transit (mTLS) et au repos est essentiel pour protéger les informations sensibles même si les nœuds etcd sont compromis.
Faire pivoter les clés de chiffrement au repos d'etcd sans interruption.
1. Ajouter la nouvelle clé comme première entrée dans le fichier `EncryptionConfiguration`. 2. Redémarrer tous les serveurs API. 3. Forcer le rechiffrement de tous les secrets (`kubectl get secrets -A -o json | kubectl replace -f -`). 4. Après vérification, retirer l'ancienne clé de la configuration et redémarrer les serveurs API à nouveau.
Pourquoi: La modification de la configuration n'affecte que les nouvelles écritures. Les données existantes doivent être réécrites pour être chiffrées avec la nouvelle clé. La suppression prématurée de l'ancienne clé vous empêchera d'accéder à vos données.
Implémenter un modèle de réseau zero-trust au sein d'un namespace.
Appliquer une `NetworkPolicy` avec un `podSelector: {}` vide et `policyTypes: [Ingress, Egress]` mais sans règles `ingress` ou `egress`. Cela sélectionne tous les pods et refuse tout le trafic.
Pourquoi: Cette politique établit une base "tout refuser", forçant des règles "autoriser" explicites pour toutes les communications requises, ce qui est le fondement du réseau zero-trust.
Les NetworkPolicies de sortie bloquent la résolution DNS pour les pods.
Ajouter une règle de sortie spécifique pour autoriser le trafic vers le service DNS du cluster. Autoriser le trafic de sortie vers le port 53 sur les protocoles UDP et TCP. Sélectionner les pods kube-dns via `namespaceSelector` et `podSelector` si possible.
Pourquoi: Les NetworkPolicies sont granulaires. Une règle de sortie générale vers un bloc d'IP pourrait ne pas couvrir le protocole spécifique (UDP) requis pour le DNS, entraînant des échecs de résolution.
Sécuriser l'accès externe aux services exposés via un Ingress.
Configurer la ressource Ingress en ajoutant une section `tls` qui référence un Secret Kubernetes de type `kubernetes.io/tls`. Le secret doit contenir le certificat TLS et la clé privée.
Pourquoi: Ceci centralise la terminaison TLS au niveau du contrôleur Ingress, chiffrant le trafic des clients vers la limite du cluster et simplifiant la gestion des certificats pour les services backend.
Renforcement du cluster
Accorder aux utilisateurs ou aux applications uniquement les permissions minimales requises.
Utiliser des `Roles` et `RoleBindings` à portée de namespace lorsque cela est possible. Éviter `cluster-admin` et les jokers (`"*"`) dans les `verbs` ou `resources`. Accorder des permissions spécifiques comme `["get", "list"]` sur `["pods"]`.
Pourquoi: Ceci minimise le rayon d'impact si un compte ou un jeton est compromis, empêchant les mouvements latéraux et l'escalade de privilèges.
Réduire la surface d'attaque pour les pods qui n'ont pas besoin d'interagir avec l'API Kubernetes.
Désactiver le montage automatique des jetons de compte de service en définissant `automountServiceAccountToken: false` sur le ServiceAccount ou dans la spécification du Pod.
Pourquoi: Si un pod est compromis, un attaquant ne peut pas utiliser un jeton monté pour accéder au serveur API, empêchant les attaques au niveau du cluster provenant du pod compromis.
Vérifier si un utilisateur ou un compte de service spécifique a la permission d'effectuer une action.
Pourquoi: Cette commande permet l'usurpation d'identité pour vérifier avec précision les permissions effectives sans avoir besoin de parser manuellement tous les Rôles et Bindings.
Maintenir la sécurité du cluster en faisant pivoter régulièrement les certificats du plan de contrôle et du kubelet.
Pour les clusters kubeadm, utiliser `kubeadm certs renew all`. Pour les autres, suivre la procédure de rotation manuelle ou automatisée documentée. Activer la rotation des certificats client/serveur kubelet via sa configuration.
Pourquoi: La rotation régulière limite la fenêtre de temps pendant laquelle un attaquant peut utiliser un certificat compromis. C'est une pratique d'hygiène de sécurité critique.
Un nœud de travail est suspecté d'être compromis et doit être immédiatement isolé.
Premièrement, utiliser `kubectl cordon <node-name>` pour empêcher la planification de nouveaux pods. Ensuite, utiliser `kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data` pour évacuer en toute sécurité les charges de travail en cours.
Pourquoi: Le cordonnement et le drainage sont la procédure standard et non destructive pour retirer un nœud du service, permettant de replanifier les charges de travail ailleurs tout en préservant le nœud compromis pour l'analyse forensique.
Renforcement du système
Restreindre les appels système qu'un conteneur peut faire au noyau hôte.
Dans le `securityContext` du Pod ou du Conteneur, définir `seccompProfile.type` sur `RuntimeDefault` pour une base sécurisée, ou `Localhost` avec un chemin vers un profil JSON personnalisé pour un contrôle plus strict.
Pourquoi: Seccomp réduit la surface d'attaque du noyau depuis un conteneur, empêchant les exploits contre les vulnérabilités du noyau en bloquant les appels système inutilisés ou dangereux.
Confiner les processus de conteneurs en restreignant l'accès aux fichiers, aux capacités réseau et à d'autres ressources.
Appliquer un profil AppArmor à un conteneur via l'annotation : `container.apparmor.security.beta.kubernetes.io/<container_name>: localhost/<profile_name>`. Le profil doit être préchargé sur le nœud.
Pourquoi: AppArmor fournit un contrôle d'accès obligatoire (MAC), ajoutant une couche cruciale de défense en profondeur pour contenir une application compromise et l'empêcher d'accéder à des ressources non autorisées.
Un conteneur a besoin d'une opération privilégiée spécifique (par exemple, la liaison au port 80) sans s'exécuter en tant que root.
Dans le `securityContext.capabilities`, `drop: ["ALL"]` puis `add: ["NET_BIND_SERVICE"]`.
Pourquoi: Ceci suit le principe du moindre privilège en accordant uniquement la capacité Linux spécifique requise, évitant les permissions étendues de l'exécution en tant que root.
Empêcher un conteneur d'obtenir un accès complet au système hôte.
Définir `securityContext.privileged: false` (ce qui est la valeur par défaut). Utiliser les Pod Security Standards ou OPA/Kyverno pour appliquer cette règle à l'échelle du cluster.
Pourquoi: Un conteneur privilégié a presque toutes les capacités de l'hôte et l'accès aux périphériques, désactivant de fait l'isolation des conteneurs. C'est un vecteur primaire d'évasion de conteneur.
Minimiser les vulnérabilités des microservices
Appliquer des configurations de sécurité de base ou strictes pour les pods au niveau d'un namespace.
Appliquer des étiquettes au namespace, par exemple, `pod-security.kubernetes.io/enforce: restricted`. Les modes sont `enforce` (appliquer), `audit` (auditer) et `warn` (avertir).
Pourquoi: Les Pod Security Standards (PSS) fournissent une politique de sécurité intégrée et à plusieurs niveaux qui remplace la PodSecurityPolicy dépréciée, facilitant l'application des meilleures pratiques de sécurité.
Renforcer un pod en appliquant simultanément plusieurs contrôles de sécurité.
Configurer un `securityContext` qui combine `runAsNonRoot: true`, `allowPrivilegeEscalation: false` et `readOnlyRootFilesystem: true`.
Pourquoi: Cette approche de défense en profondeur superpose plusieurs protections : empêcher l'exécution en tant que root, bloquer les vecteurs d'escalade de privilèges (comme setuid) et rendre le système de fichiers du conteneur immuable.
Exécuter des charges de travail non fiables ou multi-locataires avec une isolation plus forte que les conteneurs standards.
Définir une ressource `RuntimeClass` pointant vers un gestionnaire de runtime en sandbox (par exemple, gVisor, Kata Containers). Assigner des pods à celui-ci en utilisant `spec.runtimeClassName`.
Pourquoi: Les runtimes en sandbox utilisent un noyau en espace utilisateur ou des machines virtuelles légères pour intercepter les appels système, offrant une couche d'isolation supplémentaire entre le conteneur et le noyau hôte.
Appliquer des politiques de sécurité complexes et personnalisées qui ne sont pas couvertes par les contrôles Kubernetes standards.
Déployer OPA Gatekeeper. Définir des politiques en utilisant `ConstraintTemplate` (la logique Rego) et les appliquer avec des ressources `Constraint`.
Pourquoi: Gatekeeper agit comme un webhook d'admission de validation, vous permettant d'appliquer des règles arbitraires, telles que l'exigence d'étiquettes spécifiques, l'interdiction des chemins d'hôte ou l'application de limites de ressources.
Fournir des secrets aux pods de la manière la plus sécurisée.
Monter les secrets sous forme de fichiers dans un volume. Pour une sécurité encore plus grande, utiliser un pilote CSI de magasin de secrets pour monter les secrets d'un coffre externe (par exemple, HashiCorp Vault, AWS Secrets Manager) directement dans le pod.
Pourquoi: Le montage sous forme de fichiers est plus sécurisé que les variables d'environnement (qui peuvent être journalisées ou exposées). Un pilote CSI évite complètement de stocker le secret dans etcd.
Chiffrer et authentifier automatiquement tout le trafic réseau pod-à-pod.
Déployer un maillage de services comme Istio ou Linkerd. Le maillage injecte un proxy sidecar dans chaque pod pour gérer le chiffrement mTLS, l'authentification et l'application des politiques.
Pourquoi: Un maillage de services offre un réseau transparent et zero-trust sans nécessiter de modifications du code de l'application, sécurisant toutes les communications de services internes.
Sécurité de la chaîne d'approvisionnement
Empêcher le déploiement d'images de conteneurs avec des vulnérabilités connues (CVEs).
Intégrer un scanner comme Trivy ou Grype dans le pipeline CI/CD. Échouer la construction si les vulnérabilités dépassent un seuil de gravité défini (par exemple, ÉLEVÉE ou CRITIQUE).
Pourquoi: Cette approche "shift-left" détecte les vulnérabilités tôt, avant qu'elles n'atteignent la production, réduisant drastiquement la surface d'attaque des applications en cours d'exécution.
S'assurer que seules des images de conteneurs fiables et non modifiées sont déployées sur le cluster.
Signer les images avec `cosign` pendant le processus de construction CI. Utiliser un moteur de politique (Kyverno, OPA Gatekeeper) comme contrôleur d'admission pour vérifier la signature par rapport à une clé publique avant d'autoriser la création d'un pod.
Pourquoi: La signature cryptographique offre de fortes garanties d'intégrité de l'image (elle n'a pas été altérée) et d'authenticité (elle provient d'une source fiable).
Minimiser la surface d'attaque au sein de l'image de conteneur elle-même.
Utiliser des images de base minimales (par exemple, distroless, Alpine). Utiliser un Dockerfile multi-étapes pour ignorer les outils de construction. Définir un utilisateur non-root avec l'instruction `USER`. Utiliser `.dockerignore` pour exclure les fichiers sensibles.
Pourquoi: Une image minimale contient moins de paquets et d'outils, offrant moins de vulnérabilités potentielles et rendant plus difficile pour un attaquant de pivoter si le conteneur est compromis.
Appliquer une politique selon laquelle toutes les images déployées doivent provenir du registre privé de l'organisation.
Utiliser un contrôleur d'admission (comme OPA Gatekeeper ou Kyverno) pour créer une politique qui valide le champ `image` de toutes les spécifications de conteneur par rapport à une liste blanche de noms d'hôte de registre.
Pourquoi: Ceci empêche les développeurs de télécharger des images non fiables ou non scannées depuis des dépôts publics comme Docker Hub, garantissant que tout le code a passé les vérifications de sécurité internes.
Maintenir un inventaire de tous les composants logiciels et dépendances au sein d'une image de conteneur.
Intégrer un outil comme `Syft` dans le pipeline CI/CD pour générer une nomenclature logicielle (SBOM) dans un format standard comme SPDX ou CycloneDX.
Pourquoi: Une SBOM est essentielle pour la sécurité de la chaîne d'approvisionnement, permettant l'identification rapide de tous les actifs affectés lorsqu'une nouvelle vulnérabilité est découverte dans une dépendance.
Identifier les erreurs de configuration de sécurité dans les manifests YAML Kubernetes avant qu'ils ne soient appliqués.
Dans le pipeline CI, utiliser un outil comme `trivy config` ou `kubesec` pour scanner les fichiers manifestes Kubernetes à la recherche de configurations risquées, telles que l'exécution en tant que root, l'autorisation de l'escalade de privilèges ou le montage de chemins d'hôte sensibles.
Pourquoi: Cette vérification proactive détecte les problèmes de sécurité dans l'infrastructure-as-code avant qu'ils ne créent des vulnérabilités dans le cluster en cours d'exécution.
Surveillance, Journalisation et Sécurité d'exécution
Détecter et alerter sur les activités suspectes à l'intérieur des conteneurs en cours d'exécution ou sur les nœuds du cluster.
Déployer Falco en tant que DaemonSet. Falco utilise eBPF ou un module de noyau pour surveiller les appels système et alerte sur les comportements anormaux basés sur son ensemble de règles (par exemple, shell dans un conteneur, connexions réseau inattendues).
Pourquoi: Falco offre une visibilité en temps réel sur le comportement d'exécution, permettant la détection de menaces comme les évasions de conteneurs, le cryptominage ou l'exfiltration de données que la numérisation statique ne peut pas voir.
Une règle Falco par défaut génère trop de faux positifs.
Créer un fichier de règles Falco personnalisé pour annuler la règle par défaut. Ajouter des exceptions à la `condition` de la règle pour exclure les comportements connus comme bons, tels que des processus spécifiques ou des images de conteneurs (par exemple, `and not container.image.repository contains "debug"`).
Pourquoi: Le réglage des règles est essentiel pour l'opérationnalisation de la sécurité d'exécution. Réduire le bruit garantit que les équipes de sécurité peuvent se concentrer sur les alertes exploitables et de haute priorité.
Enregistrer un journal chronologique et immuable de toutes les actions effectuées contre l'API Kubernetes.
Activer la journalisation d'audit sur le `kube-apiserver` en fournissant les flags `--audit-policy-file` et `--audit-log-path`. Configurer la politique pour définir ce qui est journalisé et à quel niveau.
Pourquoi: Les journaux d'audit sont essentiels pour l'analyse de sécurité, l'enquête sur les incidents et la conformité. Ils fournissent un enregistrement définitif de qui a fait quoi, et quand.
Auditer l'accès aux ressources sensibles comme les Secrets sans journaliser le contenu du secret lui-même.
Configurer la règle de politique d'audit pour les Secrets afin d'utiliser `level: Metadata`. Cela journalise l'utilisateur, l'horodatage, la ressource et le verbe, mais omet les corps des requêtes et des réponses.
Pourquoi: Ceci assure la responsabilité de ceux qui accèdent aux secrets sans créer un nouveau risque de sécurité en écrivant des données sensibles dans les journaux d'audit.
Aggreger les journaux de tous les composants du cluster et des applications pour une analyse centralisée.
Déployer un agent de collecte de journaux (par exemple, Fluentd, Vector) en tant que DaemonSet pour collecter les journaux des nœuds et les transmettre à un SIEM centralisé ou à un système de gestion des journaux (par exemple, Elasticsearch, Splunk).
Pourquoi: La journalisation centralisée est cruciale pour corréler les événements à travers le cluster lors d'une enquête d'incident et pour maintenir des enregistrements à long terme pour la conformité.
Transférer les alertes de sécurité Falco vers un système externe pour notification et réponse.
Déployer `Falcosidekick` aux côtés de Falco. Le configurer pour recevoir les alertes de Falco et les transmettre à des sorties comme Slack, PagerDuty ou un SIEM.
Pourquoi: Falcosidekick fournit un mécanisme flexible et robuste pour intégrer les alertes en temps réel de Falco dans les flux de travail opérationnels et de sécurité existants.
Détecter si un conteneur en cours d'exécution a été modifié, ce qui pourrait indiquer une compromission.
Appliquer des conteneurs immuables avec `readOnlyRootFilesystem: true`. Utiliser un outil de sécurité d'exécution comme Falco pour surveiller et alerter sur toute écriture de fichier à des emplacements inattendus.
Pourquoi: Dans un modèle immuable, les conteneurs ne sont jamais modifiés au moment de l'exécution ; ils sont remplacés. Toute déviation de ce modèle est un fort indicateur d'une potentielle faille de sécurité.