PR 1/3: add coraza-spoa sidecar image
Some checks failed
Build and push coraza-spoa / Build-and-Push (push) Failing after 24s
HAProxy Manager Build and Push / Build-and-Push (push) Successful in 55s

Self-contained sidecar that runs Coraza-SPOA v0.7.1 (latest upstream as of
2026-05-08, with OWASP CRS bundled in the binary). HAProxy will consult it
per-request via SPOE in PR 2; for now this PR ships the image only.

Defines:
- coraza-spoa/Dockerfile       — multi-stage build (golang:1.25 -> distroless),
                                 pinned to v0.7.1, ARG-overridable
- coraza-spoa/config.yaml      — single application "haproxy", JSON audit log
                                 to /var/log/coraza/audit.log, SecRuleEngine
                                 DetectionOnly globally
- coraza-spoa/overrides.conf   — day-one enforce list: scanner UAs (913xxx),
                                 RCE shell injection (932100-932160),
                                 webshell paths (933170-933200), targeted LFI
                                 (930120), Log4Shell/JNDI (944100-944300).
                                 Rationale per-range documented inline.
                                 Detect-only for XSS/SQLi/protocol (high FP
                                 on WP/WooCommerce/Divi customer mix).
- coraza-spoa/README.md        — deployment shape, audit log location, pin
                                 upgrade procedure, false-positive tuning.
- .gitea/workflows/build-push-coraza.yaml — Gitea Action triggered on
                                 coraza-spoa/** changes, publishes
                                 repo.anhonesthost.net/cloud-hosting-platform/
                                 coraza-spoa:latest. Path-scoped so it
                                 doesn't fire on every haproxy-manager push.

No changes to haproxy-manager-base itself in this PR — the existing image
stays bit-identical, used standalone in home networks and other projects
without dependency on this sidecar. PR 2 will add the OPT-IN template
plumbing that lets haproxy-manager call out to this agent when an env var
is set.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-12 16:28:44 -07:00
parent 55670daf5b
commit e4c506bcd9
5 changed files with 304 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
# WHP day-one enforce overrides for coraza-spoa.
#
# Global mode in config.yaml is SecRuleEngine DetectionOnly. The rule ID
# ranges below are promoted to enforcement individually, chosen for very
# low false-positive rate on the kinds of customer traffic seen on WHP
# (WordPress, WooCommerce, Divi page builders).
#
# When bumping the upstream coraza-spoa pin (and thus the bundled CRS):
# 1. Skim the CRS CHANGELOG for new/changed rules in these ID ranges.
# 2. Verify they're still high-confidence before promoting the new image.
# 3. Smoke-test in staging detect-only mode for 24h before flipping enforce.
#
# Per-customer false-positive tuning lives in a future per-customer
# override mechanism; v1 is server-wide.
# ---------------------------------------------------------------------------
# 913xxx — Scanner User-Agents
# (sqlmap, nikto, nmap-scripts, dirbuster, masscan, gobuster, ZAP, w3af, etc.)
# Legitimate browsers and apps never send these UAs. Pure recon/exploit
# tooling. Highest signal-to-noise rule family in CRS.
# ---------------------------------------------------------------------------
SecRuleUpdateActionById 913100-913199 "ctl:ruleEngine=On"
# ---------------------------------------------------------------------------
# 930120 — LFI: explicit traversal to sensitive system files
# (/etc/passwd, /proc/self/, /.ssh/, /etc/shadow, /etc/group, etc.)
# Unambiguous probe pattern; no legitimate site path leads here.
# Note: 930xxx as a whole includes broader traversal patterns that can FP
# on legitimate relative-path file browsers — keep those detect-only.
# ---------------------------------------------------------------------------
SecRuleUpdateActionById 930120 "ctl:ruleEngine=On"
# ---------------------------------------------------------------------------
# 932100-932160 — RCE: Unix shell command injection
# Patterns like `; cat /etc/passwd`, `|whoami`, backtick `\`uname\``,
# $(...) substitution, &&/|| chaining with shell builtins.
# Don't appear in normal POST bodies, URL params, or headers. Targeting
# these is unambiguous attempted command execution.
# ---------------------------------------------------------------------------
SecRuleUpdateActionById 932100-932160 "ctl:ruleEngine=On"
# ---------------------------------------------------------------------------
# 933170-933200 — PHP Webshell access patterns
# Direct requests to known webshell paths: c99.php, r57.php, b374k.php,
# wso.php, alfa.php, mini.php, etc. Almost universally reconnaissance
# scanning for post-exploitation. Even legitimate WordPress installs
# never serve these paths.
# ---------------------------------------------------------------------------
SecRuleUpdateActionById 933170-933200 "ctl:ruleEngine=On"
# ---------------------------------------------------------------------------
# 944100-944300 — Log4Shell / JNDI injection
# `${jndi:ldap://}`, `${jndi:rmi://}`, and obfuscated variants thereof
# in headers, query strings, or bodies. Even our PHP/Node stack isn't
# vulnerable, but blocking at the edge keeps logs clean and protects
# any future Java workloads.
# ---------------------------------------------------------------------------
SecRuleUpdateActionById 944100-944300 "ctl:ruleEngine=On"
# ---------------------------------------------------------------------------
# Rule families intentionally kept at DETECT-ONLY for v1 — high FP rate
# on customer mix. Promote individually after observation:
#
# 941xxx (XSS) — Divi rich-text editor saves, TinyMCE submissions
# 942xxx (SQLi) — WP admin queries reflected in params
# 920xxx (Protocol) — Cloudflare-in-front sometimes injects odd headers
# 950xxx-953xxx — Data leakage / backup-file disclosure (mixed FP)
# ---------------------------------------------------------------------------