Tekko

Language

Get in Touch

Usually respond within 24 hours

Back to BlogDevOps

Cilium eBPF: Building a Sidecar-less Service Mesh with mTLS

8 min read
KubernetesCiliumeBPFService MeshSecurity
Cilium eBPF: Building a Sidecar-less Service Mesh with mTLS

For years, the standard approach to implementing a service mesh in Kubernetes has been synonymous with the sidecar pattern. Whether you were using Istio or Linkerd, the recipe was the same: inject an Envoy proxy into every pod, intercept all incoming and outgoing traffic, and let the proxy handle mutual TLS (mTLS), retries, and observability.

While this pattern revolutionized microservices management, it introduced a non-trivial 'sidecar tax.' Every sidecar consumes CPU and memory, adds latency through multiple context switches, and complicates the pod lifecycle. As clusters scale, these overheads shift from being a minor nuisance to a significant operational burden.

Cilium, powered by eBPF (Extended Berkeley Packet Filter), offers a compelling alternative: a sidecar-less service mesh. By moving the service mesh logic into the Linux kernel, Cilium provides the same security and observability benefits without the proxy overhead. In this article, we will explore how to implement mutual authentication and deep observability using Cilium and Hubble.

The Problem with the Sidecar Pattern

To understand why sidecar-less is gaining traction, we must first look at the architectural bottlenecks of traditional meshes. In a sidecar-based mesh, a packet leaving a container doesn't go straight to the network. Instead, it travels through the loopback interface to the sidecar proxy. The proxy processes the packet (L7 inspection, encryption, etc.) and then sends it out. On the receiving end, the process repeats in reverse.

This architecture results in:

  1. Increased Latency: Each packet traverses the TCP/IP stack multiple times within the same node.
  2. Resource Waste: In a cluster with 500 microservices, you are running 500 extra proxy instances. Even if each proxy only uses 50MB of RAM, that’s 25GB of memory dedicated solely to the infrastructure.
  3. Operational Complexity: Sidecars must be injected, updated, and managed. If a sidecar fails to start, the application pod fails, leading to 'circular dependency' issues during cluster upgrades.

How eBPF Changes the Game

eBPF allows us to run sandboxed programs in the Linux kernel without changing kernel source code or loading kernel modules. In the context of networking, eBPF can intercept packets at the lowest levels of the network stack—often directly at the NIC (Network Interface Card) or the socket layer.

Cilium leverages eBPF to handle networking, security, and load balancing. Because eBPF programs have a global view of the node, they can manage traffic for all pods on that node simultaneously. Instead of 50 proxies for 50 pods, you have one eBPF-powered data plane integrated directly into the kernel. This is the foundation of the sidecar-less service mesh.

Implementing Mutual Authentication (mTLS) without Sidecars

One of the primary reasons teams adopt a service mesh is for mTLS. Traditionally, this required a proxy to handle the handshake and encryption. Cilium takes a more modular approach by decoupling Authentication from Encryption.

Identity-Based Security

Cilium does not rely on IP addresses, which are ephemeral in Kubernetes. Instead, it assigns a unique security identity to each pod based on its labels. When a pod communicates with another, Cilium verifies the identity at the kernel level.

The mTLS Implementation

In Cilium 1.14 and later, mutual authentication is implemented by combining Cilium’s identity-based access control with a dedicated authentication handshake. When a connection is initiated:

  1. Cilium checks if a valid authentication 'ticket' exists between the source and destination identities.
  2. If not, the kernel triggers a brief handshake via a node-local agent to verify certificates.
  3. Once authenticated, the data path remains in the kernel.

For the encryption layer, Cilium uses WireGuard or IPsec. WireGuard, in particular, is highly performant and runs entirely in the kernel. This provides a 'transparent encryption' layer that is faster than the user-space encryption performed by Envoy sidecars.

To enable transparent encryption with WireGuard, the configuration is as simple as a Helm flag:

helm upgrade cilium cilium/cilium --version 1.15.x \ --namespace kube-system \ --set encryption.enabled=true \ --set encryption.type=wireguard

Deep Observability with Hubble

Observability is the other half of the service mesh promise. Usually, this requires a proxy to scrape L7 metrics (like HTTP status codes or gRPC methods). Hubble is Cilium’s observability layer, and it extracts this data directly from eBPF probes.

