Architecture
Control plane, data plane, ECDS, and high availability
kubeWAF is a Kubernetes operator that turns structured security CRDs into live
WAF configuration on Envoy-based data planes. Evaluation runs in
modsecurity-proxy-wasm; you can optionally put pow-proxy-wasm (PoW challenge)
in front via spec.challenge.
Configuration is pushed over Envoy’s Extension Config Discovery Service (ECDS); each gateway product only receives a thin filter slot.
Big picture
Control plane vs data plane
| Plane | Responsibility |
|---|---|
| Kubernetes API | Desired state: rules, sets, attachment (WAF) |
| kubeWAF operator | Resolve rules → SecLang → portable config; multi-module wasm serve; ECDS; provider slots |
| Gateway control plane | Routing, TLS, listeners (Envoy Gateway / Istio / Cilium) |
| Envoy + Wasm engines | Challenge (optional) then modsecurity-proxy-wasm evaluates traffic |
kubeWAF does not replace the gateway’s ADS (LDS/RDS/CDS). It only owns extension config (ECDS) and installs a small filter that points at that ECDS resource.
Operator internals
Why this split?
Envoy (and Envoy Gateway) load-balance against the operator Service. If only the leader held ECDS config, non-leader pods would return empty snapshots and requests would fail or bypass WAF randomly. Dataplane servers and the sync controller therefore run on every pod; Kubernetes writes stay on the leader.
Portable config artifact
After rule resolution, every path produces the same intermediate object — now with an ordered filter list (optional Challenge, then WAF engine):
The ECDS resource type is always:
type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
with modsecurity-proxy-wasm plugin JSON of the form
(see schemas/waf-plugin-config.json):
{
"mode": "kubewaf",
"config_id": "kubewaf/shop/shop-waf",
"allow_fallback": false,
"default_directives": "default",
"directives_map": {
"default": [
"Include @kubewaf-defaults",
"SecRuleEngine On",
"SecDebugLogLevel 3",
"Include @crs-setup-conf",
"Include @owasp_crs/*.conf",
"..."
]
},
"metric_labels": {
"waf_namespace": "shop",
"waf_name": "shop-waf",
"engine": "modsecurity",
"owner": "modsecurity-proxy-wasm",
"team": "payments"
},
"metrics": { "enabled": true, "per_rule_id": true, "rule_tags": true },
"block": { "message": "blocked by kubeWAF" }
}End-to-end request path
Multi-provider slots
| Provider | Slot resource | How filter is installed |
|---|---|---|
| EnvoyGateway | (none owned by kubeWAF) | EG Extension Server hooks mutate xDS |
| Istio | EnvoyFilter | config_discovery → external ECDS |
| Cilium | CiliumEnvoyConfig | CEC clusters + attachment to Service |
See Data plane (ECDS) for configuration details.
Core CRDs
| CRD | Purpose | Maturity |
|---|---|---|
SecRule | Individual security rule (structured YAML) | Stable |
RuleSet | Named collection (selectors, recursion, allowedRules) | Stable |
WAF | Attach RuleSets to a gateway provider + push ECDS | Stable |
WAFInstance | Standalone proxy / sidecar (future) | Alpha |
Data flow (lifecycle)
- Author —
SecRule/SecAction(or CRS converter). - Aggregate —
RuleSetselects rules (names or labels). - Attach —
WAFreferences RuleSets and a provider. - Resolve — flatten graph, enforce namespace policy, back-references (leader).
- Publish — every pod updates its ECDS snapshot.
- Slot — leader ensures EnvoyFilter / CEC / EG index.
- Enforce — modsecurity-proxy-wasm evaluates traffic.
Rule content changes bump the ECDS snapshot only; platform slots are not rewritten unless provider or ECDS endpoint settings change.
Operator ports and Service
| Port | Protocol | Consumers |
|---|---|---|
| 18001 | gRPC ECDS | Envoy (kubewaf_ecds cluster) |
| 5005 | gRPC EG extension API | Envoy Gateway only |
| 18002 | HTTP | Envoy fetching the .wasm binary |
Security model
- Rules are namespaced.
RuleSet.allowedRulescontrols who may contribute rules (Same/All/Selector).- Only
RuleSets attach to aWAF(not rawSecRules). - Platform teams own RuleSets + WAF attachment; app teams own SecRules in their namespace.
Status and conditions
kubectl get waf -o wide
kubectl describe waf shop-waf| Field / condition | Meaning |
|---|---|
Ready | ECDS published and slot ensured |
ReferencesResolved | All RuleSet refs resolved |
status.provider | EnvoyGateway / Istio / Cilium |
status.engine | Active WAF engine (e.g. ModSecurity) |
status.challengeEnabled | PoW filter installed |
status.ecdsResourceName | e.g. kubewaf/shop/shop-waf |
status.ecdsVersion | Snapshot generation counter |
status.slotKind | ExtensionServer / EnvoyFilter / CiliumEnvoyConfig |
Current limitations
WAFInstancedoes not yet deploy proxies.- No validating admission webhooks yet.
- Cilium full L7 filter-chain merge depends on the cluster’s Envoy build (CEC slot is always created).
- Envoy Gateway requires
extensionManagerconfigured to call kubeWAF.
Related projects
- WAF engine (kubeWAF) · modsecurity-proxy-wasm
- PoW challenge (kubeWAF) · pow-proxy-wasm
- Envoy Gateway
- Istio EnvoyFilter
- Cilium Envoy
- OWASP CRS