Ingress can run a first-version WAF on matched routes after routing and before redirects, handlers, or upstream proxies. It covers:
- IP lists (
denythen optionalallowgate). - Signature checks against
path,query, assembleduri, all header lines (headers), or one header (header:User-Agent). - An optional embedded starter ruleset (SQLi/path traversal/reflected-scripting probes). Turn off with
disable_builtin: trueif it is too noisy.
There is no request-body scanning. Use log_only (global or per rule) to audit before blocking.
- Top-level
waf:is the typed global baseline. rules[].wafis a partial YAML map merged onto that baseline for the matched host rule.
::: warning Config loader caveat
The generic config decoder cannot partially merge map keys into structs, so rules[].waf is applied in waf.ApplyRulePatchesFromYAML (core/waf/yaml.go) after config.Load. Embedded configs built in Go must set rules[i].WAFPatch manually when you need route overlays without a file.
:::
- Effective policy = merge(global
waf,rules[i].WAFPatch). - Exit if
enabledis false. - Resolve client IP (
trust_proxy+xff_index; default index 0 = leftmost segment inX-Forwarded-For). - Deny list, then Allow when non-empty (only listed nets may pass the IP phase).
- Signatures: starters unless
disable_builtin, then custom rules in merged order.
Blocked clients receive block_status_code (default 403), block_content_type, and block_body.
When disable_builtin is not true, the following rules are appended before custom entries in waf.rules. IDs are stable so you can replace a builtin by adding your own rule with the same id (see examples/waf/rule-merge-by-id.yaml). Patterns use Go regexp syntax.
| ID | Targets | Description |
|---|---|---|
builtin:sqli-common |
uri |
Common SQL-injection style probes in path + raw query (union select, sleep(, benchmark(, ; drop/truncate/alter table, …). |
builtin:path-traversal |
path |
Path traversal probes (../, ..\, encoded .., etc/passwd). |
builtin:xss-lite |
uri |
Light reflected-scripting probes (<script, javascript:, on*=-style event handlers). |
Exact patterns (from core/waf/builtin.go; change there if you fork):
builtin:sqli-common
(?is)(union\s+select\b|sleep\s*\(|benchmark\s*\(|;\s*(drop|truncate|alter)\s+table\b)
builtin:path-traversal
(?:\.\./|\.\.\\|%2e%2e%2f|%2e%2e\\\\|etc/passwd\b)
builtin:xss-lite
(?is)(<\s*script\b|javascript:\s*|on\w+\s*=)
Starters can false-positive on unusual but legitimate traffic — use log_only or disable_builtin: true and replace with stricter custom rules as needed.
| Field | Notes |
|---|---|
id |
Required. Route-level waf.rules with the same id replace the global rule of that id. |
type |
regex (default) or contains |
pattern |
Compiled at startup for regex. |
targets |
One or more of path, query, uri, headers, header:… |
Runnable files: examples/waf/.