diff --git a/templates/hap_coraza_spoe_engine.tpl b/templates/hap_coraza_spoe_engine.tpl index 37a64a3..3e55db5 100644 --- a/templates/hap_coraza_spoe_engine.tpl +++ b/templates/hap_coraza_spoe_engine.tpl @@ -5,25 +5,33 @@ # via `filter spoe engine coraza config /etc/haproxy/coraza-spoe.cfg`. # # Engine name "coraza" must match the engine name in the filter line in the -# main config and the application name "haproxy" must match the application -# block name in coraza-spoa's config.yaml. +# main config; group name "coraza-req" must match the send-spoe-group action. +# Application name "haproxy" must match the application block in coraza-spoa's +# config.yaml. +# +# Reference: this config follows the shape from coraza-spoa's upstream +# example/haproxy/coraza.cfg (v0.7.1). Arg names + ordering are required by +# Coraza-SPOA exactly as specified — DO NOT reorder or rename without +# coordinating with the agent. [coraza] spoe-agent coraza - # The single message we send (defined below) — per-request inspection. - messages coraza-check + # `groups` (not `messages`) lists the spoe-group names this engine offers + # via `send-spoe-group` actions. The same group name appears below in a + # spoe-group block, which in turn references the actual message. + groups coraza-req - # Prefix for any variables the agent sets back on the request. + # Prefix for variables the agent sets back on the request transaction — + # e.g. var(txn.coraza.error) when set-on-error triggers. option var-prefix coraza - # FAIL-OPEN. If the SPOA is unreachable or times out, requests flow - # through uninspected rather than failing. For a hosting platform, - # availability beats unconditional inspection coverage. - option set-on-error continue + # On agent error/timeout, set var(txn.coraza.error). We DON'T add a + # corresponding `http-request deny if { var(txn.coraza.error) -m bool }` + # in the frontend, so the request continues uninspected. This is the + # fail-open posture: WAF outage shouldn't 503 customer traffic. + option set-on-error error - # Aggressive timeouts: we don't want the WAF to materially slow page - # loads. processing 100ms is the per-request inspection budget. timeout hello 2s timeout idle 2m timeout processing 100ms @@ -31,12 +39,16 @@ spoe-agent coraza use-backend coraza-spoa-backend log global -spoe-message coraza-check - # Send the request shape to Coraza for inspection. - # `app=str(haproxy)` matches the application named "haproxy" in - # coraza-spoa's config.yaml — that's how Coraza picks which ruleset - # to apply. - # NOTE: args must be on ONE line. HAProxy does not support backslash - # line continuations in spoe configs (verified the hard way 2026-05-12). - args app=str(haproxy) src-ip=src src-port=src_port dest-ip=dst dest-port=dst_port method=method path=path query=query version=req.ver headers=req.hdrs body=req.body - event on-frontend-http-request +# Per-request inspection message. No `event` directive — fires only when +# explicitly invoked from haproxy.cfg via `http-request send-spoe-group`. +# Arg order/names are mandatory: Coraza-SPOA parses positionally and renames +# break the agent. `app=str(haproxy)` is the literal application name from +# coraza-spoa's config.yaml `applications:` block. +spoe-message coraza-req + args app=str(haproxy) src-ip=src src-port=src_port dst-ip=dst dst-port=dst_port method=method path=path query=query version=req.ver headers=req.hdrs body=req.body + +# Group binding for send-spoe-group invocation in the frontend. One group, +# one message; could add more in the future (e.g. coraza-res for response +# inspection — currently disabled in coraza-spoa's config.yaml). +spoe-group coraza-req + messages coraza-req diff --git a/templates/hap_listener.tpl b/templates/hap_listener.tpl index a5d924f..f647600 100644 --- a/templates/hap_listener.tpl +++ b/templates/hap_listener.tpl @@ -58,7 +58,9 @@ frontend web # Coraza WAF inspection via SPOE. Runs AFTER rate-limit and IP-block # guards (no point asking the WAF about requests we're already dropping) # and AFTER the real-client-IP resolution (so Coraza sees the right src). - # Fail-open: see `option set-on-error continue` in /etc/haproxy/coraza-spoe.cfg. + # Fail-open: option set-on-error in coraza-spoe.cfg only SETS the error + # var; we deliberately don't have a `http-request deny if errored` rule, + # so SPOA outages let traffic through uninspected. filter spoe engine coraza config /etc/haproxy/coraza-spoe.cfg - http-request send-spoe-group coraza coraza-check + http-request send-spoe-group coraza coraza-req {%- endif %}