Veröffentlicht am

Kubernetes Network Security: Zero Trust umsetzen

Teilen:
Authors

Kubernetes Network Security: Network Policies, Service Mesh und Zero Trust

TL;DR

  • Standardmaessig erlaubt Kubernetes allen Pod-zu-Pod-Traffic -- ohne Network Policies ist euer Cluster ein flaches Netzwerk ohne Segmentierung
  • Startet mit Default-Deny-Policies pro Namespace und oeffnet dann gezielt nur die notwendigen Verbindungen (Least Privilege)
  • Ein Service Mesh (Istio oder Linkerd) ergaenzt Network Policies um mTLS-Verschluesselung und L7-Autorisierung
  • Linkerd hat deutlich weniger Overhead als Istio und ist fuer kleinere Teams oft die bessere Wahl
  • Zero Trust ist kein Produkt, sondern ein Architekturprinzip: jede Verbindung wird authentifiziert und autorisiert, auch cluster-intern

Das Problem: Kubernetes ist standardmaessig offen

Frisch installiertes Kubernetes hat keine Netzwerkbeschraenkungen. Jeder Pod kann mit jedem anderen Pod im Cluster kommunizieren, ueber Namespaces hinweg. Das ist praktisch fuer die Entwicklung, aber ein Sicherheitsrisiko in Produktion.

Stellt euch vor, ein Angreifer kompromittiert einen einzelnen Pod -- zum Beispiel ueber eine Schwachstelle in einer Bibliothek. Ohne Network Policies kann dieser Pod frei im gesamten Cluster kommunizieren: Datenbanken abfragen, andere Services ansprechen, Secrets aus dem API-Server lesen (sofern RBAC das erlaubt). Das ist Lateral Movement, und es ist der Grund, warum ein einzelner kompromittierter Container zum Cluster-weiten Vorfall werden kann.

Network Policies sind die erste Verteidigungslinie dagegen.

Network Policies: Grundlagen und Default-Deny

Network Policies sind Kubernetes-native Ressourcen, die den Traffic auf L3/L4-Ebene steuern. Sie werden von einem CNI-Plugin (Calico, Cilium, Weave) durchgesetzt. Wichtig: Das Standard-CNI kubenet unterstuetzt keine Network Policies. Prueft also zuerst, ob euer CNI-Plugin sie implementiert.

Der wichtigste erste Schritt: eine Default-Deny-Policy fuer jeden Namespace.

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

Diese Policy selektiert alle Pods im Namespace production (leerer podSelector) und verbietet jeglichen ein- und ausgehenden Traffic. Ab diesem Moment ist der Namespace isoliert. Kein Pod kann Verbindungen empfangen oder aufbauen, bis ihr explizite Allow-Policies erstellt.

Dann oeffnet ihr gezielt:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-api
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-server
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 8080
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api-to-database
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: api-server
      ports:
        - protocol: TCP
          port: 5432
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-egress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53

Drei Policies, und euer Namespace hat ein klares Kommunikationsmodell: Frontend spricht mit API, API spricht mit Datenbank, alle Pods duerfen DNS-Aufloesung machen. Alles andere ist geblockt.

Ein haeufig vergessener Punkt: DNS-Egress. Ohne die dritte Policy funktioniert keine Service-Discovery mehr, weil die Pods kube-dns nicht erreichen koennen.

CNI-Vergleich: Calico vs Cilium

Nicht jedes CNI-Plugin ist gleich. Die beiden relevantesten fuer Network Security:

FeatureCalicoCilium
Network Policy SupportKubernetes + eigene CRDsKubernetes + eigene CRDs
L7-Policies (HTTP)Ueber eigene CRDsNativ (eBPF-basiert)
VerschluesselungWireGuardWireGuard oder IPsec
Performance-OverheadGering (iptables/eBPF)Sehr gering (eBPF)
ObservabilityFlow LogsHubble (integriert)
LernkurveModeratSteiler
Kernel-AnforderungenStandardKernel >= 5.10 empfohlen

Cilium ist technisch ueberlegen, besonders bei L7-Policies und Observability durch Hubble. Calico ist ausgereifter und hat eine breitere Basis in bestehenden Installationen. Wenn ihr einen neuen Cluster aufsetzt, ist Cilium die Empfehlung. Bei bestehenden Calico-Installationen lohnt sich der Wechsel nur, wenn ihr konkret L7-Features braucht.

Service Mesh: mTLS und L7-Autorisierung

Network Policies arbeiten auf L3/L4: IP-Adressen und Ports. Sie koennen nicht zwischen HTTP GET und HTTP POST unterscheiden, keine Pfade filtern und keinen Traffic verschluesseln.

Ein Service Mesh schliesst diese Luecke. Es injiziert einen Sidecar-Proxy (typischerweise Envoy) in jeden Pod, der den gesamten Netzwerk-Traffic abfaengt. Dadurch kann das Mesh:

  • mTLS automatisch aktivieren (jede Verbindung ist verschluesselt und beidseitig authentifiziert)
  • L7-Autorisierung durchsetzen (Service A darf nur GET auf /api/health von Service B ausfuehren)
  • Observability bereitstellen (Request Rate, Error Rate, Latenz pro Service-Paar)

Istio vs Linkerd

AspektIstioLinkerd
Sidecar-ProxyEnvoylinkerd2-proxy (Rust)
Memory pro Sidecarca. 50-100 MBca. 10-20 MB
Control Plane FootprintGross (istiod, ca. 1-2 GB)Klein (ca. 200-500 MB)
Feature-UmfangSehr umfangreichFokussiert auf Kernfeatures
L7-AuthorizationAuthorizationPolicy (maechtig)Server/ServerAuthorization
Multi-ClusterJa (komplex)Ja (einfacher)
LernkurveSteilModerat
CNCF-StatusGraduatedGraduated

Fuer Teams unter 10 Personen ist Linkerd meist die bessere Wahl. Weniger Konfiguration, geringerer Ressourcenverbrauch, schnellere Time-to-Value. Istio lohnt sich, wenn ihr fortgeschrittenes Traffic Management braucht (Canary Deployments mit gewichteten Routing-Regeln, komplexe Retry-Policies, WASM-Plugins).

Beispiel: Istio AuthorizationPolicy

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: api-server-policy
  namespace: production
spec:
  selector:
    matchLabels:
      app: api-server
  action: ALLOW
  rules:
    - from:
        - source:
            principals:
              - "cluster.local/ns/production/sa/frontend"
      to:
        - operation:
            methods: ["GET", "POST"]
            paths: ["/api/v1/*"]
    - from:
        - source:
            principals:
              - "cluster.local/ns/monitoring/sa/prometheus"
      to:
        - operation:
            methods: ["GET"]
            paths: ["/metrics"]