Because Hubble sits in the kernel, it sees everything. It doesn't just see the traffic the proxy intercepts; it sees dropped packets, DNS queries, and TCP retransmissions that a sidecar might miss.

Real-world Example: Hubble Flow Logs

If you want to debug why a service is failing, you can use the Hubble CLI to see real-time flows without instrumenting your code or adding proxies:

hubble observe --pod my-app-pod --protocol http

This provides a stream of data including:

  • Source and Destination identities
  • HTTP methods and paths
  • Verdict (Forwarded or Dropped)
  • Reason for drops (e.g., Policy Denied)

Hubble also provides a graphical UI that maps out your entire service dependency graph automatically. This is invaluable for technical decision-makers who need to visualize the blast radius of a potential security incident.

The Role of the Node-Local Proxy

It is important to be technically precise: 'sidecar-less' does not always mean 'proxy-less.' For complex L7 traffic management—such as retries, rate limiting, or header-based routing—Cilium uses an Envoy proxy. However, unlike Istio, this proxy is node-local.

Instead of one proxy per pod, there is one Envoy instance per node. eBPF redirects only the specific traffic that requires L7 processing to this node-local proxy. All other traffic (L3/L4, encryption, identity verification) stays in the kernel's fast path. This drastically reduces the total number of proxy instances and context switches across the cluster.

Performance Comparison: Sidecar vs. eBPF

In high-throughput environments, the performance gains are measurable. In standard benchmarks, Cilium's eBPF data path consistently shows lower tail latency (P99) compared to sidecar-based meshes.

In a sidecar mesh, a packet undergoes multiple traversals of the Linux networking stack (Socket -> TCP -> IP -> Virtual Eth -> Bridge -> Repeat). With Cilium eBPF, the 'sockmap' optimization allows packets to be redirected from one socket to another within the kernel, effectively short-circuiting the entire stack. This can result in a 30-50% reduction in latency for local pod-to-pod communication.

Practical Steps to Migration

If you are currently running a sidecar-based mesh and want to move toward a sidecar-less architecture, follow this phased approach:

1. Install Cilium as the CNI

Replace your existing CNI (like Flannel or standard Calico) with Cilium. You can run Cilium in 'chaining mode' if you cannot immediately replace your CNI, but native installation is preferred for performance.

2. Enable Hubble

Turn on Hubble to gain visibility into your current traffic patterns. This allows you to build a baseline of what 'normal' communication looks like before you start enforcing security policies.

3. Implement L4 Network Policies

Start using CiliumNetworkPolicy to enforce identity-based L4 security. This replaces standard Kubernetes NetworkPolicy with a more robust, label-aware system.

apiVersion: "cilium.io/v2" kind: CiliumNetworkPolicy metadata: name: "secure-backend" spec: endpointSelector: matchLabels: app: backend ingress: - fromEndpoints: - matchLabels: app: frontend toPorts: - ports: - port: "8080" protocol: TCP

4. Enable Transparent Encryption

Turn on WireGuard or IPsec. This provides the 'encryption' part of mTLS without requiring any changes to your applications or the addition of sidecars.

5. Transition L7 Logic

For services requiring retries or circuit breaking, define Cilium L7 policies. Cilium will automatically manage the node-local Envoy redirect for you.

When to Stick with Sidecars

Despite the advantages of eBPF, sidecars are not dead. There are specific use cases where a sidecar-based approach might still be preferable:

  • Heterogeneous Environments: If you need a single service mesh that spans across Kubernetes, bare metal, and legacy VMs where eBPF support might be inconsistent.
  • Extremely Complex L7 Requirements: If your organization relies on highly custom Envoy filters (Wasm or Lua) that are tightly coupled to the application lifecycle.
  • Specific Compliance Requirements: Some older compliance frameworks explicitly look for 'mutual TLS with sidecar proxies' and may require significant documentation to prove that kernel-level encryption is equivalent.

Conclusion

The shift toward sidecar-less service meshes represents a natural evolution in cloud-native infrastructure. By leveraging eBPF, Cilium moves the complexity of the service mesh out of the application pod and into the kernel, where it belongs. This results in a system that is faster, more resource-efficient, and easier to operate.

Actionable Takeaway: If you are struggling with the resource overhead of your current service mesh, start by deploying Cilium with Hubble in a dev environment. Use Hubble to visualize your traffic, and then experiment with transparent encryption. You'll likely find that you can achieve 90% of your service mesh goals with 10% of the operational headache.