Coraza WAF via SPOE
Was ist das?
Coraza ist eine moderne WAF-Engine (Go), die das OWASP Core Rule Set (CRS) ausführt. Die Integration in HAProxy erfolgt über SPOE – denselben Mechanismus wie bei CrowdSec.
Schaubild
Installation des SPOE-Agents
Coraza läuft als eigenständiger Prozess neben HAProxy. Das Binary wird direkt aus dem Quellcode gebaut – Go ist dafür erforderlich.
apt install -y golang-go git
git clone https://github.com/corazawaf/coraza-spoa.git /opt/coraza-spoa
cd /opt/coraza-spoa
go build -o /usr/local/bin/coraza-spoa .
cd /
- Hinweis
./...funktioniert hier nicht, da das Repo mehrere Packages enthält. Das Binary landet direkt unter/usr/local/bin/– kein separatercp-Schritt nötig.
Coraza-Konfiguration
Die Konfiguration erfolgt als YAML-Datei. Die OWASP-Regeln (@owasp_crs/) sind im Binary eingebaut – ein separater CRS-Clone ist nicht nötig.
- mkdir -p /etc/coraza-spoa
- mkdir -p /var/log/coraza
- chown haproxy:haproxy /var/log/coraza
- chmod 750 /var/log/coraza
- nano /etc/coraza-spoa/coraza-spoa.yaml
bind: 127.0.0.1:9000
log_level: info
log_file: /var/log/coraza/coraza-spoa.log
log_format: json
default_application: sample_app
applications:
- name: sample_app
directives: |
Include @coraza.conf-recommended
Include @crs-setup.conf.example
Include @owasp_crs/*.conf
SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess On
SecAuditLog /var/log/coraza/audit.log
SecAuditLogType Serial
SecAuditEngine RelevantOnly
response_check: false
transaction_ttl_ms: 60000
log_level: info
log_file: /var/log/coraza/coraza-spoa.log
log_format: json
- Hinweis
chownundchmodsind zwingend – coraza-spoa läuft als Userhaproxyund benötigt Schreibrecht auf das Log-Verzeichnis.
SPOE-Agent als Systemd-Service
Coraza-SPOA wird als eigener Systemd-Service betrieben. Bei einem Absturz startet systemd den Prozess automatisch neu.
- nano /etc/systemd/system/coraza-spoa.service
[Unit]
Description=Coraza SPOA for HAProxy
After=network.target
[Service]
ExecStart=/usr/local/bin/coraza-spoa -config /etc/coraza-spoa/coraza-spoa.yaml
Restart=on-failure
User=haproxy
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now coraza-spoa
SPOE-Konfiguration für HAProxy
SPOE (Stream Processing Offload Engine) ist der HAProxy-Mechanismus um Requests an externe Prozesse auszulagern. Die Konfigurationsdatei verbindet HAProxy mit dem laufenden Coraza-Prozess.
- nano /etc/haproxy/coraza.cfg
[coraza]
spoe-agent coraza-agent
messages coraza-req
option var-prefix coraza
option set-on-error error
timeout hello 2s
timeout idle 2m
timeout processing 500ms
use-backend coraza-spoa
spoe-message coraza-req
args app=str(sample_app) id=unique-id 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
event on-frontend-http-request
- Wichtig
- Der Section-Header
[coraza]muss exakt mit dem engine-Namen inhaproxy.cfgübereinstimmen. Leerzeile am Dateiende ist zwingend, sonst meldet HAProxy Missing LF on last line.
HAProxy Konfiguration erweitern
HAProxy übergibt jeden eingehenden Request via SPOE an Coraza. Liefert Coraza den Verdict deny zurück, blockiert HAProxy den Request mit HTTP 403 und zeigt die eigene Fehlerseite an.
Im frontend ft_https ergänzen:
frontend ft_https
bind 10.88.2XX.41:443 ssl crt /etc/haproxy/ssl/revproxy.pem alpn http/1.1
# ... bestehende Einträge ...
filter spoe engine coraza config /etc/haproxy/coraza.cfg
http-request deny deny_status 403 if { var(txn.coraza.action) -m str deny }
Backend für den Coraza-SPOA hinzufügen:
backend coraza-spoa mode tcp server coraza 127.0.0.1:9000
- Wichtig
mode tcpist zwingend – ohne das schlägt der Config-Check fehl.alpn http/1.1in der bind-Zeile ist erforderlich damit HAProxy eigene Fehlerseiten ausliefert.
Konfiguration testen und neu laden
- haproxy -c -f /etc/haproxy/haproxy.cfg
- systemctl reload haproxy
Test
Klassischer WAF-Test mit einem OWASP-typischen Angriff (SQL Injection):
- curl -vk "https://revproxy.it2XX.int/?id=1'+OR+'1'='1"
Erwartet: HTTP 403
XSS-Test:
- curl -vk "https://revproxy.it2XX.int/?q=<script>alert(1)</script>"
Erwartet: HTTP 403
Logs beobachten:
- journalctl -fu coraza-spoa
- tail -f /var/log/coraza/audit.log
