Déployer des NetworkPolicy Kubernetes pas à pas
Section intitulée « Déployer des NetworkPolicy Kubernetes pas à pas »Une micro-segmentation Kubernetes commence par un refus, pas par une longue liste d’autorisations optimistes. Le compromis est net : on gagne une réduction réelle des mouvements latéraux entre pods, on paie une discipline de nommage, de test et d’exploitation qui ne pardonne pas les labels décoratifs.
Une politique réseau ressemble au contrôle des portes dans un bâtiment : chaque pièce reste fermée tant qu’une raison précise n’autorise pas un passage. Cela évite qu’une personne entrée dans un couloir puisse parcourir librement tous les étages, simplement parce que les portes existent.
→ Lire l’explication complète de la marmotte
Préparer le CNI et l’inventaire des flux
Section intitulée « Préparer le CNI et l’inventaire des flux »Une NetworkPolicy exprime une intention de filtrage entre pods Kubernetes. Son application effective dépend du CNI (Container Network Interface), le composant qui relie les pods au réseau du cluster. Kubernetes accepte l’objet même lorsqu’aucun composant ne l’applique. Une politique ignorée est donc parfaitement valide au format YAML, parfaitement visible dans kubectl get networkpolicy, et parfaitement inutile. Le genre de réussite qui passe très bien dans une démonstration commerciale.
Commencer par identifier le CNI et sa capacité de filtrage. Calico, Cilium et Antrea appliquent les NetworkPolicy Kubernetes. Flannel seul ne les applique pas. Certains environnements managés activent un CNI compatible sans activer son moteur de politiques : lire la configuration effective, pas la fiche produit.
# Identifier les pods du CNI dans l'espace système.kubectl -n kube-system get pods -o wide
# Vérifier que l'API accepte les objets NetworkPolicy.kubectl api-resources | grep -i networkpolicy
# Créer une politique de test, puis vérifier qu'elle est admise.kubectl apply -f - <<'EOF'apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: capability-probe namespace: defaultspec: podSelector: {} policyTypes: - IngressEOFkubectl delete networkpolicy capability-probe -n defaultCette vérification ne prouve que la présence de l’API. Seul un test de connectivité prouve l’application par le CNI. La différence compte : l’API Kubernetes stocke une règle, le CNI intercepte ou autorise réellement les paquets.
Avant toute politique, produire une matrice de flux : source, destination, protocole, port, nom de domaine si un service externe intervient, et propriétaire du flux. Distinguer les appels applicatifs, la résolution DNS (Domain Name System), les métriques, les webhooks d’admission et les sorties vers les dépendances externes. Une politique réseau ne devine pas qu’un appel vers une base de données est une « dépendance métier ». Les paquets n’ont pas lu les slides d’architecture.
La séparation par namespace est le premier périmètre opérationnel. Elle n’est pas une frontière réseau par elle-même. Attribuer des labels stables aux namespaces et aux pods, par exemple security.tortuetech.io/zone: frontend, app.kubernetes.io/name: api et app.kubernetes.io/component: server. Les labels doivent être imposés dans les manifestes, Helm charts ou contrôleurs de déploiement, jamais ajoutés à la main après coup.
Pour les principes de cloisonnement entre zones, consulter l’architecture réseau. Le présent guide traite l’application concrète dans Kubernetes, pas la modélisation complète des flux d’entreprise.
Établir le refus par défaut avec NetworkPolicy
Section intitulée « Établir le refus par défaut avec NetworkPolicy »Appliquer un refus par défaut par namespace applicatif. Ne pas commencer par le namespace système : couper le plan de contrôle, le DNS ou les agents de sécurité sans inventaire préalable transforme une politique réseau en exercice de restauration.
Le refus doit couvrir l’entrée et la sortie. Une politique d’entrée seule empêche les connexions arrivantes mais laisse les pods joindre n’importe quelle destination. Cela limite certains déplacements latéraux, mais permet encore l’exfiltration et les appels sortants non prévus.
# Appliquer dans un namespace applicatif déjà inventorié.apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: deny-all-ingress-egress namespace: paymentsspec: podSelector: {} # Sélectionne tous les pods du namespace payments. policyTypes: - Ingress - EgressAppliquer avec :
# Vérifier d'abord que le namespace cible existe et porte ses labels attendus.kubectl get namespace payments --show-labels
# Créer le refus total.kubectl apply -f deny-all.yaml
# Confirmer l'objet enregistré par l'API Kubernetes.kubectl -n payments describe networkpolicy deny-all-ingress-egressLes politiques sont additives. Si plusieurs politiques sélectionnent un pod, le trafic est autorisé lorsqu’au moins une règle autorise ce trafic dans la direction concernée. Il n’existe pas de priorité ni de règle de refus explicite dans le modèle standard Kubernetes. Une politique permissive ajoutée plus tard peut donc rouvrir un flux fermé. Auditer toutes les politiques qui sélectionnent le même pod, pas seulement celle en cours d’écriture.
Le refus par défaut ne protège pas contre un processus compromis dans un pod autorisé, ni contre l’abus d’identifiants applicatifs valides. Il ne chiffre rien, n’authentifie pas l’appelant et ne contrôle pas les requêtes HTTP (Hypertext Transfer Protocol). Ces garanties doivent venir de l’authentification applicative, du chiffrement de transport, de l’autorisation et, si nécessaire, d’un proxy de service. Confondre filtrage L3/L4 (couches réseau et transport) avec sécurité applicative est une erreur tenace : un port 443 autorisé reste un port 443 très bavard.
Autoriser les flux légitimes entre pods et namespaces
Section intitulée « Autoriser les flux légitimes entre pods et namespaces »Ajouter les exceptions une par une, en partant du destinataire. Une politique Ingress est portée par les pods qui reçoivent le trafic. Une politique Egress est portée par les pods qui initient le trafic. Documenter les deux côtés pour les flux sensibles, même si une seule direction suffit techniquement à autoriser le paquet.
L’exemple suivant autorise les pods frontend du namespace web à joindre les pods api du namespace payments sur TCP (Transmission Control Protocol) 8080. Les deux sélecteurs sont nécessaires : namespaceSelector limite le namespace source, podSelector limite les pods dans ce namespace.
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-web-to-api namespace: paymentsspec: podSelector: matchLabels: app.kubernetes.io/name: api policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: security.tortuetech.io/zone: frontend podSelector: matchLabels: app.kubernetes.io/name: frontend ports: - protocol: TCP port: 8080Le piège classique est ici : un sélecteur sans erreur syntaxique peut ne sélectionner aucun pod. Une règle podSelector ne cherche que dans le namespace combiné au namespaceSelector parent. Un label posé sur un Deployment mais absent du modèle de pod n’atteindra aucun pod. Vérifier les labels réels, jamais les intentions du manifeste.
# Afficher les labels réellement portés par les objets ciblés.kubectl -n payments get pods --show-labelskubectl -n web get pods --show-labelskubectl get namespaces --show-labels
# Vérifier que la politique cible les pods api attendus.kubectl -n payments describe networkpolicy allow-web-to-apiAutoriser ensuite le DNS sortant. Sans cette exception, une application qui résout des noms échoue avant même de joindre son service distant. Cibler les pods DNS par labels et le port UDP (User Datagram Protocol) 53, puis ajouter TCP 53 si le résolveur peut basculer sur TCP. Éviter les règles vers toute adresse sur le port 53 : elles transforment le DNS en tunnel de sortie, ce qui est une tradition informatique dont personne ne devrait être fier.
Pour les sorties hors cluster, préférer une passerelle de sortie ou un proxy contrôlé lorsque le CNI le permet. Les ipBlock sont fragiles avec les services cloud, les plages dynamiques et les traductions d’adresses. Une liste d’adresses IP (Internet Protocol) figée n’est pas une stratégie, c’est une date d’expiration sans calendrier.
Tester les NetworkPolicy avec un pod de diagnostic
Section intitulée « Tester les NetworkPolicy avec un pod de diagnostic »Ne jamais déployer une politique en production parce que le YAML semble logique. Tester le flux autorisé et le flux refusé depuis un pod de diagnostic dédié, avec une image maintenue et épinglée par digest dans le dépôt de déploiement. Une image latest est un pari sur le futur, discipline rarement récompensée par le futur.
Créer temporairement un pod de test dans le namespace source :
# Pod de diagnostic éphémère dans le namespace web.kubectl -n web run netcheck \ --image=nicolaka/netshoot:v0.14 \ --restart=Never \ --labels='app.kubernetes.io/name=frontend' \ --command -- sleep 3600
# Attendre son état Ready, puis tester le flux autorisé vers le service api.kubectl -n web wait --for=condition=Ready pod/netcheck --timeout=60skubectl -n web exec netcheck -- \ curl --connect-timeout 3 --max-time 5 http://api.payments.svc.cluster.local:8080/health
# Tester un port non autorisé : l'échec doit être un timeout ou un refus attendu.kubectl -n web exec netcheck -- \ nc -vz -w 3 api.payments.svc.cluster.local 9090
# Supprimer le pod après le test.kubectl -n web delete pod netcheckTester aussi une source non autorisée, dans un namespace distinct ne portant pas le label frontend. Un échec DNS ne valide pas le filtrage réseau : il masque seulement le test. Résoudre d’abord le nom, puis tester l’adresse et le port. Capturer le code retour, le délai d’échec et les journaux du CNI lorsque celui-ci expose des verdicts.
Les connexions déjà établies peuvent survivre à l’ajout d’une politique selon le CNI et son suivi d’état. Tester avec de nouvelles connexions. Une politique est un contrôle de nouveaux paquets et de leur état, pas une machine à remonter le temps sur chaque socket existant.
Exploitation, supervision et reprise des politiques
Section intitulée « Exploitation, supervision et reprise des politiques »Versionner les politiques avec les applications qu’elles protègent. Une modification de port, de namespace ou de label doit modifier simultanément le code de déploiement et les règles. Une politique séparée dans un dépôt d’infrastructure peut convenir si une revue impose la synchronisation, sinon le décalage arrive avec une régularité d’horloge suisse et une élégance de parpaing.
Limiter les droits de modification : seuls les rôles d’automatisation et les opérateurs réseau doivent créer ou modifier les NetworkPolicy. Un acteur capable d’étiqueter un namespace ou un pod peut aussi contourner une sélection fondée sur ces labels. Protéger donc les permissions RBAC (Role-Based Access Control) sur les namespaces, les workloads et les politiques. Les labels de sécurité sont des attributs d’autorisation, pas des autocollants de classement.
Superviser trois signaux : les refus réseau du CNI, les erreurs applicatives de connexion et les changements d’objets NetworkPolicy. Une hausse de timeouts après un déploiement révèle souvent une dépendance non inventoriée. Conserver les manifestes validés, les matrices de flux et une procédure de retrait ciblé. La reprise ne doit pas consister à supprimer toutes les politiques du namespace : ce bouton existe, mais un extincteur n’est pas un plan d’architecture.
Les politiques ne contiennent normalement aucun secret. Elles dépendent toutefois de composants critiques : configuration du CNI, certificats éventuels de son plan de contrôle, règles RBAC et sauvegarde des manifestes Git. Restaurer un cluster sans restaurer les politiques revient à restaurer les murs sans remettre les portes. Les pratiques de gestion des secrets et du déploiement restent nécessaires pour protéger les identifiants utilisés par les applications autorisées à communiquer.
🐝 Ce qui arrive si on s’en passe
Section intitulée « 🐝 Ce qui arrive si on s’en passe »Sans refus par défaut, le réseau du cluster reste plat : tout pod peut ouvrir une connexion vers tout autre pod, tout Service et souvent vers les points d’accès internes de la plateforme, y compris les ports de supervision, les bases de données et les interfaces d’administration qui n’écoutent que parce que personne n’a supposé qu’un voisin viendrait frapper. Un conteneur compromis dispose alors d’un balayage complet du plan applicatif sans franchir aucun contrôle. L’absence de politiques prive aussi d’un référentiel : aucune matrice de flux n’est écrite, donc aucune anomalie de trafic n’est qualifiable, et le CNI ne produit aucun verdict de refus exploitable en investigation. Le périmètre d’un incident devient impossible à borner, puisque chaque pod joignable est un pivot plausible. Les sorties vers l’extérieur restent également libres, sans point d’observation ni possibilité de coupure ciblée.
🦫 Explication de la marmotte 🍫
Section intitulée « 🦫 Explication de la marmotte 🍫 »Kubernetes exécute des programmes dans des unités appelées pods. Par défaut, ces programmes peuvent souvent se joindre sur le réseau, même s’ils n’ont aucune raison métier de le faire. Une politique réseau sert à décider quels programmes peuvent parler à quels autres programmes, sur quel port et dans quel sens.
Le processus commence par vérifier que le composant réseau du cluster sait réellement appliquer ces règles. Kubernetes peut enregistrer une règle sans la faire respecter si ce composant ne possède pas cette fonction. Ensuite, une règle de refus est posée sur tous les programmes d’un espace applicatif. À partir de ce moment, les communications entrantes et sortantes sont bloquées.
Chaque besoin réel est ensuite ajouté séparément. Une application web peut être autorisée à joindre une application métier sur un port précis. L’application métier peut être autorisée à joindre une base de données sur un autre port. La recherche des noms de services doit aussi être autorisée, sinon les applications ne trouvent plus leurs destinations.
Les règles utilisent des étiquettes placées sur les programmes et les espaces de travail. Si une étiquette manque ou change, la règle peut ne viser personne, ou viser le mauvais programme. Des tests lancent donc une connexion qui doit réussir, puis une autre qui doit échouer. Si le test échoue alors qu’il devrait réussir, il faut vérifier les étiquettes, le port et la règle.
À lire aussi
- Conteneurs, Kubernetes, CNI et service meshComprendre les réseaux de conteneurs et Kubernetes : namespaces réseau, bridges, CNI, Services, Ingress, NetworkPolicy, DNS de cluster, egress et service mesh.
- Auditer et durcir un cluster Kubernetes avec kube-benchGuide pratique pour auditer un cluster Kubernetes existant avec kube-bench, prioriser les écarts CIS et conduire la remédiation sans casser l'exploitation.
- Isolation réseau multi-tenant avec VPC et NetworkPolicyPrincipes de segmentation cloud native multi-tenant avec VPC, security groups et network policies, hors service mesh.
- Configurer le moindre privilège sur un compte cloud existantGuide pratique pas-à-pas pour auditer puis restreindre progressivement les permissions d’un compte AWS, Azure ou GCP existant.
Pages voisines
La citent
- Auditer et durcir un cluster Kubernetes avec kube-bench
- Conteneurs, Kubernetes, CNI et service mesh
- Isolation réseau multi-tenant avec VPC et NetworkPolicy
- Laisser une équipe se tromper sans casser la production
- Monolithe ou microservices : choisir sans se mentir
- Pourquoi le château fort biaise la sécurité réseau
- Séparer plan de contrôle et plan de données
Déployer des NetworkPolicy Kubernetes pas à pas
Elle cite
: les deux pages se citent l’une l’autre.
