Kubernetes ~4 Min.

Istio: mTLS und Traffic Management auf der Plattform

PeerAuthentication, VirtualService und wer das Mesh betreibt.

von PlatPrep

Stell dir vor, du arbeitest in einem Finanzdienstleister. Audit kommt. Die Frage: “Ist die Kommunikation zwischen euren Microservices verschlüsselt?” — “Ja, wir haben TLS am Ingress.” — “Und intern, zwischen den Services?” Stille.

Das ist der Moment, wo mTLS im Cluster relevant wird. Und Istio ist einer der meistgenutzten Wege dorthin.

Wie das mTLS eigentlich zustande kommt

Istios automatisches mTLS läuft über den Sidecar-Proxy (Envoy). Beim Pod-Start fordert der Proxy bei Istiod ein Workload-Zertifikat an. Die Identität darin ist eine SPIFFE-ID, die direkt aus dem Kubernetes-ServiceAccount abgeleitet wird: spiffe://cluster.local/ns/payments/sa/checkout-sa. Die Zertifikate sind kurzlebig (per Default 24 Stunden) und werden automatisch rotiert — keine manuell verwalteten Zertifikate, kein Ablauf-Incident an einem Sonntag. Der Applikationscode merkt von alledem nichts: Die App spricht Klartext mit ihrem lokalen Sidecar, verschlüsselt wird zwischen den Proxys.

PeerAuthentication steuert, ob mTLS verpflichtend ist:

apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: default
  namespace: payments
spec:
  mtls:
    mode: STRICT

STRICT akzeptiert nur verschlüsselte Verbindungen, PERMISSIVE erlaubt beides. Permissive ist als Migrationsmodus gedacht, solange noch nicht alle Workloads Sidecars haben — und genau da geht es in der Praxis schief: Teams bleiben dauerhaft auf Permissive stehen, das Dashboard zeigt “mTLS aktiv”, aber ein Angreifer im Cluster-Netz kann weiterhin unverschlüsselt mit jedem Service reden. Für das Audit vom Anfang zählt nur Strict — idealerweise mesh-weit als Default im istio-system-Namespace, mit Namespace-Ausnahmen nur wo nötig.

Auf den Identitäten baut AuthorizationPolicy auf: Wer darf mit wem reden?

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: payment-ingress
  namespace: payments
spec:
  selector:
    matchLabels:
      app: payment
  action: ALLOW
  rules:
    - from:
        - source:
            principals: ["cluster.local/ns/shop/sa/checkout-sa"]
      to:
        - operation:
            methods: ["POST"]
            paths: ["/api/v1/charge"]

Das ist feingranularer als NetworkPolicies: Es operiert auf Layer 7 (Methoden, Pfade) und die Identität kommt aus dem kryptografisch verifizierten Zertifikat, nicht aus einer IP. Wichtig zu wissen: Sobald eine ALLOW-Policy auf einem Workload existiert, ist alles andere implizit verboten — wer das vergisst, sperrt sich beim ersten Rollout selbst aus.

Traffic Management: zwei CRDs, zwei Aufgaben

VirtualServices und DestinationRules klingen zunächst wie doppelter Overhead, leisten aber verschiedene Dinge. Ein VirtualService definiert Routing: 90 Prozent Traffic an Subset v1, 10 Prozent an v2, plus Timeouts und Retries pro Route. Eine DestinationRule definiert die Subsets (über Pod-Labels) und konfiguriert, wie Envoy mit dem Backend umgeht: Load-Balancing-Algorithmus, Connection-Pool-Grenzen und Outlier Detection — also das automatische Auswerfen von Endpoints, die wiederholt 5xx liefern. Letzteres ist der eingebaute Circuit Breaker und einer der unterschätztesten Stabilitätsgewinne des Meshes.

Zwei Praxis-Fallen: Retries sind per Default aktiv (zwei Versuche) — bei nicht-idempotenten Endpoints kann das doppelte Buchungen bedeuten, also bewusst konfigurieren. Und Canary-Gewichte im VirtualService verteilen Traffic nur korrekt, wenn die Subsets in der DestinationRule sauber auf die Deployment-Labels zeigen; ein Tippfehler im Label und 100 Prozent landen auf v1, ohne Fehlermeldung.

Beides zusammen ergibt das Standard-Muster für Canary-Releases: v2 mit 5 Prozent Gewicht starten, Error-Rate und Latenz der Subsets in den Istio-Metriken vergleichen, Gewicht schrittweise erhöhen. Tools wie Argo Rollouts oder Flagger automatisieren genau diese Schleife, indem sie die VirtualService-Gewichte anhand von Metrik-Schwellwerten selbst verschieben — das Mesh liefert die Mechanik, der Rollout-Controller die Entscheidung.

Praktischer Einstieg: erst Observability, dann Policies. Istio liefert ohne Zutun Request-Metriken, Tracing-Spans und Access-Logs; Kiali visualisiert den Service-Graphen. Wenn du erst einmal siehst, was tatsächlich miteinander redet, schreibst du AuthorizationPolicies auf Basis von Daten statt Vermutungen — und merkst vorher, welcher vergessene Cronjob sonst beim Umschalten auf Strict gestorben wäre.

Die ehrlichen Kosten

Was Istio schwierig macht, ist weniger die Installation als der Dauerbetrieb. Das CRD-Portfolio ist groß, Upgrades wollen mit Canary-Revisionen durchgeführt werden (zwei Control-Plane-Versionen parallel, Namespaces schrittweise umziehen), und Debugging verlangt Envoy-Verständnis — istioctl analyze und istioctl proxy-config werden zu täglichen Werkzeugen. Der Sidecar kostet Ressourcen: typischerweise einige zehn MB Memory pro Pod und etwa 1–2 ms zusätzliche Latenz pro Hop. Bei 500 Pods ist der Sidecar-Overhead ein eigener Posten auf der Cloud-Rechnung.

Genau dafür gibt es seit einiger Zeit den Ambient Mode: statt Sidecars übernimmt ein ztunnel-DaemonSet pro Node die mTLS-Schicht (L4), und nur wer L7-Features braucht, bekommt einen Waypoint-Proxy pro Namespace. Das senkt den Ressourcen-Overhead deutlich und entkoppelt Mesh-Upgrades von Pod-Restarts. Für neue Setups lohnt der Blick; wer nur mTLS und Basis-Observability braucht, sollte sich aber auch Linkerd als leichtere Alternative anschauen — und wer nur interne Zertifikate ohne Mesh will, kommt eventuell mit cert-manager und einer internen CA aus.

Für größere Umgebungen mit komplexen Traffic-Anforderungen bleibt Istio die vollständigste Lösung — wenn man die Lernkurve als Investition einplant und jemanden hat, der das Mesh im On-Call verantwortet. Schrittweise aufgebaut wird das alles im Istio-Lernpfad.