The operator writes each renewed service account token into WasmPlugin.spec.pluginConfig.cache_token (coraza-kubernetes-operator/internal/controller/engine_controller_wasm_driver.go). Envoy includes the plugin configuration in the plugin key (envoy/source/extensions/common/wasm/plugin.cc), so a new token creates a new plugin root. Istio 1.30.3 strips its changing resource-version VM variable before forwarding the configuration, and Envoy keys the VM by its VM configuration and WASM bytes. With unchanged code and VM settings, successive roots share one worker VM.
The Coraza guest fixes are already deployed. The remaining fixes must release root-owned state without destroying state still used by another root on that VM. This plan is based on source inspection only; no process was run or measured.
Owner: envoy/source/extensions/common/wasm/wasm.{h,cc} and context.cc.
- Add a root cleanup method on Envoy's
Wasmthat disables and erasestimer_[root_id]and erases the inheritedtimer_period_[root_id]. Call it when an EnvoyContextrepresenting a root is destroyed, after the guest'son_done/on_deletelifecycle. Do not clean up a stream context or the VM context. - Make
setTimerPeriod(root_id, 0)erase both entries as well. It currently leaves map entries behind even when the guest disables its timer. - Guard
tickHandleragainst a deleted root so a late callback cannot reschedule it. This is a backstop for shutdown ordering; the primary release happens at root destruction.
Why here: WasmBase::startShutdown(plugin_key) in the pinned proxy-wasm-cpp-host removes the root, but Envoy owns the dispatcher timer. The current callback reschedules even if getContext(root_id) is null. The operator's ruleset poll interval defaults to 15 seconds, so this path is normally active.
Owner: envoy/source/extensions/common/wasm/context.cc and wasm.{h,cc}.
- When
Context::defineMetricallocates an ID, record that ID under the defining context's root ID. On that root's destruction, erase its IDs fromWasm::counters_,gauges_, andhistograms_, then erase the root's ID list. - Keep Envoy's underlying named stats intact: a later root may use the same counter name, and clearing an ID-to-stat pointer is different from deleting a shared stat. This bounds bookkeeping created by token refreshes while preserving metric values.
- Cover metrics defined from a child context by resolving its root ID, rather than assuming all definitions happen directly on the root.
Why here: coraza-proxy-wasm/wasmplugin/metrics.go creates a new per-root metric registry. Envoy currently assigns new IDs for the same metric names on each root and retains their VM-level lookup entries.
Owner: proxy-wasm-cpp-host/include/proxy-wasm/wasm.h and src/wasm.cc; then update Envoy's pinned host dependency in envoy/MODULE.bazel and its dependency metadata.
- Bound
WasmHandleBase::plugin_canary_cache_or evict a key when its final plugin handle is released. Prefer the smallest change that preserves canary validation for active configurations. Cache misses may revalidate a configuration; stale token-derived keys must not remain forever. - Land the host fix upstream or in a pinned fork. Changing a local copy of host source has no effect until Envoy consumes the new pinned revision.
Why here: the base WASM handle survives while worker clones use it, and canary() adds one result for every distinct token-derived plugin key without eviction. This is a smaller retention path than timers or guest WAF state, but it is unbounded.