Cilium vs Istio: eBPF Service Mesh Compared (2026)

If you are weighing a service mesh in 2026, the Cilium versus Istio question is really a question about where you want your dataplane to live: in a userspace proxy next to every workload, or down in the Linux kernel. That single choice ripples through latency, resource cost, operational complexity, and how much L7 control you actually get. This post walks the tradeoffs from a running-it-in-production angle. Treat every capability claim here as a starting point and verify against current releases before you commit, because both projects move fast.

For the broader landscape, see our service mesh guide. If your shortlist also includes Linkerd, the Istio vs Linkerd comparison is a useful companion.

The core architectural split #

Istio's classic model puts an Envoy proxy in every pod as a sidecar. All traffic in and out of the workload is intercepted and routed through that proxy, which gives Istio a very rich L7 story: fine-grained routing, retries, fault injection, header manipulation, and per-request telemetry. The cost is one proxy process per pod, plus the iptables or init-container plumbing to redirect traffic into it.

Istio's ambient mode changes that shape. Instead of a sidecar per pod, ambient uses a per-node component (ztunnel) for L4 processing and mTLS, and introduces optional waypoint proxies only for workloads that need L7 features. So you pay for L7 Envoy only where you actually use it. Ambient has matured a lot, and for many teams it is now the default way to run Istio rather than an experiment.

Cilium comes at this from the opposite direction. It started life as a CNI plugin and network-policy engine built on eBPF, and grew mesh features on top. There is no per-pod sidecar. The dataplane is eBPF programs attached in the kernel, doing L3/L4 forwarding and policy enforcement at the socket and network layers. When you need L7 (HTTP routing, gRPC, Kafka-aware policy), Cilium hands the relevant traffic to a per-node Envoy that it manages for you. So both projects have converged on a per-node-proxy idea for L7, but Cilium never had a sidecar to shed.

What eBPF actually changes #

Running the dataplane in the kernel removes hops. There is no userspace proxy in the fast path for L3/L4 traffic, so you avoid the extra context switches and memory copies a sidecar imposes. In practice that tends to mean lower and more predictable latency and lower per-pod overhead, especially at high connection counts. Enforcement happens at the node level, close to the socket, rather than in a proxy each packet has to detour through.

The catch: eBPF is brilliant for L3/L4, but HTTP-level logic still needs a real proxy. Cilium's answer is that per-node Envoy, so once you turn on L7 features you are back to proxying that traffic, just once per node instead of once per pod.

mTLS approaches #

Istio's mTLS is well-trodden. Identities are issued via SPIFFE, certificates are distributed to the sidecars (or ztunnel in ambient), and mutual TLS between workloads is essentially a policy toggle. It is one of the most battle-tested parts of the project.

Cilium offers mutual authentication and transparent encryption, historically via IPsec or WireGuard at the node level, plus a mutual-auth mechanism that also builds on SPIFFE identities. The model is different from per-connection sidecar mTLS, so if regulatory or zero-trust requirements hinge on the exact encryption boundary, read the current Cilium docs carefully rather than assuming parity.

Network policy vs mesh policy #

This is where Cilium's origin story matters. Because it began as a CNI, CiliumNetworkPolicy is a first-class, mature feature, and it can express both classic L3/L4 rules and L7-aware rules in one object:

yaml.yaml

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-api-get
spec:
endpointSelector:
matchLabels:
app: backend
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: "GET"
path: "/api/.*"

That single policy allows the frontend to reach the backend, but only for GET requests under /api/. If your primary goal is strong, identity-aware segmentation, Cilium gives you that without adopting a full mesh. Istio expresses similar intent through AuthorizationPolicy, which is powerful but lives in the mesh layer rather than the CNI. For a deeper look at the policy side alone, see Kubernetes network policies.

Observability #

Cilium ships Hubble, which taps the same eBPF layer to give you flow-level visibility without instrumenting apps. You can watch traffic live:

bash.bash

hubble observe --namespace payments --protocol http --verdict DROPPED

That surfaces dropped flows, DNS lookups, and L7 requests with identities attached, which is genuinely useful for debugging policy. Istio leans on Envoy's telemetry feeding Prometheus, Grafana, and distributed tracing through Jaeger or Tempo. Istio's request-level metrics and tracing are richer for application-behavior questions; Hubble is stronger for network-level truth about what actually flowed.

Performance and resource overhead #

The sidecar-less design is Cilium's headline efficiency argument: no per-pod proxy means less memory and CPU multiplied across thousands of pods, and fewer moving parts per workload. Istio ambient narrows this gap considerably by removing sidecars too, but its L4 path still runs through ztunnel in userspace rather than the kernel. Benchmark with your own workloads. Synthetic numbers rarely survive contact with real traffic patterns, and the delta depends heavily on connection churn and payload sizes.

Maturity for L7 mesh features #

Istio remains the deeper L7 toolkit. Traffic mirroring, sophisticated canary and weighted routing, request-level fault injection, and a large ecosystem of extensions are all mature. Cilium's L7 capabilities are real and improving, but if your architecture depends on intricate request routing and virtual-service composition, Istio is still the more complete answer today.

How to choose #

You already run Cilium as your CNI: Adding its mesh and mТLS features is a small step and avoids a second system. This is the most compelling case for Cilium.

You need strong, identity-aware segmentation more than L7 traffic shaping: Cilium's policy engine plus Hubble covers it with less overhead.

You need advanced L7 routing, canary deployments, and a broad extension ecosystem: Istio, most likely in ambient mode, is the safer bet.

You are latency and density sensitive at scale: The kernel dataplane is worth benchmarking seriously.

Multi-cluster: Both support it. Cilium Cluster Mesh connects clusters at the eBPF/pod-networking layer with cross-cluster identity and service discovery, which feels natural if Cilium is already your CNI. Istio's multi-cluster (shared or multi-primary control planes) is mature and gives you consistent L7 policy across clusters. Pick based on whether your cross-cluster needs are mostly connectivity and policy (Cilium) or mostly L7 traffic management (Istio).

The call we'd make #

If Cilium is already your CNI, start with its mesh features before adding anything else. You likely get the segmentation, encryption, and observability you need with the least operational weight, and Hubble alone often justifies the move. Reach for Istio when your requirements are genuinely L7-heavy: complex routing, progressive delivery, and a mature extension surface. And if you are greenfield, seriously evaluate Cilium as CNI plus mesh first, then layer Istio ambient only if the L7 gap actually bites. Whichever way you lean, prototype both against your own traffic and re-check the current release notes, because the feature line between these two keeps moving.