Le modèle de réseau de Kubernetes définit un ensemble de règles fondamentales pour la connectivité au sein du cluster :
Ce modèle crée un réseau "plat" où les Pods et les nœuds peuvent communiquer directement en utilisant les adresses IP des Pods. C'est la base sur laquelle les autres abstractions réseau (comme les Services) sont construites.
Le modèle réseau de Kubernetes est une spécification. Sa mise en œuvre concrète est déléguée aux plugins CNI. Ces plugins sont responsables de :
Il existe de nombreux plugins CNI disponibles (ex: Calico, Flannel, Cilium, Weave Net), chacun avec ses propres caractéristiques et mécanismes sous-jacents (ex: utilisation de VXLAN, BGP, eBPF).
Important : Un cluster Kubernetes n'est pas fonctionnel sans un plugin CNI installé et configuré. Les nœuds resteront généralement à l'état
NotReady
tant qu'un CNI n'est pas opérationnel, car le Kubelet ne peut pas finaliser la configuration réseau des Pods.
Par défaut, dans Kubernetes, la communication est totalement ouverte : tous les Pods peuvent communiquer avec tous les autres Pods, quels que soient leurs namespaces. Les Network Policies permettent de restreindre ce trafic au niveau réseau (couches 3 et 4), agissant comme un pare-feu au sein du cluster.
Important : Pour que les Network Policies aient un effet, le plugin CNI utilisé dans le cluster doit les supporter (ex: Calico, Cilium, Weave Net le supportent ; Flannel seul ne le supporte pas).
Une Network Policy sélectionne un groupe de Pods (via podSelector
) et définit des règles pour le trafic entrant (ingress
) et/ou sortant (egress
) pour ces Pods.
Comportement clé :
Champs principaux d'une Network Policy (networking.k8s.io/v1
) :
metadata.namespace
: Une Network Policy est un objet namespacé, elle ne s'applique qu'aux Pods du namespace où elle est créée.spec.podSelector
: Sélectionne les Pods auxquels cette policy s'applique. Si omis, la policy s'applique à tous les Pods du namespace.spec.policyTypes
: Liste contenant Ingress
, Egress
, ou les deux. Indique si la policy définit des règles pour le trafic entrant, sortant, ou les deux. Si omis, et qu'une section ingress
ou egress
est définie, le type correspondant est automatiquement ajouté. Si omis et qu'aucune section ingress
/egress
n'est définie, cela dépend de la présence de podSelector
(voir la documentation pour les détails, mais il est recommandé de toujours le spécifier clairement).spec.ingress
: Liste de règles pour le trafic entrant autorisé.
from
: Spécifie les sources autorisées. Peut contenir ipBlock
, namespaceSelector
, podSelector
.ports
: Spécifie les ports et protocoles autorisés depuis ces sources.spec.egress
: Liste de règles pour le trafic sortant autorisé.
to
: Spécifie les destinations autorisées. Peut contenir ipBlock
, namespaceSelector
, podSelector
.ports
: Spécifie les ports et protocoles autorisés vers ces destinations.Politique d'isolation par défaut : Pour isoler tous les Pods d'un namespace par défaut (tout bloquer), on peut créer une Network Policy avec un
podSelector
vide qui s'applique à tous les Pods et qui n'a aucune règleingress
/egress
définie (ou des listes vides[]
).apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all namespace: mon-namespace spec: podSelector: {} policyTypes: - Ingress - Egress
from
et to
Les clauses from
(pour ingress) et to
(pour egress) sont des listes. Chaque élément de la liste spécifie une source/destination autorisée. Si plusieurs éléments sont présents dans la liste from
/to
, le trafic est autorisé s'il correspond à au moins un de ces éléments (logique OU).
Chaque élément peut contenir une combinaison de ipBlock
, namespaceSelector
, et podSelector
. Si plusieurs de ces sélecteurs sont présents dans le même élément from
/to
, le trafic doit correspondre à tous ces sélecteurs (logique ET).
Reprenons l'exemple d'un serveur Nginx et d'un client AlpineCurl dans un namespace wiki-test
.
Création du Namespace et Label :
kubectl create namespace wiki-test
kubectl label namespace wiki-test team=wiki-test
Déploiement du serveur Nginx :
apiVersion: v1
kind: Pod
metadata:
name: wiki-nginx
namespace: wiki-test
labels:
app: nginx # Label pour le pod Nginx
spec:
containers:
- name: nginx
image: nginx:1.27
Déploiement du Pod client :
apiVersion: v1
kind: Pod
metadata:
name: wiki-alping
namespace: wiki-test
labels:
app: client
spec:
containers:
- name: alpine
image: curlimages/curl
command: ['sh', '-c', 'while true; do sleep 3600; done']
Appliquer ces deux manifestes YAML.
Vérification initiale (tout est ouvert) :
# Obtenir l'IP du pod Nginx
NGINX_IP=$(kubectl get pod wiki-nginx -n wiki-test -o jsonpath='{.status.podIP}')
echo "IP Nginx: $NGINX_IP"
# Exécuter curl depuis le pod alping vers l'IP Nginx
kubectl exec -n wiki-test wiki-alpine -- curl -s --connect-timeout 2 $NGINX_IP | grep title
# Sortie attendue : <title>Welcome to nginx!</title>
La connexion réussit car aucune Network Policy n'est en place.
Appliquer une politique "deny-all" pour Nginx :
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-nginx-all
namespace: wiki-test
spec:
podSelector:
matchLabels:
app: nginx # S'applique uniquement aux pods Nginx
policyTypes:
- Ingress
- Egress
# Aucune règle ingress/egress = tout bloquer
Appliquer ce manifeste.
Retester la connexion :
kubectl exec -n wiki-test wiki-alpine -- curl -s --connect-timeout 2 $NGINX_IP | grep title
# Aucune sortie attendue, la commande devrait échouer (timeout ou connexion refusée)
# On peut vérifier le code de sortie: kubectl exec -n wiki-test wiki-alpine -- curl -s --connect-timeout 2 $NGINX_IP > /dev/null; echo $?
# Devrait retourner un code non-nul (ex: 28 pour timeout)
La connexion échoue car le pod wiki-nginx
est maintenant isolé.
Modifier la politique pour autoriser l'ingress depuis le même namespace sur le port 80 :
Modifier le manifeste deny-nginx-all.yaml
(ou créer une nouvelle policy plus spécifique) :
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-nginx-ingress
namespace: wiki-test
spec:
podSelector:
matchLabels:
app: nginx
policyTypes:
- Ingress # On ne définit que les règles d'Ingress ici
ingress:
- from:
# Autoriser depuis n'importe quel pod dans le même namespace
# On pourrait être plus spécifique avec podSelector:
# matchLabels:
# app: client
- podSelector: {}
ports:
- protocol: TCP
port: 80
# Note: Egress reste non défini, donc tout egress est toujours bloqué si une policy
# Egress s'appliquait aussi (ce qui n'est pas le cas ici si on supprime 'deny-nginx-all')
# Ou si on avait mis 'Egress' dans policyTypes sans règle egress.
Appliquer ce manifeste (après avoir supprimé deny-nginx-all
ou en s'assurant que celui-ci ne bloque plus l'ingress).
Retester la connexion :
kubectl exec -n wiki-test wiki-alpine -- curl -s --connect-timeout 2 $NGINX_IP | grep title
# Sortie attendue : <title>Welcome to nginx!</title>
La connexion devrait maintenant réussir.
Nettoyage :
kubectl delete namespace wiki-test