infra / kubernetes
Networking avancé : NetworkPolicy
Explication
Ce que vous allez apprendre
- Comprendre que tous les Pods communiquent librement entre eux par défaut, sans restriction
- Appliquer le modèle de sécurité "deny by default" avec une NetworkPolicy
- Autoriser explicitement seulement les flux réseau réellement nécessaires
- Éviter le piège classique du blocage accidentel de la résolution DNS (port 53)
- Vérifier que le plugin réseau (CNI) du cluster applique réellement les NetworkPolicy
Dans quel contexte ?
Une entreprise héberge sur le même cluster une application de test, ouverte à des développeurs externes pour une démo, et sa base de données de production. Un jour, un des Pods de test est compromis via une dépendance vulnérable. Sans NetworkPolicy, rien n'empêche cet attaquant de scanner le réseau interne du cluster et de se connecter directement à la base de production depuis ce Pod compromis, comme si les deux applications partageaient le même réseau local. Cette leçon montre comment verrouiller ces communications avec un modèle "tout refuser, puis autoriser explicitement".
Un fait souvent méconnu et pourtant crucial
D'abord, voici un fait à connaître impérativement : par défaut, dans un cluster Kubernetes, absolument tous les Pods peuvent communiquer librement avec tous les autres, quel que soit leur namespace.
Le risque concret que ça représente
Un Pod compromis dans une application de test pourrait donc, en théorie, essayer de contacter directement la base de données de production, si rien n'en empêche le trafic réseau.
L'outil qui reprend le contrôle
La NetworkPolicy existe pour reprendre le contrôle de ces communications, un peu comme un pare-feu interne au cluster.
| Étape | Action |
|---|---|
| 1. Deny by default | Bloquer tout le trafic entrant et sortant d'un namespace sensible |
| 2. Autorisation explicite | Ouvrir un par un les flux réellement nécessaires (frontend vers API, API vers base) |
| 3. Vérification DNS | Toujours garder le port 53 ouvert en sortie, sous peine de casser toute résolution de nom |
| 4. Vérification CNI | Confirmer que le plugin réseau du cluster applique réellement les NetworkPolicy |
Piège fréquent
En verrouillant le trafic sortant (egress) d'un Pod, on oublie très souvent d'autoriser le port 53 utilisé par la résolution DNS. Conséquence : le Pod ne peut plus résoudre AUCUN nom de domaine, ni interne ni externe, ce qui casse son fonctionnement de façon confuse si on ne pense pas immédiatement à cette cause précise.
Le principe à appliquer : tout refuser d'abord
La bonne pratique de sécurité ici, comme ailleurs, est le modèle "deny by default" : on commence par tout interdire dans un namespace sensible.
Puis on autorise seulement ce qui est justifié
Ensuite, on autorise explicitement, un par un, uniquement les flux réellement nécessaires : le frontend peut parler à l'API, l'API peut parler à la base. Cette approche inverse la logique par défaut, bien plus sûre en pratique.
Un piège qui casse silencieusement une application
Un piège très courant : en verrouillant le trafic sortant (egress) d'un Pod, on oublie souvent d'autoriser le port 53 utilisé par la résolution DNS.
La conséquence de cet oubli
Résultat : le Pod ne peut plus résoudre AUCUN nom de domaine, ni interne ni externe, ce qui casse son fonctionnement de façon souvent confuse à diagnostiquer si on ne pense pas immédiatement au DNS.
Prérequis
Cette leçon suppose les namespaces et les Services déjà connus : une NetworkPolicy cible du trafic entre Pods et namespaces, en s'appuyant sur les mêmes labels que ceux déjà utilisés pour les Services.
Une dépendance technique à vérifier avant de compter dessus
Point important : les NetworkPolicy ne sont pas appliquées par Kubernetes lui-même, mais par le plugin réseau (CNI) installé dans le cluster.
Ce qui peut rendre cette protection illusoire
Certains plugins basiques, comme flannel dans sa configuration la plus simple, ignorent silencieusement les NetworkPolicy : elles semblent acceptées mais n'ont aucun effet réel. Vérifie toujours que le CNI utilisé, comme Calico ou Cilium, les supporte réellement avant de compter dessus pour la sécurité.
La dernière leçon de ce cours rassemble toutes ces bonnes pratiques pour rendre une application réellement prête pour la production.
Commandes & code
NetworkPolicy
Par défaut, TOUS les Pods peuvent communiquer entre eux sans restriction. Les NetworkPolicy imposent un modèle "deny by default".
# 1. Politique de base : tout refuser par défaut dans le namespace "production"
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {} # s'applique à TOUS les Pods du namespace
policyTypes:
- Ingress
- Egress# 2. Autoriser explicitement : l'API peut recevoir du trafic depuis le frontend uniquement
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-api
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 3000# 3. L'API peut sortir vers la base de données ET le DNS interne (obligatoire sinon rien ne résout)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-api-egress
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53 # DNS - à oublier ici casse TOUTE résolution de noms pour ce Pod
- protocol: TCP
port: 53# 4. Autoriser le trafic venant d'un AUTRE namespace précis (ex: un Ingress Controller dédié)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-controller
namespace: production
spec:
podSelector:
matchLabels:
app: frontend
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx# Les NetworkPolicy nécessitent un plugin CNI qui les supporte (Calico, Cilium...)
# flannel "pur" les ignore silencieusement -> toujours vérifier le CNI installé
kubectl get networkpolicy -n production
kubectl describe networkpolicy default-deny-all -n productionRésumé
- Sans NetworkPolicy, le réseau du cluster est totalement ouvert entre tous les Pods.
- Modèle recommandé :
default-deny-allpuis autorisations explicites par flux. - Ne jamais oublier d'autoriser le DNS (port 53) en egress, sinon plus aucune résolution de nom.
- Le plugin CNI doit supporter les NetworkPolicy (Calico, Cilium) : flannel basique les ignore.
Exercices pratiques
Mission : empêcher un Pod de test compromis d'atteindre la production
Objectif : Verrouiller le trafic réseau du namespace production avec un modèle deny by default, sans casser la résolution DNS ni oublier de vérifier le support réel du CNI.
Contexte
Le cluster héberge à la fois une application de test ouverte à des développeurs externes et la base de données de production postgres, dans le namespace production. Un Pod de test vient d'être identifié comme compromis via une dépendance vulnérable. Rien n'empêche aujourd'hui ce Pod de scanner le réseau et de se connecter directement à postgres, comme si les deux applications partageaient le même réseau local. Il faut verrouiller ces communications avant qu'un incident réel ne survienne.