1 Grundlagen: Data Plane & Control Plane
Istio besteht aus zwei getrennten Ebenen: der Data Plane, die den eigentlichen Netzwerkverkehr
transportiert, und der Control Plane (istiod), die Konfiguration verteilt und Zertifikate
ausstellt. Kein Anwendungscode wird verändert. Der gesamte Netzwerkverkehr eines Pods wird transparent über einen
injizierten Envoy-Sidecar umgeleitet.
Control Plane: istiod
Verteilt Routing-Regeln, TLS-Zertifikate (mTLS) und Sicherheitsrichtlinien an alle Envoy-Proxys im Mesh. Selbst kein Teil des Datenpfads.
Data Plane: Envoy Sidecar
Ein Envoy-Proxy pro Pod, injiziert als zweiter Container. Fängt jeden ein- und ausgehenden
Netzwerkverkehr des Pods ab (via iptables oder eBPF).
Transparent für die App
Die Anwendung spricht wie gewohnt HTTP/gRPC über localhost oder DNS-Namen. Vom Sidecar merkt
sie im Idealfall nichts.
Sidecar Injection: Traffic-Interception im Pod
iptables-Regeln leiten allen In-/Outbound-Traffic des Pods zunächst durch den lokalen Envoy-Sidecar. istiod pusht Konfiguration & Zertifikate per gRPC (xDS-API) an jeden Sidecar.
2 Ingress Gateway: der Eintrittspunkt
Was macht das Ingress Gateway?
Ein eigenständiges Envoy-Deployment am Rand des Mesh (kein Sidecar!). Es terminiert externen
Traffic (TLS-Termination), ist über eine Gateway-Resource konfiguriert (Ports, Hosts, Zertifikate)
und benötigt zwingend ein VirtualService, das an dieses Gateway gebunden ist, um Requests
tatsächlich weiterzuleiten.
Externer Request trifft auf das Mesh
Gateway-Resource (Beispiel)
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: shop-ingress-gw
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: shop-tls-cert
hosts:
- "shop.example.com"
3 VirtualService: Layer-7-Routing
Wofür ist das VirtualService zuständig?
Definiert wie ein Request geroutet wird: Matching auf Host, URI-Pfad, Header oder Methode, Aufteilung auf mehrere Ziel-Subsets (z.B. Canary-Releases per Gewichtung), Retries, Timeouts und Fault-Injection. Ein VirtualService kann an ein Gateway (Nord-Süd-Traffic) oder ohne Gateway direkt im Mesh (Ost-West-Traffic zwischen Services) gebunden werden.
Routing-Beispiel: Canary-Release per Gewichtung
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews-route
spec:
hosts:
- reviews.prod.svc.cluster.local
http:
- match:
- headers:
x-canary:
exact: "true"
route:
- destination:
host: reviews.prod.svc.cluster.local
subset: v2
- route:
- destination:
host: reviews.prod.svc.cluster.local
subset: v1
weight: 90
- destination:
host: reviews.prod.svc.cluster.local
subset: v2
weight: 10
4 DestinationRule: Subsets & Policies
Wofür ist die DestinationRule zuständig?
Wird nach dem Routing-Entscheid des VirtualService angewendet. Definiert Subsets
(Pod-Gruppen anhand von Labels, z.B. version: v1), die Load-Balancing-Strategie
(Round Robin, Least Request, Consistent Hash), Connection-Pool-Limits, Outlier Detection
(Circuit Breaking) sowie den TLS-Modus für die Verbindung zum Ziel (ISTIO_MUTUAL für automatisches mTLS).
Subset-Auflösung & Load Balancing
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews-dr
spec:
host: reviews.prod.svc.cluster.local
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
loadBalancer:
simple: LEAST_REQUEST
outlierDetection:
consecutive5xxErrors: 3
interval: 10s
baseEjectionTime: 30s
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
5 Service, Sidecar & Zugriffskontrolle: Ost-West-Traffic im Detail
Kubernetes Service
Rein logische Abstraktion: stabiler DNS-Name + ClusterIP. Er ist kein zusätzlicher Netzwerk-Hop. Er liefert Envoy lediglich die Zieladresse, die tatsächliche Verbindung läuft direkt Pod-zu-Pod.
HTTP Client = die Anwendung selbst
Der "HTTP Client" ist der ganz normale HTTP-Client im Anwendungscode (z.B. RestTemplate,
fetch, requests). Er ruft den Service-DNS-Namen auf. Von der Umleitung
durch den Sidecar merkt er nichts.
Was zwischen Client-Aufruf und Antwort passiert
- App-Container ruft
http://payment.prod.svc.cluster.localauf, ganz normaler HTTP-Client-Code. iptablesim selben Pod-Netzwerk-Namespace fängt den Outbound-Call ab und leitet ihn transparent an den lokalen Envoy-Sidecar (Port 15001) um.- Der Outbound-Sidecar löst den Service-Namen über die von istiod gelieferte Endpoint-Liste auf, wendet VirtualService/DestinationRule an und wählt eine konkrete Ziel-Pod-IP per Load Balancing.
- Verbindung wird per mTLS aufgebaut und direkt zum Inbound-Sidecar des Ziel-Pods gesendet (Service/ClusterIP wird dabei nur für die initiale Namensauflösung benötigt).
- Inbound-Sidecar terminiert mTLS, prüft AuthorizationPolicies und reicht den Klartext-Request an den lokalen App-Container weiter (
localhost).
Ruft ein Microservice einen anderen auf, sind also immer zwei Sidecars beteiligt: der ausgehende Sidecar des Aufrufers und der eingehende Sidecar des Ziels. Dazwischen läuft die Verbindung automatisch mTLS-verschlüsselt und gegenseitig authentifiziert, ganz ohne Code-Änderung an den Microservices.
Microservice A → Sidecar A (outbound) → mTLS → Sidecar B (inbound) → Microservice B. Antwort läuft denselben Weg zurück.
Warum ist das sicher, ohne dass Entwickler etwas tun müssen?
istiod stellt jedem Sidecar ein kurzlebiges X.509-Zertifikat aus (SPIFFE-Identität pro Service-Account).
Beim Verbindungsaufbau prüfen sich beide Sidecars gegenseitig. Erst danach wird der Klartext-Request
an die jeweilige Anwendung weitergereicht. PeerAuthentication-Policies können mTLS
pro Namespace verpflichtend machen (STRICT-Modus).
AuthorizationPolicy: wer darf wen aufrufen?
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: payment-allow-frontend
namespace: prod
spec:
selector:
matchLabels:
app: payment
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/prod/sa/frontend"]
to:
- operation:
methods: ["POST"]
paths: ["/api/orders/*"]
Zugriffskontrolle auf Basis der mTLS-Identität
Die per SPIFFE-Zertifikat bewiesene Identität des Aufrufers (principal) ist die Grundlage für
Layer-7-Zugriffskontrolle. Der Inbound-Sidecar wertet AuthorizationPolicy-Regeln aus,
bevor der Request an die Anwendung weitergereicht wird, ohne dass die App selbst
Auth-Logik implementieren muss. Ohne passende ALLOW-Regel wird der Request mit 403
abgelehnt, sobald für den Namespace/Workload mindestens eine AuthorizationPolicy existiert.
6 External Service & Egress Gateway
Verlässt ein Aufruf das Mesh, z.B. ein Microservice, der Nachrichten an ein externes RabbitMQ außerhalb des Clusters sendet, kennt Istio das Ziel standardmäßig nicht. Es gibt zwei Muster, um das zu lösen:
A) Direkter Egress (ServiceEntry)
Ein ServiceEntry registriert den externen Host im Mesh-Katalog. Der ausgehende Sidecar
routet die Verbindung dann direkt an den externen Host. Einfach, aber jeder Pod mit Sidecar
braucht Netzwerkroute nach außen.
B) Egress Gateway (kontrolliert)
Der Sidecar routet den Traffic stattdessen zu einem dedizierten Egress Gateway (Envoy am Mesh-Rand). Nur dieses Gateway benötigt Netzwerkzugriff nach außen. Das macht es zur zentralen Stelle für TLS-Origination, Logging und Policy-Durchsetzung (z.B. Compliance-Vorgabe: "nur über Egress Gateway nach draußen").
Traffic-Fluss zu einem externen RabbitMQ über das Egress Gateway
# 1. Externen Host im Mesh bekannt machen
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: external-rabbitmq
spec:
hosts:
- rabbitmq.partner.example.com
ports:
- number: 5671
name: amqps
protocol: TLS
resolution: DNS
location: MESH_EXTERNAL
---
# 2. Egress-Gateway-Deployment als Ziel für externen Traffic
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: rabbitmq-egress-gw
spec:
selector:
istio: egressgateway
servers:
- port:
number: 5671
name: tls
protocol: TLS
tls:
mode: PASSTHROUGH
hosts:
- rabbitmq.partner.example.com
---
# 3. Mesh-internen Traffic explizit über das Egress Gateway leiten
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: rabbitmq-via-egress
spec:
hosts:
- rabbitmq.partner.example.com
gateways:
- mesh
- rabbitmq-egress-gw
tls:
- match:
- gateways: [mesh]
port: 5671
sniHosts: [rabbitmq.partner.example.com]
route:
- destination:
host: rabbitmq-egress-gw.istio-system.svc.cluster.local
port:
number: 5671
- match:
- gateways: [rabbitmq-egress-gw]
port: 5671
sniHosts: [rabbitmq.partner.example.com]
route:
- destination:
host: rabbitmq.partner.example.com
port:
number: 5671
7 Gesamtüberblick: kompletter Traffic-Pfad
Alle Bausteine zusammen: ein externer User ruft über das Ingress Gateway einen Microservice auf, der intern einen zweiten Microservice per mTLS anspricht, welcher wiederum über das Egress Gateway Nachrichten an ein externes RabbitMQ sendet.
Wer macht was? Kompakt-Übersicht
| Komponente | Typ | Zuständigkeit | Resource |
|---|---|---|---|
| Ingress Gateway | Envoy (dediziert, Mesh-Rand) | Empfang & TLS-Termination von externem Traffic | Gateway |
| VirtualService | Konfiguration | L7-Routing: Host, Pfad, Header, Gewichtung, Retries | VirtualService |
| DestinationRule | Konfiguration | Subsets, Load Balancing, mTLS-Modus, Circuit Breaking | DestinationRule |
| Service | Kubernetes-Objekt | Stabiler DNS-Name / ClusterIP, kein echter Hop | Service |
| Sidecar / HTTP Client | Envoy (injiziert je Pod) | Transparente Interception, mTLS, Policy-Enforcement | automatische Injection |
| AuthorizationPolicy | Konfiguration | L7-Zugriffskontrolle auf Basis der mTLS-Identität (principal) | AuthorizationPolicy |
| Egress Gateway | Envoy (dediziert, Mesh-Rand) | Kontrollierter, auditierbarer Austritt nach extern | Gateway (egress) |
| External Service | außerhalb des Mesh | z.B. externes RabbitMQ, Partner-API | ServiceEntry |