mirror of
https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin.git
synced 2026-10-17 23:19:37 +02:00
* add the bot detection feature to the crowdsec traefik bouncer
* fix the return value
* add http status normalization
* fix appsec query test return values
* add boundaries for appsec response
* 🎨 satisfy golangci-lint on the appsec response path
gofmt on bouncer_test.go (merge artifact), a doc comment revive requires
on the exported AppSecResponse, and nolint directives for the linters the
new appsecQuery signature trips: tagliatelle on the snake_case json tags
that are Appsec's wire format, and nilnil/gocognit/gocyclo/funlen on
appsecQuery itself, matching how New is already handled.
No feature code changed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* 🐛 keep serving the configured ban page for appsec bans
An appsec "ban" with a structured body was served straight from appsec,
so an operator with banFilePath configured silently lost their ban page
as soon as Crowdsec 1.8 started returning structured JSON — and got a
blank 403 when appsec sent no user_body_content at all. Route the ban
action back through handleBanServeHTTP, which keeps the template, the
content type, the remediation header value and the trace templating.
Only actions that must carry their own content, challenge among them,
are relayed from appsec. Those now fall back to banTemplateContentType
when appsec sends no Content-Type, instead of letting Go sniff it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* 🍱 reduce test and logic in appsec query
* 🍱 use same appsec response limit as defined for user
* 🍱 fix lint
* 🐛 fix tests
* 🍱 revert to 1Mo appsec response body
* 📝 examples: add a bot detection example
The PR relays the whole AppSec remediation rather than collapsing it into a
403, which is what makes the bot challenge possible: a ban is a status code,
a challenge is a status code plus a body, cookies and headers. Nothing
demonstrated that, so this adds an example alongside the existing ones.
Verified end to end against CrowdSec 1.8.1: the challenge page is served, the
browser solves the proof of work, the submission is accepted and the request
reaches the backend.
Three things break this setup silently, and all three cost time here, so the
README names them:
- The router must also match /crowdsec-internal. The challenge page loads its
fingerprint script and its proof-of-work worker from there by absolute path,
so a router scoped to the application prefix alone returns 404 and the
challenge can never be solved, with no error logged anywhere.
- The acquisition must load the config that calls SendChallenge(), which is
appsec-bot-challenge-scoring; the -balanced variant only carries the
rejection threshold. Loading the latter alone processes requests and
challenges nothing. The wildcard form from the CrowdSec enable guide is used
instead of a hand-written list, since it also picks up the exclusion configs
the collection ships.
- Referencing an appsec-config that is not installed is fatal rather than
degraded. CrowdSec refuses to start and, because crowdsecAppsecFailureBlock
defaults to true, every request then returns a 403 that reads like a WAF
decision. appsec-default needs appsec-virtual-patching and
appsec-generic-rules, so both are in COLLECTIONS.
The routing requirement is in the main README too, since it applies to anyone
enabling bot detection and not just to this example.
The example runs the plugin from the working tree, as relaying the remediation
is not in a release yet; the catalog lines are present and commented out.
* 🍱 reduce complexity and set the remediationHeader to 'challenge' instead of decision.Action
* 📝 examples: add a bot detection example
The PR relays the whole AppSec remediation rather than collapsing it into a
403, which is what makes the bot challenge possible: a ban is a status code,
a challenge is a status code plus a body, cookies and headers. Nothing
demonstrated that, so this adds an example alongside the existing ones.
Verified end to end against CrowdSec 1.8.1: the challenge page is served, the
browser solves the proof of work, the submission is accepted and the request
reaches the backend.
Two things break this setup silently, and both cost time here, so the README
names them:
- The router must also match /crowdsec-internal. The challenge page loads its
fingerprint script and its proof-of-work worker from there by absolute path,
so a router scoped to the application prefix alone returns 404 and the
challenge can never be solved, with no error logged anywhere.
- The acquisition must load the config that calls SendChallenge(), which is
appsec-bot-challenge-scoring; the -balanced variant only carries the
rejection threshold. Loading the latter alone processes requests and
challenges nothing. The wildcard form from the CrowdSec enable guide is used
instead of a hand-written list, since it also picks up the exclusion configs
the collection ships.
The routing requirement is in the main README too, since it applies to anyone
enabling bot detection and not just to this example, along with the supported
versions stated the same way as the existing Appsec line.
* ✅ tests: drop the challenge Content-Type fallback test
c8d7751 removed the fallback that set Content-Type from banTemplateContentType
when the appsec response carried none, but left the test asserting it, so the
suite has been red since.
Removing the test rather than restoring the fallback, per maxlerebourg.
* 🍱 harmonize appsecServer vs appsec in test
* 🍱 reduce loc and go closer to Lua implementation
* 💄 fix log statusCode 401 -> 403
* 🍱 fix lint
* 🍱 add guard on appsec response
* 🍱 fix lint
---------
Co-authored-by: mhx <mathieu@hanotaux.fr>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: maxlerebourg <maxlerebourg@gmail.com>
17 lines
417 B
YAML
17 lines
417 B
YAML
filenames:
|
|
- /var/log/traefik/access.log
|
|
labels:
|
|
type: traefik
|
|
|
|
---
|
|
listen_addr: 0.0.0.0:7422
|
|
# The wildcard matches installed appsec-configs only, so it picks up exactly what the
|
|
# collection provides: the scoring engine, its threshold, and every exclusion config.
|
|
appsec_configs:
|
|
- crowdsecurity/appsec-default
|
|
- crowdsecurity/appsec-bot-*
|
|
name: myBotDetectionComponent
|
|
source: appsec
|
|
labels:
|
|
type: appsec
|