September 2026
M D M D F S S
 123456
78910111213
14151617181920
21222324252627
282930  

Kubernetes NetworkPolicies: Warum dein Cluster offen ist

Written in

von

Der blinde Fleck: uneingeschränkter Pod-zu-Pod-Traffic

Ohne explizite NetworkPolicy ist ein Kubernetes-Cluster netzwerkseitig flach. Jeder Pod kann jeden anderen Pod erreichen – unabhängig davon, in welchem Namespace er läuft. Das Frontend im Namespace shop kann direkt mit der Datenbank im Namespace billing sprechen, ein kompromittierter Debug-Pod kann in Sekunden jeden Service im Cluster abklappern, und auch nach außen ist Egress standardmäßig offen. Das ist keine Fehlkonfiguration einzelner Teams, sondern das Standardverhalten der meisten CNI-Implementierungen: Pods bekommen IP-Adressen aus einem gemeinsamen Netzwerk, und ohne eine Regel, die das einschränkt, wird jedes Paket geroutet.

In den letzten Wochen ging es hier um Admission Control mit Kyverno (03.08.), Runtime Security mit Falco (07.08.) und seccomp/AppArmor (29.08.) – also darum, was beim Erstellen eines Pods verhindert und was zur Laufzeit erkannt wird. NetworkPolicies setzen dazwischen an: Sie begrenzen, was ein bereits laufender Pod überhaupt erreichen kann, falls er kompromittiert wird. Kein Ersatz für Admission Control oder Falco, sondern die Segmentierung, die den Schaden eines Kompromisses eindämmt, bevor er sich lateral im Cluster ausbreitet.

Schnell testen lässt sich der Ausgangszustand mit einem Debug-Pod:

kubectl run --rm -it netcheck --image=busybox --restart=Never -- \
  wget -qO- --timeout=2 http://backend.other-namespace.svc.cluster.local:8080

Ohne NetworkPolicy antwortet das, egal aus welchem Namespace der Debug-Pod gestartet wird.

NetworkPolicy ist nur ein Vertrag – der CNI muss ihn einhalten

NetworkPolicy ist eine Kubernetes-Standardressource, aber sie ist deklarativ: Das API-Objekt existiert, sobald du es anlegst, unabhängig davon, ob irgendetwas es durchsetzt. Ob die Regel tatsächlich wirkt, entscheidet die CNI-Implementierung. Calico, Cilium und Weave Net implementieren eine Policy-Engine und setzen NetworkPolicies durch. Ein einfaches Flannel-Standardsetup ohne zusätzliche Policy-Engine tut das nicht – die Ressource lässt sich anlegen, wird aber stillschweigend ignoriert. Das ist der häufigste Stolperstein in der Praxis: Policies schreiben, kubectl apply laufen lassen, sich sicher fühlen, ohne dass am Datenpfad irgendetwas passiert ist. Vor der ersten Policy lohnt sich deshalb ein Blick in die CNI-Dokumentation des Clusters, nicht in die Kubernetes-Doku zu NetworkPolicy.

Default-Deny als Ausgangspunkt

Das Grundmuster ist Least Privilege statt Blockliste: erst alles zu, dann gezielt öffnen. Eine Policy mit leerem podSelector und leeren ingress/egress-Listen blockt jeglichen Traffic im Namespace:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: billing
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

Ab hier ist der Namespace billing komplett isoliert, ingress wie egress. Alles Weitere ist eine bewusste Ausnahme, keine implizite Erlaubnis.

Gezielt öffnen: nur das Frontend darf zum Backend

Danach erlaubst du exakt die Verbindungen, die gebraucht werden. Zum Beispiel: Nur Pods aus dem Namespace shop mit Label role: frontend dürfen den Backend-Service auf Port 8080 erreichen:

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

namespaceSelector und podSelector lassen sich kombinieren – die Regel greift nur, wenn beide Bedingungen zutreffen. Für Quellen außerhalb des Clusters gibt es zusätzlich ipBlock, um CIDR-Bereiche gezielt zuzulassen oder auszuschließen.

Der Klassiker: Default-Deny blockt auch DNS

Wer Default-Deny-Egress aktiviert und sich wundert, warum plötzlich gar nichts mehr funktioniert, ist meistens auf diesen Stolperstein gelaufen: DNS-Auflösung läuft über Port 53 zum CoreDNS-Service, und der wird von der Default-Deny-Regel mitblockiert. Ohne DNS kann kein Pod mehr Service-Namen auflösen – auch nicht die, die eigentlich erlaubt wären. Deshalb braucht praktisch jede Egress-Policy diese Ausnahme:

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

Wo die Grenze liegt

NetworkPolicy arbeitet auf Layer 3/4 – IP-Adressen, Namespaces, Ports. Sie kennt keine Workload-Identität, keine Verschlüsselung zwischen Pods und keine Layer-7-Regeln wie „nur GET-Requests auf /api/orders erlauben“. Das ist die Domäne eines Service Mesh wie Istio oder Linkerd, das mit mTLS und identitätsbasierten Policies eine Ebene höher ansetzt. NetworkPolicy ersetzt das nicht – sie ist die günstigere erste Stufe, die mit Bordmitteln des Clusters funktioniert, bevor ein Mesh überhaupt zur Debatte steht.

Schreiben ist nicht prüfen

Eine Policy, die nicht das tut, was du denkst, ist gefährlicher als keine Policy – sie erzeugt ein falsches Sicherheitsgefühl. Nach jeder Änderung lohnt sich ein Test mit einem Debug-Pod aus genau der Position, die die Policy erlauben soll, und aus einer Position, die sie verbieten soll:

kubectl run --rm -it -n shop probe --image=busybox --restart=Never \
  -- wget -qO- --timeout=2 http://backend.billing.svc.cluster.local:8080

Für einen schnellen Überblick über bestehende Policies in einem Namespace helfen Werkzeuge wie kubectl-np-viewer (ein Krew-Plugin für kubectl), die die effektiven Regeln visualisieren statt sie aus mehreren YAML-Dateien im Kopf zusammenzusetzen.

Woran es hier weitergeht

Kubernetes-Security ist hier ein wiederkehrendes Thema — von Admission Control über Laufzeit-Erkennung bis zur Netzwerksegmentierung, wie in diesem Artikel. Fragen oder Austausch dazu: mm@mhm-dl.de.

Hinterlasse einen Kommentar

Diese Seite verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden..