PR 1/3: add coraza-spoa sidecar image
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>
2026-05-12 16:28:44 -07:00
|
|
|
# Coraza-SPOA configuration for WHP haproxy-manager integration.
|
|
|
|
|
#
|
|
|
|
|
# One named application "haproxy" — the haproxy-manager spoe template
|
|
|
|
|
# references this same name in its spoe-agent block, so the SPOA knows
|
|
|
|
|
# which rules to apply when HAProxy dispatches a request.
|
|
|
|
|
#
|
|
|
|
|
# Mode: SecRuleEngine DetectionOnly globally; overrides.conf promotes
|
|
|
|
|
# specific high-confidence rule ID ranges to enforcement individually.
|
|
|
|
|
# This is the safest posture for v1 — every rule logs, but only the
|
|
|
|
|
# unambiguous ones (scanner UAs, RCE, LFI, webshells, Log4Shell) block.
|
|
|
|
|
|
|
|
|
|
bind: 0.0.0.0:9000
|
|
|
|
|
|
|
|
|
|
# Process-level logging (separate from per-request audit logging below)
|
|
|
|
|
log_level: info
|
|
|
|
|
log_file: /dev/stdout
|
|
|
|
|
log_format: json
|
|
|
|
|
|
|
|
|
|
# Fallback when the request doesn't match a named application — we only
|
|
|
|
|
# have one, so it's also the default.
|
|
|
|
|
default_application: haproxy
|
|
|
|
|
|
|
|
|
|
applications:
|
|
|
|
|
- name: haproxy
|
|
|
|
|
directives: |
|
|
|
|
|
# CRS-bundled defaults: recommended Coraza settings + CRS setup +
|
|
|
|
|
# the rule pack itself (~16 MB of rules embedded in the binary).
|
|
|
|
|
Include @coraza.conf-recommended
|
|
|
|
|
Include @crs-setup.conf.example
|
2026-05-14 07:55:51 -07:00
|
|
|
|
|
|
|
|
# Runtime-managed PRE-CRS exclusions written by WHP UI. Empty by default.
|
|
|
|
|
# Loaded BEFORE the CRS rules so per-host ctl:ruleRemoveById exemptions
|
|
|
|
|
# fire in phase:1 BEFORE the CRS rule they're trying to exempt would
|
|
|
|
|
# otherwise match. Server-wide overrides live in local-overrides.conf
|
|
|
|
|
# (loaded after CRS) instead.
|
|
|
|
|
Include /etc/coraza/pre-overrides.conf
|
|
|
|
|
|
PR 1/3: add coraza-spoa sidecar image
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>
2026-05-12 16:28:44 -07:00
|
|
|
Include @owasp_crs/*.conf
|
|
|
|
|
|
|
|
|
|
# WHP-specific overrides — day-one enforce list, plus tuning for
|
|
|
|
|
# the customer mix (WordPress, WooCommerce, Divi). Read this file
|
|
|
|
|
# to see exactly what blocks vs what's detect-only.
|
|
|
|
|
Include /etc/coraza/overrides.conf
|
2026-05-14 06:51:24 -07:00
|
|
|
|
2026-05-14 07:55:51 -07:00
|
|
|
# Runtime-managed POST-CRS overrides written by WHP UI. Empty by default.
|
2026-05-14 06:51:24 -07:00
|
|
|
Include /etc/coraza/local-overrides.conf
|
PR 1/3: add coraza-spoa sidecar image
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>
2026-05-12 16:28:44 -07:00
|
|
|
|
|
|
|
|
# Global mode: log all alerts, block only what overrides.conf
|
|
|
|
|
# explicitly promotes via ctl:ruleEngine=On.
|
|
|
|
|
SecRuleEngine DetectionOnly
|
|
|
|
|
|
|
|
|
|
# Audit log: JSON to a bind-mounted file so AI Monitor + log
|
|
|
|
|
# rotation can pick it up. RelevantOnly means we don't log every
|
|
|
|
|
# passing request, only ones that triggered at least one rule.
|
|
|
|
|
SecAuditEngine RelevantOnly
|
|
|
|
|
SecAuditLog /var/log/coraza/audit.log
|
|
|
|
|
SecAuditLogFormat JSON
|
|
|
|
|
SecAuditLogParts ABIJDEFHKZ
|
|
|
|
|
|
|
|
|
|
# HAProxy sends request-only events for v1. Response inspection adds
|
|
|
|
|
# latency on every page render with marginal additional protection
|
|
|
|
|
# for our customer mix; can be turned on later if we want it.
|
|
|
|
|
response_check: false
|
|
|
|
|
|
|
|
|
|
# Transactions cache for 60s. SPOE protocol is fire-and-forget per
|
|
|
|
|
# request, so this is just how long Coraza holds context for any
|
|
|
|
|
# multi-stage processing.
|
|
|
|
|
transaction_ttl_ms: 60000
|
|
|
|
|
|
|
|
|
|
log_level: info
|
|
|
|
|
log_file: /var/log/coraza/spoa.log
|
|
|
|
|
log_format: json
|