Cheatsheet im Volltext
Derselbe Inhalt wie im PDF, zum Mitlesen, Durchsuchen und direkten Kopieren der YAML-Snippets. Stand: Cilium v1.20.4 (Edition 2026.11).
Architektur & Identity
eBPF-Datapath
CNI mit eBPF-Datapath: Networking, Load-Balancing, Policy und Observability laufen als eBPF-Programme im Kernel, mit kube-proxy-Replacement ohne iptables-Ketten pro Service.
Komponenten: cilium-agent
(DaemonSet, je Node), cilium-operator (clusterweite
Aufgaben, z.B. IPAM), cilium-envoy (DaemonSet,
L7-Proxy), Hubble (Observability),
cilium-CLI. CNCF-graduated.
Identity statt IP
Jeder Endpoint bekommt eine clusterweite Security-Identity, abgeleitet aus den security-relevanten Pod-Labels. Endpoints mit identischem Label-Set teilen eine Identity.
Policy-Entscheidungen laufen gegen die Identity, nicht gegen flüchtige Pod-IPs. Das skaliert unabhängig von der Endpoint-Zahl.
cilium status --wait kubectl get ciliumendpoints -A # Identity je Pod kubectl get ciliumidentities
Install & kube-proxy-Replacement
Helm-Install
Ohne kube-proxy müssen
k8sServiceHost / k8sServicePort gesetzt
sein, sonst findet der Agent den API-Server nicht (den
Service löst sonst niemand auf). Chart per OCI,
cosign-signiert, Version ohne v pinnen (oder per
Digest).
helm install cilium \ oci://quay.io/cilium/charts/cilium \ --version 1.20.4 -n kube-system \ --set kubeProxyReplacement=true \ --set k8sServiceHost=<api-server-ip> \ --set k8sServicePort=6443
kube-proxy-Replacement
eBPF übernimmt ClusterIP, NodePort, LoadBalancer, externalIPs und HostPort.
Socket-LB: übersetzt Service auf Backend
schon beim connect()/sendmsg(), kein
Paket-Rewriting auf dem Pfad.
Mit Istio (Sidecar oder Ambient) immer
cni.exclusive=false, damit Istios CNI-Plugin erhalten
bleibt. Kube-proxy-frei zusätzlich
socketLB.hostNamespaceOnly=true, sonst greift
Socket-LB schon im Pod und stört die Umleitung zum
Istio-Proxy. Die Cilium-Doku empfiehlt mit Istio weiterhin
kubeProxyReplacement=false. Unter Istio-mTLS sieht
Cilium kein L7, L7-Policies nicht in beiden Systemen pflegen.
kubectl -n kube-system exec ds/cilium -- \ cilium-dbg status --verbose | \ grep KubeProxyReplacement
LoadBalancer ohne Cloud
IP-Pools per CiliumLoadBalancerIPPool
(cilium.io/v2), auch für den Gateway-Service.
Bekanntgabe per L2 (l2announcements.enabled=true,
Beta, braucht kube-proxy-Replacement und ein höheres
k8sClientRateLimit, plus
CiliumL2AnnouncementPolicy) oder BGP
(bgpControlPlane.enabled=true, v2-CRDs).
cilium-dbg bgp ist seit 1.20 deprecated, Ersatz im
Agent-Pod cilium-dbg shell -- bgp/*.
CiliumNetworkPolicy (L3/L4)
Selektoren, Entities, CIDR
endpointSelector wählt die Ziel-Endpoints;
fromEndpoints/toEndpoints selektieren
per Label (Identity).
toEntities: world,
cluster, cluster-mesh (seit 1.20, alle
verbundenen Cluster), host, remote-node,
kube-apiserver.
toCIDR/toCIDRSet: für
externe Ziele, Cluster-intern per Label
selektieren.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata: {name: backend-allow, namespace: shop}
spec:
endpointSelector:
matchLabels: {app: backend}
ingress:
- fromEndpoints:
- matchLabels: {app: frontend}
toPorts:
- ports:
- {port: "8080", protocol: TCP}
Clusterwide & Enforcement-Modi
CiliumClusterwideNetworkPolicy: gleiche
Syntax, nicht namespaced, für Baselines über alle
Namespaces. Baseline ohne Deny-Nebenwirkung:
enableDefaultDeny: {ingress: false, egress: false},
gilt nicht für L7-Regeln (L7 ohne Allow-all droppt
trotzdem).
policyEnforcementMode: default
(alles offen, bis eine Regel den Endpoint selektiert, dann
default-deny je Richtung), always,
never.
L7-Policies & toFQDNs
HTTP-Rules (L7)
L7-Regeln hängen unter toPorts.rules.http:
method, path, host als
POSIX-Regex. Header nie per Regex: headers prüft
Präsenz, als "Name: Wert" den exakten Wert;
headerMatches vergleicht exakt (Wert auch aus Secret,
mismatch steuert die Reaktion). Durchsetzung via
node-lokalem Envoy; Verstoß liefert
HTTP 403 statt Paket-Drop.
Weiterer L7-Typ: dns. Kafka- und proxylib-Regeln
(kafka, l7, l7proto) sind
seit 1.20 entfernt und müssen vor dem Upgrade aus den
Policies raus.
spec:
endpointSelector:
matchLabels: {app: api}
ingress:
- fromEndpoints:
- matchLabels: {app: frontend}
toPorts:
- ports:
- {port: "80", protocol: TCP}
rules:
http:
- method: GET
path: /v1/.*
toFQDNs (Egress nach Namen)
matchName exakt, matchPattern mit
Wildcard.
Pflicht-Voraussetzung: eine
rules.dns-Regel schaltet den DNS-Proxy ein,
ohne DNS-Sichtbarkeit kann Cilium FQDNs nicht auf IPs mappen und
die Policy läuft leer. Selektoren ohne Namespace-Label gelten
in einer CNP nur im eigenen Namespace, kube-dns also mit Namespace
selektieren.
egress:
- toEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports: [{port: "53", protocol: ANY}]
rules:
dns: [{matchPattern: "*"}]
- toFQDNs:
- matchName: api.example.com
- matchPattern: "*.storage.example.com"
toPorts:
- ports: [{port: "443", protocol: TCP}]
Hubble (Observability)
Flows, Relay, UI
Hubble liest Flows direkt aus dem eBPF-Datapath, ohne Sidecars oder Paket-Mirroring. L7-Flows (HTTP, DNS) gibt es nur für Traffic, den eine L7-Regel über den Proxy leitet, und diese Regel filtert dann auch.
Relay aggregiert clusterweit (auch über
ClusterMesh), UI zeigt die
Service-Dependency-Map, die CLI
(hubble) filtert Flows live.
Redaction: Hubble schwärzt L7-Daten
(Query-Parameter, Header) standardmäßig nicht.
hubble.redact.enabled=true plus
hubble.redact.http.urlQuery=true, Header per
hubble.redact.http.headers.allow oder
.deny (nur eine der beiden Listen).
cilium hubble enable --ui cilium hubble port-forward & hubble status hubble observe --namespace shop \ --verdict DROPPED hubble observe --protocol http --last 20
Metriken
Hubble-Metriken für Prometheus per Helm:
hubble.metrics.enabled="{dns,drop,tcp,flow,icmp,httpV2}".
Agent: prometheus.enabled=true (Default aus),
Operator: operator.prometheus.enabled (Default
an).
Encryption
WireGuard
Transparente Verschlüsselung des Pod-Traffics
zwischen Nodes (Device cilium_wg0,
UDP 51871, Firewall freischalten!).
Key-Paar erzeugt jeder Node selbst, Public-Key-Austausch via
CiliumNode-Annotation.
Node-zu-Node zusätzlich:
encryption.nodeEncryption=true. Nodes mit Label
node-role.kubernetes.io/control-plane nimmt Cilium
davon automatisch aus. Same-Node-Traffic bleibt
unverschlüsselt.
Strict Mode:
encryption.strictMode.egress.enabled=true plus
.egress.cidr (Pod-CIDR, nur IPv4) verhindert
unverschlüsselte Erstpakete.
encryption.strictMode.ingress.enabled=true (nur
WireGuard) droppt unverschlüsselten Pod-Traffic. Die alten
Schlüssel
encryption.strictMode.enabled/.cidr
sind seit 1.20 entfernt.
# Konfig-Änderung: --version = installierte Chart-Version helm upgrade cilium \ oci://quay.io/cilium/charts/cilium \ --version 1.20.4 -n kube-system \ --reuse-values \ --set encryption.enabled=true \ --set encryption.type=wireguard kubectl -n kube-system exec ds/cilium -- \ cilium-dbg status | grep Encryption
IPsec
encryption.type=ipsec; Key liegt im Secret
cilium-ipsec-keys (Cilium-Namespace), z.B.
"3+ rfc4106(gcm(aes)) <key> 128". Das
+ erzwingt Per-Tunnel-Keys, globale Keys gelten als
unsicher (GHSA-pwqm-x5x6-5586).
Key-Rotation ist manuell (KEYID 1–15 inkrementieren), nie während eines Upgrades rotieren.
ztunnel (Beta)
encryption.type=ztunnel: L4-mTLS je Node über
Istios ztunnel, Enrollment je Namespace (Label
io.cilium/mtls-enabled=true), CA
internal (Default) oder spire. Nicht mit
ClusterMesh kombinierbar. Nur TCP, beide Seiten müssen
eingeschrieben sein, braucht iptables; L4-Policies greifen nur noch
auf Port 15008 (HBONE). Empfohlene Alternative zur Mutual
Authentication (seit 1.20 deprecated, in v1.21.0-pre.3
entfernt).
ClusterMesh
Multi-Cluster-Verbund
Pod-Konnektivität über Cluster-Grenzen, globale
Services mit Cross-Cluster-Load-Balancing. Policies selektieren
seit 1.19 nur den lokalen Cluster, Remote-Endpoints explizit per
Label io.cilium.k8s.policy.cluster.
Voraussetzungen: PodCIDRs aller Cluster
disjunkt, eindeutiger cluster.name +
cluster.id (1–255, mit
clustermesh.maxConnectedClusters=511 bis 511, nur bei
der Installation setzbar, in allen Clustern gleich), gegenseitiges
TLS-Vertrauen (gemeinsame CA, z.B. cilium-ca
kopieren, oder tls.caBundle),
IP-Konnektivität zwischen allen Nodes,
clustermesh-apiserver gegenseitig erreichbar.
# CLI-Weg (Lab, Demo) cilium clustermesh enable --context c1 cilium clustermesh connect --context c1 \ --destination-context c2 cilium clustermesh status --wait
Helm-Setup & Zertifikate
Setup laut Doku Helm-first:
clustermesh.useAPIServer=true,
clustermesh.config.enabled=true, Remote-Cluster unter
clustermesh.config.clusters. Die CLI ist ein
Helm-Wrapper für schnelle Setups (Lab, Demo).
Zertifikate: seit 1.20 gelten auto-generierte
Cluster-Mesh-Zertifikate ein Jahr. Methode helm
(Default) erneuert nur beim Re-Render, also beim Upgrade.
Produktiv cronJob (erneuert alle 4 Monate) oder
certmanager, oder
clustermesh.apiserver.tls.auto.certValidityDuration
setzen.
Globale Services
Annotation service.cilium.io/global: "true" auf
dem gleichnamigen Service in beiden Clustern, Cilium
load-balanct auf die Backends beider Cluster.
service.cilium.io/shared: "false":
Remote-Backends nutzen, eigene nicht teilen.
Alternative zu globalen Services: MCS-API
(clustermesh.mcsapi.enabled=true, seit 1.20 stabil,
CRDs v1beta1, braucht CoreDNS ab 1.12.2 für
clusterset.local).
Gateway API
Eingebauter Controller
Cilium implementiert die Gateway API. CRDs
vorab installieren, mindestens v1.6.1, die Doku zu 1.20.4
installiert v1.6.3. Cilium führt Gateway API v1.7.0
(29.10.2026) noch nicht. Pflicht:
GatewayClass, Gateway, HTTPRoute, GRPCRoute, BackendTLSPolicy,
ReferenceGrant, TLSRoute. Optional ListenerSet und
TCPRoute/UDPRoute (seit Gateway API 1.6 GA,
v1; Traffic läuft am Envoy vorbei direkt auf den
Gateway-Service; im Host-Network-Modus nicht nutzbar). Fehlt eine
optionale CRD, ist das Feature aus.
Gateway-Service per Default vom Typ
LoadBalancer.
Voraussetzungen:
kubeProxyReplacement=true, l7Proxy=true
(Default), gatewayAPI.enabled=true. Ohne
bpf.tproxy=true (beta) läuft der Redirect zu
Envoy über iptables-TPROXY: fehlen die Netfilter-Module,
laufen Verbindungen in Timeouts. GatewayClass heißt
cilium.
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata: {name: web-gw, namespace: shop}
spec:
gatewayClassName: cilium
listeners:
- {name: http, port: 80, protocol: HTTP}
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata: {name: web, namespace: shop}
spec:
parentRefs: [{name: web-gw}]
rules:
- matches:
- path: {type: PathPrefix, value: /}
backendRefs: [{name: web, port: 80}]
Diagnose (cilium-CLI)
Werkzeuge
cilium status --wait: Health aller Komponenten.
cilium connectivity test: E2E-Testsuite im Cluster.
cilium sysdump: Support-Archiv für
Bug-Reports.
Im Agent-Pod: cilium-dbg
(endpoint list, policy get,
monitor).
cilium connectivity test cilium sysdump --output-filename dump kubectl -n kube-system exec ds/cilium -- \ cilium-dbg endpoint list kubectl -n kube-system exec ds/cilium -- \ cilium-dbg monitor --type drop
Neu in v1.20
Highlights (29.07.2026)
ClusterNetworkPolicy (network-policy-api,
v1alpha2): opt-in per
k8sClusterNetworkPolicy.enabled=true, CRD separat
installieren. Tier Admin schlägt auch CNP/CCNP,
Baseline greift erst nach ihnen. Volle
API-Konformität verlangt
--policy-cidr-match-mode=pods,nodes (Helm
policyCIDRMatchMode={pods,nodes}, Beta), weil die API
CIDR-Regeln auch auf Pod- und Node-IPs anwendet;
pods kostet je getroffenem Pod eine zusätzliche
Identity.
Gateway API v1.6.1: TCPRoute/UDPRoute GA, delegierte Listener (ListenerSets), ExternalAuth-Filter, Backend-TLS.
netkit automatisch (Beta):
bpf.datapathMode=auto nimmt netkit, wenn der Kernel
es kann (ab 6.8, eBPF-Host-Routing nötig), sonst veth;
Default bleibt veth. Kein In-place-Wechsel: erkennt
auto netkit auf einem Node mit bestehenden
veth-Pods, startet Cilium mit Fehler. Mit
bpf.tproxy=true fällt auto immer
auf veth zurück, explizites netkit plus tproxy startet
nicht.
Traffic Distribution:
PreferSameZone / PreferSameNode werden
ausgewertet; Maglev beachtet
service.cilium.io/weight auf EndpointSlices
(Gewicht 0 = draining, Bestandsverbindungen laufen weiter).
MCS-API stabil für portable Service-Discovery über ClusterMesh.
Getestet gegen Kubernetes 1.33 bis 1.36 (ältere ohne
Support, 1.37 erst im Entwicklungszweig für 1.21 gelistet),
Envoy je nach Patch 1.37 bis 1.39. Das
cilium-cni-Binary schrumpft von rund 77 auf
16 MB.
Upgrade-Reihenfolge
Nur eine Minor-Stufe je Upgrade oder Rollback, vorher auf den
letzten Patch der laufenden Linie;
upgradeCompatibility auf die Version der
Erstinstallation setzen.
Gateway-API-CRDs vor dem Cilium-Upgrade auf
mindestens v1.6.1 heben und TLSRoute-Ressourcen
vorher sichern. Kafka-/l7-/l7proto-Regeln
vorher aus den Policies entfernen, CiliumNodeConfig
auf cilium.io/v2 umstellen. Ziel mindestens
1.20.4: 1.20.0 und 1.20.1 scheitern auf
Clustern, die mit 1.15 oder älter angelegt wurden, und ein
HTTPRoute-ExternalAuth mit ungültiger
Backend-Referenz schlägt erst ab 1.20.2 geschlossen
fehl. 1.20.3 hat bei BackendTLSPolicy eine
Regression (hohe CPU-Last, kein Forwarding), behoben in
1.20.4.
Mit kube-proxy-Replacement ohne Socket-LB oder mit
socketLB.hostNamespaceOnly=true balanciert 1.20
Pod-Verbindungen auf NodePort-Services schon beim Verlassen des
Client-Pods. Die Egress-Policy des Clients muss die Backends
erlauben, die Ingress-Policy der Backends den Client.
Support-Fenster: drei Minor-Linien parallel (1.20.4, 1.19.10, 1.18.16 vom 23.10.2026). Die aktuelle Linie bekommt alle Bugfixes, die beiden Vorgänger nur Security- und schwere Korrektheits-Fixes. Die Releases vom 23.10. bauen mit Go 1.26.10 und verwerfen damit in den Go-Komponenten die eMudhra-Intermediates (CVE-2026-111943); zu cilium-envoy sagen die Release Notes nichts.
Anti-Patterns
Was du nicht tun solltest
toFQDNs ohne DNS-Rule: ohne
rules.dns-Sichtbarkeit kein FQDN-zu-IP-Mapping,
Policy blockt oder läuft leer.
kube-proxy-frei ohne k8sServiceHost/Port: Agent erreicht den API-Server nicht, Cluster-Bootstrap hängt.
CIDR-Regeln für Cluster-Traffic:
toCIDR ist für externe Ziele gedacht; Pod-IPs
sind flüchtig, Labels/Identities selektieren.
Default-Modus falsch verstanden: ohne
selektierende Regel ist alles offen; die erste Regel schaltet den
Endpoint auf default-deny (je Richtung), sofern sie nicht
enableDefaultDeny abschaltet.
WireGuard ohne UDP 51871: Nodes müssen sich auf dem Port erreichen, sonst kein Tunnel.
--reuse-values beim Minor-Upgrade:
neue Chart-Werte fehlen, das Template rendert falsch. Werte per
helm get values sichern, auf umbenannte Keys
prüfen, mit -f übergeben.
IPsec-Keys während des Upgrades rotieren: erst alle Nodes auf gleiche Cilium-Version, dann rotieren.
ClusterMesh mit überlappenden PodCIDRs
oder doppelter cluster.id: Verbund kommt nicht
sauber hoch, vorab planen.
kube-proxy-Replacement im laufenden Cluster
umschalten: bestehende Verbindungen brechen ab. Wer
kube-proxy unter kubeadm entfernt, löscht auch die ConfigMap
kube-proxy, sonst kommt kube-proxy beim nächsten
Upgrade zurück.