Retour au cours

infra / kubernetes

Networking avancé : NetworkPolicy

Leçon 191 exercice

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.

ÉtapeAction
1. Deny by defaultBloquer tout le trafic entrant et sortant d'un namespace sensible
2. Autorisation expliciteOuvrir un par un les flux réellement nécessaires (frontend vers API, API vers base)
3. Vérification DNSToujours garder le port 53 ouvert en sortie, sous peine de casser toute résolution de nom
4. Vérification CNIConfirmer 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".

yaml
# 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
yaml
# 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
yaml
# 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
yaml
# 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
bash
# 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 production

Résumé

  • Sans NetworkPolicy, le réseau du cluster est totalement ouvert entre tous les Pods.
  • Modèle recommandé : default-deny-all puis 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

1 disponible
1

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.

Résoudre l’exercice →