traefik/crowdsec: serve Cloudflare Turnstile for captcha remediation
CrowdSec LAPI already issues `captcha`-type decisions for lower-severity abuse (http-429-abuse, http-403-abuse, http-crawl-non_statics, http-sensitive-files), but the Traefik bouncer plugin had no captcha provider configured — so those decisions silently fell through to a 403 ban (traced in the plugin's bouncer.go @ v1.4.2: captchaClient.Valid==false => handleBanServeHTTP). Flagged users had no way to self-unblock, contradicting the profile's stated intent. Wire Cloudflare Turnstile as the bouncer's captcha provider so a captcha decision now renders a solvable challenge instead of a hard block: - New cloudflare_turnstile_widget.crowdsec_captcha (managed mode), scoped to viktorbarzin.me so one widget covers every subdomain the bouncer fronts. Mirrors the existing Forgejo-signup Turnstile pattern; sitekey + secret are passed into the traefik module. - middleware.tf: captchaProvider=turnstile + site/secret keys + grace 1800s + captchaHTMLFilePath=/captcha/captcha.html. - Vendor the plugin's captcha.html and mount it into the Traefik container at /captcha via the chart `volumes` value — the pulled Yaegi plugin does not expose its bundled template to Traefik. - docs/architecture/security.md: document the ban-vs-captcha remediation split. - Remove the dead crowdsec-ingress-bouncer.yaml (unused nginx bouncer with placeholder reCAPTCHA keys; referenced by zero .tf). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
963e4fcdde
commit
fd0c7493c3
6 changed files with 424 additions and 48 deletions
|
|
@ -80,11 +80,22 @@ CrowdSec operates in a hub-and-agent model:
|
|||
- Reports malicious IPs to LAPI
|
||||
- Shares threat intel with CrowdSec community (anonymized)
|
||||
|
||||
**Traefik Bouncer Plugin**:
|
||||
- Integrated as Traefik middleware
|
||||
**Traefik Bouncer Plugin** (`crowdsec-bouncer-traefik-plugin`, `stacks/traefik/modules/traefik/middleware.tf`):
|
||||
- Integrated as Traefik middleware (in the default ingress chain)
|
||||
- Queries LAPI for IP reputation on each request
|
||||
- **Fail-open mode**: If LAPI unreachable, allows traffic (graceful degradation)
|
||||
- Blocks IPs on ban list, allows others
|
||||
- Honours two LAPI remediation types (profiles in `stacks/crowdsec/modules/crowdsec/values.yaml`):
|
||||
- **`ban`** → HTTP 403 (serious attacks: CVE exploits, scanners, brute force)
|
||||
- **`captcha`** → **Cloudflare Turnstile challenge** so the flagged user can
|
||||
self-unblock (lower-severity abuse: `http-429-abuse`, `http-403-abuse`,
|
||||
`http-crawl-non_statics`, `http-sensitive-files`). The plugin is configured
|
||||
with `captchaProvider=turnstile` + the widget keys; the `captcha.html`
|
||||
template is mounted into the Traefik pod at `/captcha`. The widget is
|
||||
Terraform-managed in `stacks/traefik/main.tf`
|
||||
(`cloudflare_turnstile_widget.crowdsec_captcha`, scoped to `viktorbarzin.me`
|
||||
so it covers every subdomain). **Before 2026-06-19 no captcha provider was
|
||||
configured, so `captcha` decisions silently degraded to a 403 ban** — users
|
||||
had no way to self-unblock; wiring Turnstile fixed that.
|
||||
|
||||
**Metabase** (disabled by default):
|
||||
- Dashboard for CrowdSec analytics
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue