Veröffentlicht am

Netzwerk-Mikrosegmentierung in Kubernetes umsetzen

Teilen:
Authors

Netzwerk-Mikrosegmentierung in Kubernetes umsetzen

TL;DR

Mikrosegmentierung bedeutet, dass jeder Workload nur die Netzwerkverbindungen nutzen kann, die er tatsächlich braucht. In Kubernetes setzen Sie das mit Default-Deny pro Namespace, einer Zonen-Architektur (Frontend, Backend, Datenbank) und Cilium ClusterWide NetworkPolicies um. Dieser Guide zeigt die vollständige Implementierung mit kopierbaren YAML-Beispielen.


In klassischen Netzwerken trennen Firewalls grobe Zonen: DMZ, internes Netz, Datenbank-Segment. Kubernetes bringt standardmäßig keine solche Trennung mit. Jeder Pod kann jeden anderen Pod im Cluster erreichen -- über Namespace-Grenzen hinweg. Mikrosegmentierung geht einen Schritt weiter als klassische Segmentierung: Statt ganzer Netzsegmente werden einzelne Workloads isoliert.

Zonen-Architektur planen

Bevor Sie Policies schreiben, definieren Sie Ihre Zonen. Eine bewährte Architektur für die meisten Anwendungen:

ZoneNamespacesErlaubter IngressErlaubter Egress
DMZingress-systemExtern (Internet)Nur Frontend-Zone
Frontendapp-frontendNur DMZ-ZoneBackend-Zone, DNS
Backendapp-backendNur Frontend-ZoneDatenbank-Zone, externe APIs, DNS
Datenbankapp-databaseNur Backend-ZoneDNS
MonitoringmonitoringAlle Zonen (Scraping)Alerting-Ziele, DNS

Labels sind der Schlüssel. Versehen Sie jeden Namespace mit einem Zonen-Label:

# Namespaces mit Zonen-Labels erstellen
kubectl create namespace app-frontend
kubectl label namespace app-frontend zone=frontend

kubectl create namespace app-backend
kubectl label namespace app-backend zone=backend

kubectl create namespace app-database
kubectl label namespace app-database zone=database

kubectl create namespace monitoring
kubectl label namespace monitoring zone=monitoring

# Labels pruefen
kubectl get namespaces -L zone

Schritt 1: Default-Deny als Fundament

Ohne Default-Deny ist jede weitere Policy wirkungslos -- sie würde nur zusätzlichen Traffic erlauben, statt ihn einzuschränken. Setzen Sie Default-Deny in jeder Zone:

# default-deny.yaml -- auf alle Applikations-Namespaces anwenden
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: app-frontend  # Wiederholen fuer app-backend, app-database
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
---
# DNS-Egress erlauben -- ohne DNS funktioniert nichts
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-egress
  namespace: app-frontend  # Wiederholen fuer app-backend, app-database
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

Diese beiden Policies bilden die Baseline für jeden Namespace. Erst danach öffnen Sie gezielt die benötigten Pfade.

Schritt 2: Zonen-basierte Policies definieren

Jetzt verbinden Sie die Zonen miteinander. Die Regel ist einfach: Traffic darf nur in eine Richtung fließen -- von der DMZ zur Datenbank, nie umgekehrt.

Frontend-Zone: Ingress von DMZ, Egress zum Backend

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-ingress-from-dmz
  namespace: app-frontend
spec:
  podSelector:
    matchLabels:
      tier: frontend
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              zone: dmz
      ports:
        - protocol: TCP
          port: 3000
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-egress-to-backend
  namespace: app-frontend
spec:
  podSelector:
    matchLabels:
      tier: frontend
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              zone: backend
      ports:
        - protocol: TCP
          port: 8080

Backend-Zone: Ingress vom Frontend, Egress zur Datenbank

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-ingress-from-frontend
  namespace: app-backend
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              zone: frontend
          podSelector:
            matchLabels:
              tier: frontend
      ports:
        - protocol: TCP
          port: 8080
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-egress-to-database
  namespace: app-backend
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              zone: database
      ports:
        - protocol: TCP
          port: 5432

Datenbank-Zone: Nur Ingress vom Backend

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database-ingress-from-backend
  namespace: app-database
spec:
  podSelector:
    matchLabels:
      tier: database
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              zone: backend
          podSelector:
            matchLabels:
              tier: backend
      ports:
        - protocol: TCP
          port: 5432

Die Datenbank-Zone hat keinen erlaubten Egress außer DNS. Kein Pod in dieser Zone kann nach außen kommunizieren.

Schritt 3: Cilium ClusterWide NetworkPolicy

Standard-NetworkPolicies gelten immer pro Namespace. Das bedeutet: Sie müssen Default-Deny in jedem Namespace separat deployen. Bei 20+ Namespaces wird das unübersichtlich.

Cilium löst das mit CiliumClusterwideNetworkPolicy -- einer Policy, die clusterweit gilt:

apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: default-deny-all-namespaces
spec:
  endpointSelector:
    matchExpressions:
      - key: io.kubernetes.pod.namespace
        operator: NotIn
        values:
          - kube-system
          - cilium
  ingressDeny:
    - fromEntities:
        - all
  egressDeny:
    - toEntities:
        - all
---
# DNS clusterweit erlauben
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: allow-dns-cluster
spec:
  endpointSelector: {}
  egress:
    - toEndpoints:
        - matchLabels:
            k8s:io.kubernetes.pod.namespace: kube-system
            k8s:k8s-app: kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: UDP
            - port: "53"
              protocol: TCP

Der Vorteil: Neue Namespaces sind automatisch isoliert. Kein Team kann versehentlich einen Namespace ohne Default-Deny erstellen.

Monitoring-Zone: Scraping erlauben

Monitoring ist ein Sonderfall. Prometheus muss Metriken aus allen Zonen scrapen können:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-prometheus-scraping
  namespace: app-backend  # In jeder Zone wiederholen
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              zone: monitoring
          podSelector:
            matchLabels:
              app: prometheus
      ports:
        - protocol: TCP
          port: 9090
        - protocol: TCP
          port: 8080

Policies validieren

Deployte Policies ohne Validierung sind gefährlich. Testen Sie systematisch:

# Test: Frontend kann Backend erreichen
kubectl run test-frontend --rm -it \
  --image=curlimages/curl \
  --labels="tier=frontend" \
  -n app-frontend \
  -- curl -s --connect-timeout 5 -o /dev/null -w "%{http_code}" \
  http://api-service.app-backend.svc.cluster.local:8080/health

# Test: Frontend kann NICHT direkt auf Datenbank zugreifen
kubectl run test-blocked --rm -it \
  --image=curlimages/curl \
  --labels="tier=frontend" \
  -n app-frontend \
  -- curl -s --connect-timeout 3 \
  http://postgres.app-database.svc.cluster.local:5432
# Erwartung: Connection timeout nach 3 Sekunden

# Alle Policies in einem Namespace anzeigen
kubectl get networkpolicies -n app-backend -o wide

Mit Cilium Hubble können Sie den tatsächlichen Traffic-Flow in Echtzeit beobachten:

# Hubble CLI installieren und Traffic beobachten
hubble observe --namespace app-backend --verdict DROPPED
hubble observe --namespace app-backend --verdict FORWARDED

Typische Fallstricke

Vergessene Egress-Regeln für externe APIs: Wenn Ihr Backend einen Payment-Provider oder eine externe API aufruft, braucht es eine explizite Egress-Regel. Mit Cilium können Sie FQDN-basiert filtern statt IP-Bereiche zu pflegen.

Monitoring bricht: Prometheus, Liveness-Probes vom Kubelet und Ingress-Controller brauchen Ingress-Zugriff. Vergessen Sie nicht, den Kubelet-Zugriff für Health-Checks freizugeben.

Neue Namespaces ohne Policies: Ohne ClusterwideNetworkPolicy oder einen Admission Controller (OPA/Kyverno) können Teams Namespaces ohne Default-Deny erstellen. Das untergräbt die gesamte Segmentierung.

FAQ

Was ist der Unterschied zwischen Segmentierung und Mikrosegmentierung?

Klassische Segmentierung trennt Netzwerke auf Subnetz-Ebene (VLANs, Firewalls). Mikrosegmentierung geht granularer vor und isoliert einzelne Workloads oder Pods. In Kubernetes erreichen Sie Mikrosegmentierung durch NetworkPolicies, die auf Pod-Labels statt auf IP-Adressen basieren.

Brauche ich Cilium oder reicht Calico?

Für Standard-NetworkPolicies (L3/L4) reichen beide. Cilium bietet Vorteile bei ClusterwideNetworkPolicies, L7-Filtering (HTTP, gRPC), FQDN-basiertem Egress und eBPF-basierter Performance. Calico ist ausgereifter und hat eine breitere Installationsbasis.

Wie verhindere ich, dass Teams die Segmentierung umgehen?

Nutzen Sie einen Policy-as-Code-Ansatz mit OPA/Gatekeeper oder Kyverno. Definieren Sie eine Constraint, die NetworkPolicies in jedem Namespace erzwingt. Ohne Default-Deny-Policy darf kein Pod im Namespace starten.

Beeinträchtigt Mikrosegmentierung die Performance?

Standard-NetworkPolicies über iptables haben minimalen Overhead. Cilium mit eBPF ist in Benchmarks sogar schneller als ein Cluster ohne Policies, weil eBPF den Netzwerk-Stack effizienter durchläuft als iptables-Ketten. Bei tausenden Policies kann die Regelauswertung messbar werden -- in der Praxis ist das selten ein Problem.

Wie dokumentiere ich die Segmentierung für Audits?

Exportieren Sie alle NetworkPolicies als YAML und pflegen Sie eine Kommunikationsmatrix (welcher Service darf mit welchem kommunizieren). Tools wie Cilium Hubble oder kubectl-np-viewer visualisieren die tatsächlichen Policies. Für DSGVO-Audits nach Art. 32 dokumentieren Sie die Segmentierung als technisch-organisatorische Maßnahme.

Kubernetes-Security & Compliance?

Security-Audits, Penetration Tests und Compliance-Beratung für Ihre Container-Infrastruktur. BSI-Grundschutz, DSGVO, ISO 27001.

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