Aller au contenu
Conteneurs & Orchestration medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Les NetworkPolicies Kubernetes

18 min de lecture

logo kubernetes

Les NetworkPolicies contrôlent quels Pods peuvent communiquer entre eux et avec l’extérieur au niveau IP et port (L3/L4). Par défaut, Kubernetes n’applique aucune restriction : tous les Pods se parlent librement. Les NetworkPolicies permettent de cloisonner ces flux selon le principe du moindre privilège.

Ce guide couvre la création de policies ingress et egress, les cas critiques comme le DNS, et les techniques de debug indispensables.

  • Comprendre le modèle : sélection par labels, union des règles, logique source/destination
  • Créer des policies : deny par défaut, autorisation ciblée, filtrage par namespace
  • Gérer l’egress : ne pas casser le DNS, autoriser les flux nécessaires
  • Débugger : diagnostiquer pourquoi un flux est bloqué ou autorisé

En l’absence de restrictions réseau applicables, les Pods peuvent généralement communiquer largement entre eux, y compris entre namespaces. C’est le comportement réseau permissif par défaut de Kubernetes.

Les NetworkPolicies permettent de :

  • Restreindre les connexions entrantes vers un Pod (ingress)
  • Restreindre les connexions sortantes depuis un Pod (egress)
  • Isoler des environnements (production, staging, test)
  • Limiter la propagation en cas de compromission d’un Pod

Kubernetes définit les NetworkPolicies, mais ne les applique pas lui-même. C’est le plugin réseau (CNI) qui doit implémenter cette fonctionnalité.

Avant d’écrire des NetworkPolicies, vérifiez dans la documentation de votre plugin réseau qu’il applique bien les policies Kubernetes.

Parmi les implémentations souvent utilisées qui supportent les NetworkPolicies :

CNISupport NetworkPolicyNotes
Calico✅ CompletPolicies étendues disponibles
Cilium✅ CompletFiltrage L7 optionnel
Weave Net✅ Complet
Antrea✅ CompletOrienté VMware/vSphere
Flannel⚠️ PartielNécessite un complément (ex: Calico)

Vérifier le CNI installé :

Fenêtre de terminal
kubectl get pods -n kube-system -l k8s-app=calico-node
kubectl get pods -n kube-system -l k8s-app=cilium

Une NetworkPolicy cible les Pods via un podSelector basé sur leurs labels. Sans sélection valide, la policy ne s’applique à aucun Pod.

spec:
podSelector:
matchLabels:
app: backend

Cette policy s’applique uniquement aux Pods ayant le label app: backend dans le namespace où elle est déployée.

Sélectionner tous les Pods d’un namespace :

spec:
podSelector: {}
DirectionContrôleQuand restreindre
IngressConnexions entrantes vers le PodLimiter qui peut accéder à un service
EgressConnexions sortantes depuis le PodLimiter où un Pod peut se connecter

Déclarez explicitement policyTypes pour éviter les ambiguïtés :

spec:
policyTypes:
- Ingress
- Egress

Les NetworkPolicies ne se remplacent pas l’une l’autre. Les connexions autorisées résultent de l’union de toutes les règles applicables au Pod pour la direction concernée.

Exemple : si deux policies autorisent des sources différentes vers le même Pod, les deux sources sont autorisées.

Policy A : autorise frontend → backend
Policy B : autorise monitoring → backend
Résultat : frontend ET monitoring peuvent accéder à backend

Pour qu’une connexion fonctionne, elle doit être autorisée des deux côtés si des restrictions existent :

  • L’egress du Pod source doit autoriser la sortie vers la destination
  • L’ingress du Pod destination doit autoriser l’entrée depuis la source
Pod A (egress restreint) → Pod B (ingress restreint)
✅ Fonctionne si :
- Policy egress de A autorise B
- Policy ingress de B autorise A
❌ Échoue si :
- L'une des deux policies manque l'autorisation

C’est un point fondamental pour le dépannage : vérifiez toujours les policies des deux côtés.

Commençons par un cas classique : seuls les Pods frontend peuvent accéder aux Pods backend sur le port 8080.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: default
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080

Ce que fait cette policy :

  1. Sélectionne les Pods app: backend dans le namespace default
  2. Restreint leur trafic ingress (entrées deviennent contrôlées)
  3. Autorise uniquement les connexions depuis les Pods app: frontend
  4. Limite au port TCP 8080

Appliquer et tester :

Fenêtre de terminal
kubectl apply -f allow-frontend-to-backend.yaml
# Depuis un Pod frontend
kubectl exec -it deploy/frontend -- curl backend:8080
# Résultat : connexion réussie
# Depuis un autre Pod
kubectl exec -it deploy/autre-app -- curl backend:8080
# Résultat : timeout (bloqué)

Pour isoler complètement un namespace ou un groupe de Pods, commencez par bloquer tout le trafic entrant :

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # Tous les Pods du namespace
policyTypes:
- Ingress
# Pas de section ingress = rien n'est autorisé

Cette policy :

  • Sélectionne tous les Pods du namespace production
  • Déclare qu’elle contrôle l’ingress
  • N’autorise aucune connexion entrante (pas de règle ingress)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-ingress-backend
namespace: default
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress: []

Restreindre les connexions sortantes est tout aussi important, mais nécessite plus d’attention car cela peut casser des fonctionnalités critiques.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
# Pas de section egress = rien n'est autorisé

C’est le premier réflexe dès que vous restreignez l’egress. Sans DNS, vos applications ne peuvent plus résoudre mon-service.namespace.svc.cluster.local.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: production
spec:
podSelector: {} # Tous les Pods du namespace
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53

Alternative plus simple (moins restrictive) :

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress-simple
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53

Cette version autorise le port 53 vers n’importe quelle destination. Plus permissive, mais plus simple à maintenir.

Voici une policy qui autorise un Pod à :

  • Résoudre le DNS
  • Accéder à une base de données PostgreSQL interne
  • Rien d’autre
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-egress-controlled
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress
egress:
# DNS
- ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
# PostgreSQL interne
- to:
- podSelector:
matchLabels:
app: postgresql
ports:
- protocol: TCP
port: 5432

Pour autoriser des flux entre namespaces, utilisez namespaceSelector.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-monitoring
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring

Pour cibler des Pods spécifiques dans un namespace spécifique :

ingress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring
podSelector:
matchLabels:
app: prometheus

Attention à la syntaxe : les deux sélecteurs dans le même item - signifie ET logique. Séparés, c’est OU logique :

# ET logique : namespace monitoring ET pod prometheus
- from:
- namespaceSelector:
matchLabels:
name: monitoring
podSelector:
matchLabels:
app: prometheus
# OU logique : namespace monitoring OU pod prometheus (dans le même namespace)
- from:
- namespaceSelector:
matchLabels:
name: monitoring
- podSelector:
matchLabels:
app: prometheus

ipBlock permet d’autoriser des plages d’adresses IP, typiquement pour des systèmes externes au cluster.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-external-api
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 203.0.113.0/24
except:
- 203.0.113.128/25
ports:
- protocol: TCP
port: 443

Pour éviter les fausses attentes, voici ce que les NetworkPolicies standard ne peuvent pas faire :

FonctionnalitéNetworkPolicyAlternative
Filtrer par URL/path HTTP❌ NonService mesh (Istio, Linkerd)
Authentification mutuelle (mTLS)❌ NonService mesh
Filtrer par méthode HTTP (GET, POST)❌ NonService mesh, API Gateway
Inspection de payload❌ NonWAF
Logging des connexions bloquées❌ NonCNI spécifique (Cilium, Calico)
Policies inter-clusters❌ NonSolutions multi-cluster

Les NetworkPolicies sont un premier niveau de segmentation réseau, pas une solution de sécurité applicative complète.

