The Problem with Customizing a Proxy
Every organization eventually needs custom logic in their proxy layer: "Add a correlation ID header if one is missing," "Block requests from certain IP ranges," "Emit a custom metric for this specific endpoint." The question is how to do this safely.
The Old Ways and Their Problems
Historically, Envoy offered two extension mechanisms, both with serious drawbacks:
Lua Scripts: You could embed Lua code directly in the Envoy config. Flexible, but Lua runs in a single-threaded interpreter, is slow for CPU-intensive work, and produces cryptic errors that are hard to debug in production.
Native C++ Filters: Fast and powerful, but required forking the Envoy codebase, writing C++, recompiling the entire binary, and redeploying it across your fleet. A memory bug in your custom filter could crash the entire proxy — taking down every service on that node simultaneously.
The New Way: WebAssembly (WASM)
Envoy now supports a WASM sandbox. You write a filter in Rust, Go, or C++, compile it to a .wasm binary, and push it to Envoy at runtime via the control plane. No recompilation of Envoy. No restart.
The key properties of the WASM sandbox:
Safety: WASM code runs in a memory-isolated sandbox with a fixed memory limit. If your WASM filter panics or hits an infinite loop, it does not crash Envoy. The filter fails gracefully — either fail-open (pass the request through) or fail-close (return an error), depending on your configuration.
Dynamism: You can update the WASM filter binary and its configuration via Istio's WasmPlugin CRD without restarting any Pods. The control plane pushes the new .wasm file to sidecars, which hot-reload it.
Portability: The same .wasm binary runs on any Envoy build, regardless of OS or CPU architecture, because WASM is a virtual instruction set.
A Minimal WASM Plugin in Istio
Istio's WasmPlugin custom resource ties this together: it selects which Pods get the filter (by label), names the OCI registry URL the .wasm binary should be pulled from, specifies which phase of the filter chain to insert it at (e.g. after authentication), and passes plugin-specific configuration like a header name. The .wasm binary is pulled from an OCI registry — the same infrastructure you use for container images.
A common interview question is: "What happens if a WASM filter crashes in production?" The answer demonstrates understanding of the sandbox model. A crashing WASM filter does not crash Envoy — the sandbox is isolated. Envoy detects the failure and applies the failOpen or failClose policy you configured. This is fundamentally safer than native C++ filters, where a segfault kills the entire proxy process. Follow-up: "How do you update a WASM filter without downtime?" — via the WasmPlugin CRD; istiod pushes the new binary to sidecars via xDS, which hot-reload it with no Pod restart.