- Authors

- Name
- Phillip Pham
- @ddppham
Egress Filtering in Kubernetes: Ausgehenden Traffic gezielt kontrollieren
TL;DR
- Default-Deny fuer Egress ist der wichtigste erste Schritt -- ohne ihn kann jeder Pod beliebige externe Ziele erreichen
- Native NetworkPolicies arbeiten auf Layer 3/4 (IP + Port), Cilium erweitert das um Layer 7 (DNS, HTTP Host)
- Ein Egress Gateway zentralisiert ausgehenden Traffic und ermoeglicht TLS-Inspektion sowie Logging an einer Stelle
- Der Rollout sollte schrittweise erfolgen: erst Audit-Modus, dann Deny-All mit expliziten Allow-Regeln
- Fuer die meisten Cluster reicht Cilium mit DNS-basiertem Egress aus -- ein Service Mesh ist selten noetig
Warum Egress Filtering oft vernachlaessigt wird
Die meisten Kubernetes-Setups konzentrieren sich auf Ingress: Wer darf von aussen auf welchen Service zugreifen? Die Gegenrichtung -- welche externen Ziele ein Pod erreichen darf -- wird erstaunlich oft ignoriert. Das ist ein Problem.
Wenn ein Container kompromittiert wird, ist ausgehender Netzwerkzugriff der primaere Angriffsvektor. Malware kontaktiert Command-and-Control-Server. Daten werden exfiltriert. Cryptominer laden Payloads nach. Ohne Egress-Kontrolle steht dem nichts im Weg.
Dazu kommt die DSGVO: Artikel 32 verlangt technische Massnahmen zur Sicherheit der Verarbeitung. Egress Filtering ist eine der wirksamsten, weil sie verhindert, dass personenbezogene Daten ueberhaupt den Cluster verlassen koennen.
Die drei Ebenen von Egress-Kontrolle
Es gibt nicht die eine Loesung. Je nach Anforderung kommen unterschiedliche Mechanismen zum Einsatz, die sich auch kombinieren lassen.
| Ansatz | Layer | DNS-Filtering | TLS-Inspektion | Komplexitaet | Typischer Einsatz |
|---|---|---|---|---|---|
| Native NetworkPolicies | L3/L4 | Nein | Nein | Niedrig | Basis-Absicherung |
| Cilium NetworkPolicies | L3/L4 + L7 | Ja | Nein | Mittel | Standard-Setup |
| Egress Gateway (Envoy/Squid) | L7 | Ja | Moeglich | Hoch | Regulierte Umgebungen |
| Service Mesh (Istio) | L7 | Ja | Ja (mTLS) | Sehr hoch | Nur wenn bereits vorhanden |
Fuer die meisten Produktions-Cluster ist Cilium der beste Kompromiss. Es bietet DNS-basiertes Egress-Filtering ohne den Overhead eines Service Mesh.
Schritt 1: Default-Deny fuer Egress
Der wichtigste Schritt ist eine Default-Deny-Policy fuer den Namespace. Ohne sie erlaubt Kubernetes standardmaessig allen ausgehenden Traffic.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
Diese Policy blockiert saemtlichen ausgehenden Traffic fuer alle Pods im Namespace production. Das bricht natuerlich erstmal alles -- DNS-Aufloesung, Zugriff auf andere Services, externe APIs. Deshalb ist der naechste Schritt entscheidend.
Schritt 2: DNS und interne Kommunikation erlauben
Pods brauchen DNS-Zugriff und muessen mit Services im gleichen Cluster kommunizieren koennen. Diese Policy erlaubt beides:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-and-internal
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
# DNS (CoreDNS im kube-system Namespace)
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
# Kommunikation innerhalb des Clusters (Pod CIDR)
- to:
- ipBlock:
cidr: 10.0.0.0/8
Wichtig: Der Pod-CIDR muss an euer Cluster angepasst werden. Bei den meisten Installationen liegt er im 10.0.0.0/8-Bereich, aber prueft das mit kubectl cluster-info dump | grep -i cidr.
Schritt 3: Externe Ziele gezielt freigeben
Jetzt koennt ihr fuer einzelne Workloads spezifische externe Ziele erlauben. Hier ein Beispiel fuer einen Pod, der nur eine externe API auf Port 443 erreichen darf:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-payment-api-egress
namespace: production
spec:
podSelector:
matchLabels:
app: payment-service
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 203.0.113.0/24
ports:
- protocol: TCP
port: 443
Das Problem: Externe APIs aendern ihre IP-Adressen. Wenn der Payment-Provider seine Infrastruktur umzieht, bricht die Verbindung. Hier helfen DNS-basierte Policies.
Cilium: DNS-basiertes Egress Filtering
Cilium erweitert NetworkPolicies um FQDN-basierte Regeln. Statt IP-Adressen koennt ihr Hostnamen verwenden:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-payment-api-fqdn
namespace: production
spec:
endpointSelector:
matchLabels:
app: payment-service
egress:
- toFQDNs:
- matchName: "api.stripe.com"
- matchName: "api.paypal.com"
toPorts:
- ports:
- port: "443"
protocol: TCP
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
Cilium faengt DNS-Antworten ab und erstellt daraus dynamisch IP-basierte Regeln. Wenn api.stripe.com seine IP aendert, passt sich die Policy automatisch an. Wichtig dabei: DNS-Zugriff muss explizit erlaubt sein, sonst kann Cilium die Hostnamen nicht aufloesen.
Egress Gateway fuer zentrales Logging
Wenn ihr nicht nur kontrollieren, sondern auch auditieren wollt, welche externen Verbindungen aufgebaut werden, bietet sich ein Egress Gateway an. Der gesamte ausgehende Traffic wird durch einen zentralen Proxy geleitet.
Ein einfaches Setup mit Envoy als Egress Proxy:
# Envoy als Egress Gateway deployen
kubectl create namespace egress-gateway
# Envoy Konfiguration als ConfigMap
kubectl create configmap envoy-config \
--from-file=envoy.yaml=envoy-egress.yaml \
-n egress-gateway
# NetworkPolicy: Pods duerfen nur zum Egress Gateway
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: force-egress-through-gateway
namespace: production
spec:
podSelector:
matchLabels:
egress-policy: gateway-required
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: egress-gateway
podSelector:
matchLabels:
app: envoy-egress
ports:
- protocol: TCP
port: 8443
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
EOF
Der Vorteil: Am Gateway habt ihr einen einzelnen Punkt, an dem ihr TLS-Inspektion, Rate Limiting, detailliertes Logging und Content Filtering implementieren koennt. Der Nachteil: Es ist ein Single Point of Failure, den ihr redundant auslegen muesst.
Monitoring: Blockierte Verbindungen erkennen
Egress-Regeln ohne Monitoring sind nutzlos. Ihr muesst wissen, wenn Pods versuchen, unerlaubte Ziele zu erreichen. Cilium liefert dafuer Hubble:
# Hubble CLI installieren und blockierte Flows anzeigen
hubble observe --verdict DROPPED --type l3/l4 \
--namespace production \
--since 1h \
-o json | jq '.flow | {src: .source.labels, dst: .IP.destination, port: .l4.TCP.destination_port}'
Fuer Prometheus-basiertes Alerting definiert ihr eine Rule wie diese:
groups:
- name: egress-filtering
rules:
- alert: EgressPolicyViolation
expr: sum(rate(hubble_drop_total{reason="POLICY_DENIED", direction="EGRESS"}[5m])) by (namespace) > 0
for: 2m
labels:
severity: warning
annotations:
summary: "Egress Policy Violation in {{ $labels.namespace }}"
description: "Pods in Namespace {{ $labels.namespace }} versuchen, blockierte externe Ziele zu erreichen."
Haeufige Fehler beim Rollout
DNS vergessen. Die haeufigste Ursache fuer Probleme nach dem Aktivieren von Egress-Policies ist fehlender DNS-Zugriff. Ohne DNS koennen Pods keine Hostnamen aufloesen, und fast alles bricht.
Zu restriktiv starten. Schaltet nicht sofort Default-Deny in Produktion ein. Beginnt in einer Staging-Umgebung oder nutzt Ciliums Policy-Audit-Modus, um zu sehen, welche Verbindungen blockiert wuerden.
Cluster-interne Kommunikation blockieren. Pods muessen mit dem Kubernetes API Server, mit CoreDNS und mit Services in anderen Namespaces kommunizieren koennen. Vergesst nicht, diese Pfade freizugeben.
Keine Automation. Egress-Regeln gehoeren in die CI/CD-Pipeline. Wenn Entwickler neue externe Abhaengigkeiten einfuehren, muss die zugehoerige NetworkPolicy als Code mitgeliefert werden.
Vorgehensweise fuer den Rollout
Ein pragmatischer Plan fuer bestehende Cluster:
Woche 1-2: Bestandsaufnahme. Nutzt Hubble oder tcpdump, um zu erfassen, welche externen Ziele eure Pods aktuell erreichen. Erstellt eine Liste pro Namespace.
Woche 3-4: Policies schreiben. Formuliert Default-Deny und Allow-Regeln basierend auf der Bestandsaufnahme. Testet sie in Staging.
Woche 5-6: Audit-Modus. Aktiviert die Policies im Audit-Modus (Cilium: policyAuditMode=true). Ueberwacht die Logs auf unerwartete Drops.
Woche 7-8: Enforcement. Schaltet auf Enforcement um, Namespace fuer Namespace. Beginnt mit den am wenigsten kritischen Workloads.
Weitergehende Themen
Egress Filtering ist ein Baustein einer umfassenden Netzwerksicherheit. Verwandte Themen, die ihr euch ansehen solltet:
- Network Policies im Detail -- Fortgeschrittene Patterns und Debugging
- Kubernetes Netzwerksicherheit -- Gesamtbild der Netzwerkabsicherung
- Runtime Security -- Erkennung verdaechtiger Aktivitaeten auf Pod-Ebene
- Security Scanning Tools -- Schwachstellen in Images und Konfigurationen finden
- Identity Management -- Authentifizierung und Autorisierung im Cluster
Fazit
Egress Filtering gehoert zu den wirksamsten Sicherheitsmassnahmen in Kubernetes, wird aber zu selten eingesetzt. Mit nativen NetworkPolicies und einem Default-Deny-Ansatz laesst sich bereits ein Grossteil der Angriffflaeche reduzieren. Cilium erweitert das sinnvoll um DNS-basierte Regeln.
Der Aufwand fuer die Implementierung ist ueberschaubar, wenn man schrittweise vorgeht. Der Ertrag -- Schutz vor Datenexfiltration, geringere Blast Radius bei Kompromittierung, bessere Compliance-Nachweise -- ist erheblich.
Wenn ihr Unterstuetzung bei der Planung oder Umsetzung eurer Egress-Strategie braucht, sprecht uns an 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
Network Policies: Kubernetes-Traffic richtig absichern
Kubernetes erlaubt standardmäßig allen Pod-Traffic. Mit Network Policies sichern Sie Ingress und Egress gezielt ab. Praxis-Guide mit YAML-Beispielen.
Netzwerk-Mikrosegmentierung in Kubernetes umsetzen
Mikrosegmentierung in Kubernetes mit Default-Deny, Zonen-Architektur und Cilium ClusterWide NetworkPolicy praktisch umsetzen.
Kubernetes Mikrosegmentierung: NetworkPolicies und Cilium
Mikrosegmentierung in Kubernetes mit NetworkPolicies und Cilium umsetzen: Deny-all-Baseline, Layer-7-Policies und praktische YAML-Beispiele erklärt.
Zero Trust Networking für Kubernetes umsetzen
Zero Trust in Kubernetes mit mTLS via Service Mesh, Network Policies und SPIFFE-Identitäten umsetzen. Praxisanleitung mit YAML.
Zero-Trust Architektur für Kubernetes Cluster
Zero-Trust in Kubernetes umsetzen mit Network Policies, mTLS und Identity Verification. Schritt-für-Schritt Anleitung für sichere Cluster-Kommunikation.