Diese Policy erlaubt dem Frontend-ServiceAccount GET und POST auf /api/v1/* und Prometheus GET auf /metrics. Alles andere wird abgelehnt. Das ist deutlich granularer als eine Network Policy.

Zero Trust: Mehr als ein Buzzword

Zero Trust wird oft als Produkt verkauft, ist aber ein Architekturprinzip. Die Kernidee: Vertraue keiner Verbindung nur wegen ihrer Herkunft im Netzwerk. Jede Anfrage muss sich authentifizieren und autorisieren.

In Kubernetes setzt ihr Zero Trust durch die Kombination von:

  1. Network Policies -- Netzwerk-Segmentierung als Basis
  2. mTLS via Service Mesh -- Jede Verbindung ist verschluesselt und authentifiziert
  3. Workload Identity -- Pods werden ueber ServiceAccounts und SPIFFE-IDs identifiziert, nicht ueber IP-Adressen
  4. L7 Authorization Policies -- Zugriff wird pro Service, Pfad und Methode gesteuert
  5. RBAC -- API-Server-Zugriff ist rollenbasiert beschraenkt

Die Schichten ergaenzen sich. Network Policies allein sind kein Zero Trust (kein mTLS, kein L7). Ein Service Mesh allein reicht auch nicht (kein Schutz gegen Pods ausserhalb des Mesh). Erst die Kombination ergibt ein vollstaendiges Modell.

Schrittweise Einfuehrung

Alles auf einmal einzufuehren ist ein Rezept fuer Ausfaelle. Hier ein pragmatischer Stufenplan:

Phase 1 (Woche 1-3): Network Policies

  • CNI-Plugin pruefen (Calico/Cilium vorhanden?)
  • Default-Deny in einem Test-Namespace einrichten
  • Kommunikationsmatrix der Services dokumentieren
  • Allow-Policies schreiben und testen
  • Auf weitere Namespaces ausrollen

Phase 2 (Woche 4-6): Service Mesh Pilot

  • Istio oder Linkerd in einem Test-Namespace installieren
  • mTLS im Permissive Mode aktivieren (verschluesselt, aber erzwingt nicht)
  • Traffic-Metriken in Grafana visualisieren
  • Anomalien und unerwartete Verbindungen identifizieren

Phase 3 (Woche 7-9): mTLS Strict und L7 Policies

  • mTLS auf Strict Mode umstellen (unverschluesselter Traffic wird abgelehnt)
  • L7-Authorization-Policies fuer kritische Services schreiben
  • Alerting fuer Policy-Verletzungen einrichten

Phase 4 (Woche 10-12): Rollout und Haertung

  • Service Mesh auf Produktions-Namespaces ausweiten
  • Egress-Policies fuer externen Traffic definieren
  • Penetration Test durchfuehren
  • Dokumentation und Runbooks erstellen

Haeufige Fehler

Fehler 1: Network Policies ohne CNI-Support deployen. Die Policies werden von Kubernetes akzeptiert, aber nicht durchgesetzt. Ihr habt ein falsches Sicherheitsgefuehl. Testet immer, ob der Traffic tatsaechlich geblockt wird.

Fehler 2: DNS-Egress vergessen. Nach dem Default-Deny funktioniert keine Service-Discovery mehr. Immer eine Egress-Policy fuer kube-dns mitsenden.

Fehler 3: mTLS im Strict Mode ohne Rollout-Plan. Wenn ein Service noch keinen Sidecar hat, wird er von Services im Mesh nicht mehr erreicht. Startet mit Permissive Mode und wechselt erst nach vollstaendigem Rollout auf Strict.

Fehler 4: Zu breite Namespace-Selektoren. namespaceSelector: {} selektiert alle Namespaces, einschliesslich kube-system. Seid praezise mit Labels.

Fehler 5: Network Policies nicht versionieren. Policies gehoeren ins Git-Repository, nicht in kubectl apply aus der Shell. Behandelt sie wie Code.

Monitoring und Troubleshooting

Ohne Monitoring wisst ihr nicht, ob eure Policies funktionieren. Nuetzliche Tools:

  • Cilium Hubble: Echtzeit-Flow-Logs und Policy-Verdicts (allowed/denied)
  • Calico Flow Logs: Aehnlich, aber weniger integriert
  • Istio/Linkerd Dashboards: Request-Metriken pro Service-Paar
  • np-viewer (Open Source): Visualisiert Network Policies als Graph

Ein guter Test: Deployt einen Debug-Pod und versucht, Verbindungen aufzubauen, die geblockt sein sollten:

# Debug-Pod ohne spezifische Labels deployen
kubectl run nettest --rm -it --restart=Never \
  --image=nicolaka/netshoot \
  --namespace=production \
  -- bash

# Innerhalb des Pods: Verbindung zur Datenbank versuchen
curl -v postgres:5432
# Sollte timeout/connection refused ergeben

# DNS pruefen
nslookup api-server.production.svc.cluster.local

Wenn der Debug-Pod die Datenbank erreichen kann, ist eure Network Policy falsch konfiguriert.

Weitergehende Themen

Wenn ihr Unterstuetzung bei der Netzwerk-Segmentierung oder Service-Mesh-Einfuehrung in eurem Cluster braucht, meldet euch unter /kontakt.

Kubernetes-Beratung gesucht?

Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen