feat(waf): Phase 2 — edgeguard-waf Binary + SPOE + Coraza Engine — v1.2.67

- cmd/edgeguard-waf/: neues Binary — lädt WAF-Configs aus DB, startet
  SPOE-Agent auf 127.0.0.1:9000, refreshed Configs alle 30s
- internal/waf/engine.go: BuildEngine() — Coraza WAF aus WafConfig bauen
  (SecLang-Direktiven: RuleEngine, PL, CRS-Include, Exclusions, Custom)
- internal/waf/manager.go: Manager — per-Hostname Coraza-Engine-Cache
  (thread-safe, Lazy-Init via Reload(), Port-Strip, IPv6-Brackets)
- internal/waf/spoe.go: SPOEAgent — haproxy-go SPOE-Handler
  (src/method/path/query/ver/host/headers aus HAProxy-Vars,
   Coraza-Transaction, Blocking: txn.waf.status=403 setzen)
- services/waf/waf.go: ListAllWithDomain() — JOIN domains+waf_configs
- go.mod: coraza/v3 v3.7.0 + dropmorepackets/haproxy-go v0.0.8

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Debian
2026-06-02 15:43:15 +02:00
parent 72f793552e
commit bd32bc343a
8 changed files with 599 additions and 16 deletions

View File

@@ -112,3 +112,42 @@ func (r *Repo) ListEnabled(ctx context.Context) ([]models.WafConfig, error) {
}
return out, rows.Err()
}
// DomainConfigPair combines a domain hostname with its WAF config.
type DomainConfigPair struct {
Hostname string
Config models.WafConfig
}
// ListAllWithDomain returns all WAF configs joined with their domain name.
// Used by the WAF agent to build the hostname→engine mapping.
func (r *Repo) ListAllWithDomain(ctx context.Context) ([]DomainConfigPair, error) {
rows, err := r.Pool.Query(ctx, `
SELECT d.name,
w.id, w.domain_id, w.enabled, w.mode, w.paranoia_level,
w.rule_exclusions, w.trusted_proxies, w.custom_rules, w.updated_at
FROM waf_configs w
JOIN domains d ON d.id = w.domain_id
WHERE d.active = true
ORDER BY d.name ASC
`)
if err != nil {
return nil, err
}
defer rows.Close()
out := make([]DomainConfigPair, 0, 16)
for rows.Next() {
var p DomainConfigPair
var c models.WafConfig
if err := rows.Scan(
&p.Hostname,
&c.ID, &c.DomainID, &c.Enabled, &c.Mode, &c.ParanoiaLevel,
&c.RuleExclusions, &c.TrustedProxies, &c.CustomRules, &c.UpdatedAt,
); err != nil {
return nil, err
}
p.Config = c
out = append(out, p)
}
return out, rows.Err()
}