Skip to content

Three Enforcement Layers: Cilium, Istio, and Tetragon

If one layer fails and everything is allowed, you don’t have defense in depth — you have a single point of failure with a reassuring name.

Most Kubernetes clusters have one security enforcement layer. Cilium, maybe. Or Istio. One tool, one mechanism, one thing between you and “everything talks to everything.”

When that tool has a bad day — agent crash, botched upgrade, silent misconfiguration — enforcement vanishes. Traffic that should be denied flows freely. Nobody notices until the alert fires, or doesn’t.

That’s not a security model. That’s a hope.

And even when the tool is healthy, it’s blind to entire threat classes. L4 can’t tell a GET /api/orders from a DELETE /admin. L7 authorization can’t evaluate non-HTTP traffic or traffic that bypasses the waypoint proxy. Neither can stop a compromised container from downloading and executing a binary at runtime.

“Three layers sounds like overengineering.”

Fair. It sounds that way until the Cilium agent crashes at 3 AM and L7 is the only thing standing between a compromised pod and your database. Then it sounds like the bare minimum.

Each layer operates at a different point in the stack, sees different things, and fails independently. That independence is the whole point.

flowchart TD
  A[Service Spec] --> B{Compiler}
  B --> C["L4: CiliumNetworkPolicy\n(eBPF, kernel)"]
  B --> D["L7: Istio AuthorizationPolicy\n(waypoint proxy, userspace)"]
  B --> E["Runtime: Tetragon TracingPolicy\n(eBPF/LSM, kernel)"]
  C --> F[Packet filtering]
  D --> G[Request authorization]
  E --> H[Binary execution control]

Layer 1: Cilium at L4. Default-deny CiliumClusterwideNetworkPolicy blocks all traffic. Per-service CiliumNetworkPolicies open specific paths based on dependency declarations. Enforcement is in eBPF — kernel-level, low-latency, not bypassable from a container. This is the backstop that keeps working when everything else is having a bad day.

Layer 2: Istio ambient mesh at L7. Default-deny AuthorizationPolicy blocks all requests. Per-service policies allow specific SPIFFE identities for specific HTTP methods and paths. Ztunnel handles L4 mTLS on every node. Waypoint proxies handle L7 evaluation for namespaces that need it. No sidecar injection — the compilation pipeline produces clean pod specs.

Layer 3: Tetragon at the kernel. Tetragon uses eBPF to intercept execve syscalls. A TracingPolicy specifies which binaries are allowed to execute in a container. A compromised container that passes both network layers — it has L4 egress and L7 authorization — can still download and run an unauthorized binary. Tetragon blocks the execution before the binary starts. It catches what network policy, by definition, cannot see.

If your L7 rules are derived from your L4 rules, a bug in the derivation compromises both layers simultaneously. That’s not two layers — it’s one layer with two names.

Lattice compiles all three from the same service spec, but through independent derivation paths. A bug in the Istio policy compiler doesn’t affect the Cilium policy compiler. They share a source, not a mechanism.

FailureL4 (Cilium)L7 (Istio)Kernel (Tetragon)
Cilium agent crashLostEnforcesEnforces
Waypoint proxy downEnforcesLostEnforces
Tetragon DaemonSet evictedEnforcesEnforcesLost
All healthyFullFullFull

No single failure removes all enforcement. That’s the whole point — not that each layer is perfect, but that they fail independently.

Maintaining three independent policy sets by hand would be operationally brutal. Nobody is going to write 600 YAML files to rename a service across three enforcement systems. That’s the kind of idea that sounds good in a threat model review and dies in the first sprint.

Lattice doesn’t ask you to. You declare type: service, direction: outbound. The compiler produces a CiliumNetworkPolicy, an Istio AuthorizationPolicy, and a Tetragon TracingPolicy. Three layers, one declaration, zero manual policy authoring. They share a source (the service spec) but not a derivation path — the Cilium compiler, the Istio compiler, and the Tetragon compiler are independent code that produces independent resources. A bug in one doesn’t corrupt the others. Defense-in-depth that survives contact with a real team’s backlog — because if it doesn’t survive the backlog, it doesn’t survive.

  • One enforcement layer is one failure from full exposure. If your only security mechanism crashes, all traffic flows freely. That’s not defense-in-depth — it’s a single point of failure with better marketing.
  • L4, L7, and runtime enforcement see different things. Packets, requests, and binary execution are three distinct threat classes. No single tool covers all three.
  • Compilation makes three layers practical. Without automation, maintaining 3 policy sets per service is a fantasy. The platform generates all three from a single dependency declaration.