Quand un flux est bloqué (ou ne l’est pas alors qu’il devrait), suivez cette méthode :

  1. Lister les policies du namespace

    Fenêtre de terminal
    kubectl get networkpolicy -n production
  2. Examiner une policy en détail

    Fenêtre de terminal
    kubectl describe networkpolicy allow-frontend-to-backend -n production

    Vérifiez :

    • PodSelector : quels Pods sont ciblés ?
    • Allowing ingress traffic : quelles sources sont autorisées ?
    • Allowing egress traffic : quelles destinations sont autorisées ?
  3. Vérifier les labels des Pods

    Fenêtre de terminal
    kubectl get pods -n production --show-labels
    kubectl get pods -n production -l app=backend

    Un Pod sans le bon label ne sera pas sélectionné par la policy.

  4. Tester la connectivité

    Fenêtre de terminal
    # Depuis le Pod source
    kubectl exec -it deploy/frontend -n production -- nc -vz backend 8080
    # Test DNS
    kubectl exec -it deploy/frontend -n production -- nslookup backend
  5. Vérifier les deux côtés

    Si l’egress du source ET l’ingress de la destination sont restreints, vérifiez que les deux autorisent le flux.

    Fenêtre de terminal
    # Policies qui sélectionnent le Pod source (egress)
    kubectl get networkpolicy -n production -o json | \
    jq '.items[] | select(.spec.podSelector.matchLabels.app=="frontend")'
    # Policies qui sélectionnent le Pod destination (ingress)
    kubectl get networkpolicy -n production -o json | \
    jq '.items[] | select(.spec.podSelector.matchLabels.app=="backend")'
Fenêtre de terminal
# Pod de debug avec outils réseau
kubectl run netshoot --rm -it --image=nicolaka/netshoot -- bash
# Dans le pod netshoot
nslookup backend.production.svc.cluster.local
curl -v backend.production:8080
nc -vz backend.production 8080
# Vérifier si le CNI loggue les drops (Cilium)
kubectl logs -n kube-system -l k8s-app=cilium -c cilium-agent | grep -i drop
SymptômeCause probableSolution
Timeout vers un servicePolicy ingress manquante côté destinationAjouter une règle from
DNS ne résout plusEgress deny sans exception DNSAutoriser le port 53
Policy ignoréeCNI incompatibleVérifier le support NetworkPolicy
Pod non sélectionnéLabels incorrectsVérifier --show-labels
Flux autorisé inattenduUnion de plusieurs policiesLister toutes les policies applicables

Pour maintenir des policies lisibles dans le temps :

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
annotations:
description: "Autorise le frontend à accéder au backend sur le port API"
owner: "team-platform"
last-review: "2026-03-22"
spec:
# ...

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

7 questions
5 min.
90% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

  1. Lire une policy existante

    Identifiez rapidement : quels Pods sont sélectionnés (podSelector), quel trafic est contrôlé (policyTypes), quelles règles s’appliquent.

  2. Créer un default deny ingress

    podSelector: {}
    policyTypes: [Ingress]
    # Pas de section ingress
  3. Autoriser un flux spécifique

    Frontend vers backend, port 8080 :

    ingress:
    - from:
    - podSelector:
    matchLabels:
    app: frontend
    ports:
    - port: 8080
  4. Autoriser le DNS en egress

    Dès que vous restreignez l’egress, autorisez UDP/TCP 53.

  5. Diagnostiquer un blocage

    • kubectl get networkpolicy -n <ns>
    • kubectl describe networkpolicy <name>
    • kubectl get pods --show-labels
    • kubectl exec ... -- nc -vz <service> <port>
  1. Les NetworkPolicies opèrent au niveau L3/L4 (IP/port), pas HTTP
  2. Le CNI doit supporter l’enforcement des policies, sinon elles sont ignorées
  3. Un Pod devient isolé (ingress ou egress) dès qu’une policy le sélectionne
  4. Les règles autorisées sont l’union des policies applicables
  5. Une connexion doit être autorisée des deux côtés (source egress + destination ingress)
  6. Dès que l’egress est restreint, pensez au DNS (port 53)
  7. ipBlock est pour les IP externes stables, pas pour cibler des Pods
  8. Déclarez explicitement policyTypes pour éviter les ambiguïtés

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn