Cheveo Blog
managed-kubernetes 11 min Lesezeit ·

Kubernetes NetworkPolicy Cheatsheet: 12 Patterns zum Copy-Pasten

NetworkPolicies sind mächtig aber verwirrend. 12 produktionsreife YAML-Patterns für Ingress, Egress, Namespace-Isolation und Monitoring. Inklusive AND-vs-OR-Falle.

Clemens Christen
Clemens Christen Certified Kubernetes Administrator (CKA)

TL;DR - NetworkPolicies sind Kubernetes-eigene Firewall-Regeln auf Pod-Ebene. Ohne sie ist aller Traffic erlaubt. 12 Copy-Paste-Patterns decken 90% der Production-Fälle ab: von Deny-All-Default bis Prometheus-Scraping und DNS-Egress. Die größte Falle ist die AND-vs-OR-Semantik bei Selektoren.

🔖 Nur die YAMLs? Hier ist der interaktive NetworkPolicy-Cheatsheet - mit Copy-Button pro Pattern und häufigen Fehlern. Lesezeichen empfohlen.

Wie NetworkPolicies funktionieren

Das Mentalmodell in drei Sätzen:

  1. Ohne Policy ist alles erlaubt. Jeder Pod kann mit jedem Pod in jedem Namespace reden. Das ist der Kubernetes-Default.
  2. Sobald eine Policy auf einen Pod matched, ist alles blockiert was nicht explizit erlaubt ist. Ein podSelector: {} matched alle Pods im Namespace.
  3. Policies sind additiv. Mehrere Policies auf demselben Pod widersprechen sich nie, sie vereinigen ihre Allows.

Wichtig: NetworkPolicies brauchen ein CNI-Plugin das sie durchsetzt. Cilium, Calico und Weave Net tun das. Standard-kubenet in manchen Managed-K8s-Setups ignoriert Policies stillschweigend. Das ist die tückischste Falle: Sie schreiben Policies, testen auf dem Cluster, alles funktioniert weiterhin, und Sie denken “Policy greift”. In Wahrheit greift nichts.

# CNI prüfen
kubectl get pods -n kube-system -l k8s-app=cilium
kubectl get pods -n kube-system -l k8s-app=calico-node

Die AND-vs-OR-Falle

Die häufigste Verwechslung bei NetworkPolicies. Zwei Selektoren im from:-Block verhalten sich unterschiedlich je nach Formatierung:

OR (zwei separate Listenelemente):

ingress:
  - from:
      - namespaceSelector:          # Listenelement 1
          matchLabels:
            name: monitoring
      - podSelector:                # Listenelement 2
          matchLabels:
            app: prometheus

Bedeutet: Traffic von allen Pods aus Namespace “monitoring” ODER von allen Pods mit Label app=prometheus im eigenen Namespace. Viel offener als gewollt.

AND (ein einziges Listenelement):

ingress:
  - from:
      - namespaceSelector:          # Teil von Listenelement 1
          matchLabels:
            name: monitoring
        podSelector:                # auch Teil von Listenelement 1
          matchLabels:
            app: prometheus

Bedeutet: Traffic nur von Pods mit Label app=prometheus die sich im Namespace “monitoring” befinden. Das ist meistens was man will.

Der Unterschied sind zwei Zeichen im YAML: der Bindestrich vor podSelector. Mit Bindestrich: OR. Ohne: AND.

Die 12 Patterns

Deny-Defaults (die Basis)

Jeder Zero-Trust-Ansatz beginnt mit einem Deny-All. Erst alles blockieren, dann explizit erlauben.

Pattern 1: Deny All Ingress

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-ingress
  namespace: <ns>
spec:
  podSelector: {}
  policyTypes:
    - Ingress

Blockiert allen eingehenden Traffic zu allen Pods im Namespace. Kein ingress:-Block = keine Ausnahmen.

Pattern 2: Deny All Egress

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-egress
  namespace: <ns>
spec:
  podSelector: {}
  policyTypes:
    - Egress

Blockiert allen ausgehenden Traffic. Vorsicht: auch DNS ist blockiert. Pods können keine Service-Namen mehr auflösen. Immer mit Pattern 10 (DNS-Egress) kombinieren.

Pattern 3: Deny All (beides)

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

Komplette Isolation. Namespace ist stumm. Von hier aus Pattern für Pattern öffnen.

Namespace- und Pod-Zugriff

Pattern 4: Allow from Same Namespace

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-same-namespace
  namespace: <ns>
spec:
  podSelector: {}
  ingress:
    - from:
        - podSelector: {}
  policyTypes:
    - Ingress

Alle Pods im eigenen Namespace dürfen sich gegenseitig erreichen, aber nichts von außen. Das häufigste Pattern für interne Microservices.

Pattern 5: Allow from Specific Namespace

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-namespace
  namespace: <ns>
spec:
  podSelector: {}
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: backend
  policyTypes:
    - Ingress

Erlaubt Traffic aus einem bestimmten Namespace (hier: backend). Voraussetzung: der Quell-Namespace muss ein passendes Label haben (kubectl label namespace backend name=backend).

Pattern 6: Allow Specific Port Only

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-http-only
  namespace: <ns>
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
    - ports:
        - port: 8080
          protocol: TCP
      from:
        - podSelector: {}
  policyTypes:
    - Ingress

Nur Port 8080/TCP, nur aus dem eigenen Namespace. Alles andere blockiert.

1-Tag Intensiv-Workshop

Kubernetes Debugging - systematisch statt raten

Echte Production-Incidents nachstellen, kubectl-Workflows verinnerlichen, Root-Causes in Minuten finden.

Workshop-Details ansehen

Infrastruktur-Zugriff

Pattern 7: Allow from Ingress Controller

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-ingress
  namespace: <ns>
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx
  policyTypes:
    - Ingress

Erlaubt eingehenden Traffic vom Ingress-Controller-Namespace. Ohne dieses Pattern ist Ihre App von außen nicht erreichbar, auch wenn der Ingress korrekt konfiguriert ist. Gängige Labels: ingress-nginx, traefik, istio-ingress.

Pattern 8: Allow Prometheus Scraping (AND-Variante)

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-prometheus
  namespace: <ns>
spec:
  podSelector: {}
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: monitoring
          podSelector:
            matchLabels:
              app.kubernetes.io/name: prometheus
      ports:
        - port: 9090
          protocol: TCP
  policyTypes:
    - Ingress

AND-Variante: nur Prometheus (Label app.kubernetes.io/name: prometheus) aus dem Monitoring-Namespace. Port auf den Metrics-Port Ihrer App anpassen.

Pattern 9: Allow from Specific Pod (Database-Zugriff)

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-backend-to-db
  namespace: <ns>
spec:
  podSelector:
    matchLabels:
      app: database
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: backend
      ports:
        - port: 5432
          protocol: TCP
  policyTypes:
    - Ingress

Nur der Backend-Pod darf auf die Datenbank zugreifen, nur auf Port 5432.

Egress-Kontrolle

Pattern 10: Allow DNS Egress Only

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

Das wichtigste Egress-Pattern. Ohne DNS-Egress können Pods keine Service-Namen auflösen: curl http://api-service:8080 schlägt fehl, obwohl der Pod eigentlich erreichbar wäre. Immer mit Deny-All-Egress (Pattern 2 oder 3) kombinieren.

Pattern 11: Allow Egress to External CIDR

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-egress-to-db
  namespace: <ns>
spec:
  podSelector:
    matchLabels:
      app: backend
  egress:
    - to:
        - ipBlock:
            cidr: 10.0.0.0/24
      ports:
        - port: 5432
          protocol: TCP
    - ports:
        - port: 53
          protocol: UDP
  policyTypes:
    - Egress

Backend darf nur an eine externe Datenbank (Subnet 10.0.0.0/24, Port 5432) und DNS. Für RDS, Cloud SQL oder Managed-DB-Instanzen außerhalb des Clusters.

Pattern 12: Allow Egress to Internal Service

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-api
  namespace: <ns>
spec:
  podSelector:
    matchLabels:
      app: frontend
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: api
      ports:
        - port: 8080
          protocol: TCP
    - ports:
        - port: 53
          protocol: UDP
  policyTypes:
    - Egress

Frontend darf nur mit dem API-Service reden (Port 8080) und DNS.

Die 5 häufigsten Fehler

  1. DNS-Egress vergessen. Deny-All-Egress ohne DNS-Allow (Pattern 10) → alle Verbindungen schlagen fehl, obwohl Ingress-Policies korrekt sind.
  2. AND vs OR verwechselt. Ein Bindestrich Unterschied im YAML öffnet den Zugriff viel weiter als gewollt. Immer explizit testen.
  3. Namespace-Labels fehlen. namespaceSelector matcht auf Labels des Namespaces, nicht auf den Namen. Labels manuell setzen: kubectl label namespace <ns> name=<ns>.
  4. CNI enforced nicht. Policies existieren im API, werden aber von kubenet ignoriert. kubectl get pods -n kube-system | grep cilium prüfen.
  5. Policies nur auf Ingress, Egress vergessen. Ingress-Policies allein kontrollieren nicht den ausgehenden Traffic. Für Zero-Trust braucht es beides.

Wie es weitergeht

Im Kubernetes Debugging Workshop simulieren wir unter anderem einen Incident, bei dem eine fehlende NetworkPolicy zu unbeabsichtigtem Cross-Namespace-Traffic führt, und debuggen ihn systematisch.

Verwandt aus unserer Serie:

1-Tag Intensiv-Workshop

Kubernetes Debugging - systematisch statt raten

Echte Production-Incidents nachstellen, kubectl-Workflows verinnerlichen, Root-Causes in Minuten finden.

Workshop-Details ansehen
Kostenfrei · 30 Minuten

Brauchen Sie eine zweite Meinung zu Ihrem Cluster?

Buchen Sie einen kostenfreien 30-Minuten Kubernetes Health-Check. Wir schauen uns Ihr Setup an und geben konkrete Hinweise, ohne Verkaufsgespräch.

Termin buchen