From e34a0e909d9398b5af1d47c5fefb497252279901 Mon Sep 17 00:00:00 2001 From: devydave Date: Sat, 18 Jul 2026 13:04:43 +0200 Subject: [PATCH] feat: adds crowdsec --- .env.sample | 6 ++++ README.md | 46 +++++++++++++++++++++++++++++++ abra.sh | 5 ++-- compose.crowdsec.yml | 42 ++++++++++++++++++++++++++++ compose.yml | 2 ++ crowdsec_traefik_config.yaml.tmpl | 5 ++++ file-provider.yml.tmpl | 12 +++++++- traefik.yml.tmpl | 13 +++++++++ 8 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 compose.crowdsec.yml create mode 100644 crowdsec_traefik_config.yaml.tmpl diff --git a/.env.sample b/.env.sample index 9389641..0d57b76 100644 --- a/.env.sample +++ b/.env.sample @@ -223,5 +223,11 @@ WRITE_TIMEOUT=0s #ANUBIS_SERVE_ROBOTS_TXT=true #ANUBIS_SLOG_LEVEL=INFO +## Crowdsec +#COMPOSE_FILE="$COMPOSE_FILE:compose.crowdsec.yml" +#CROWDSEC_ENABLED=1 +#CROWDSEC_BOUNCER_ENABLED=1 +#CROWDSEC_TRAEFIK_BOUNCER_API_KEY="some-api-key" + ## Enable onion service support #ONION_ENABLED=1 diff --git a/README.md b/README.md index b845d48..fc89c8b 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,52 @@ After deploying these changes, go to each recipe that supports Anubis and follow the process there. **Enabling Anubis here is not enough for protection your apps.** +## Crowdsec + +IMPORTANT even though Crowdsec is Open Source, the software sends information of the attacker IP and what decision(ban or captcha) to a centralized server for communit managed block lists. + +On first deployment you need to generate an empty secret, because the lapi key is created at runtime. +``` +abra app secret insert crowdsec_lapi_key v1 +``` + +Then deploy your traefik recipe with the crowdsec compose and variables enabled and set `CROWDSEC_BOUNCER_ENABLED=0` to prevent initializing the bouncer that has no key yet. + +When traefik is running, generate the LAPI key with the following command: +``` +abra app run crowdsec cscli bouncers add crowdsecBouncer +``` + +After that insert the LAPI key(command below) and redeploy traefik with `CROWDSEC_BOUNCER_ENABLED=1` and `CROWDSEC_TRAEFIK_CONFIG_VERSION=v2`. +``` +abra app secret insert crowdsec_lapi_key v2 -f -t +``` + +When it is up and running go to the recipe you want to protect and add the following snippet and redeploy. +``` +--- +version: "3.8" +services: + app: + deploy: + labels: + - "traefik.http.routers.${STACK_NAME}.middlewares=crowdsec@file" +``` + +You can see if it is working by checking the ban list. +``` +abra app run crowdsec cscli decisions list +``` + +When there are not bans yet you can try by banning your own IP. +``` +abra app run crowdsec cscli decisions add --ip -d 10m # this will be effective 10min +``` +Remove it with: +``` +abra app run crowdsec cscli decisions remove --ip # this can still take a few minutes because of cache +``` + ## Enabling onion service Uncomment the line in the config setting `ONION_ENABLED=1`. This will create a new entrypoint on port 9052 which can be used to bypass forced SSL. For more details, see the [onion recipe](https://recipes.coopcloud.tech/onion). diff --git a/abra.sh b/abra.sh index d5c01aa..512d69f 100644 --- a/abra.sh +++ b/abra.sh @@ -1,3 +1,4 @@ -export TRAEFIK_YML_VERSION=v32 -export FILE_PROVIDER_YML_VERSION=v12 +export TRAEFIK_YML_VERSION=v33 +export FILE_PROVIDER_YML_VERSION=v15 export ENTRYPOINT_VERSION=v5 +export CROWDSEC_TRAEFIK_CONFIG_VERSION=v1 diff --git a/compose.crowdsec.yml b/compose.crowdsec.yml new file mode 100644 index 0000000..d56cf3e --- /dev/null +++ b/compose.crowdsec.yml @@ -0,0 +1,42 @@ +version: "3.8" +services: + app: + deploy: + labels: + - "traefik.http.routers.${STACK_NAME}.middlewares=crowdsec@file" + secrets: + - crowdsec_lapi_key + crowdsec: + image: crowdsecurity/crowdsec:v1.7.8 + environment: + GID: "${GID-1000}" + COLLECTIONS: "crowdsecurity/linux crowdsecurity/traefik" + volumes: + - crowdsec-db:/var/lib/crowdsec/data/ + - crowdsec-config:/etc/crowdsec/ + - traefik-logs:/var/log/traefik/:ro + configs: + - source: crowdsec_traefik_config + target: /etc/crowdsec/acquis.d/traefik_config.yaml + mode: 0555 + networks: + - internal + deploy: + update_config: + failure_action: rollback + order: stop-first + +configs: + crowdsec_traefik_config: + name: ${STACK_NAME}_crowdsec_traefik_${CROWDSEC_TRAEFIK_CONFIG_VERSION} + file: crowdsec_traefik_config.yaml.tmpl + template_driver: golang + +secrets: + crowdsec_lapi_key: + external: true + name: ${STACK_NAME}_crowdsec_lapi_key_${SECRET_CROWDSEC_LAPI_KEY_VERSION} + +volumes: + crowdsec-db: + crowdsec-config: diff --git a/compose.yml b/compose.yml index 5ff848e..aff482b 100644 --- a/compose.yml +++ b/compose.yml @@ -19,6 +19,7 @@ services: volumes: - "letsencrypt:/etc/letsencrypt" - "file-providers:/etc/traefik/file-providers" + - "traefik-logs:/var/log/traefik" configs: - source: traefik_yml target: /etc/traefik/traefik.yml @@ -121,3 +122,4 @@ configs: volumes: letsencrypt: file-providers: + traefik-logs: diff --git a/crowdsec_traefik_config.yaml.tmpl b/crowdsec_traefik_config.yaml.tmpl new file mode 100644 index 0000000..7206d20 --- /dev/null +++ b/crowdsec_traefik_config.yaml.tmpl @@ -0,0 +1,5 @@ +filenames: + - /var/log/traefik/* +labels: + type: traefik + diff --git a/file-provider.yml.tmpl b/file-provider.yml.tmpl index 6bab128..0364794 100644 --- a/file-provider.yml.tmpl +++ b/file-provider.yml.tmpl @@ -22,6 +22,16 @@ http: basicAuth: usersFile: "/run/secrets/usersfile" {{ end }} + {{ if eq (env "CROWDSEC_ENABLED") "1" }} + crowdsec: + plugin: + bouncer: + enabled: {{ if eq (env "CROWDSEC_BOUNCER_ENABLED") "1" }}true{{ else }}false{{ end }} + logLevel: DEBUG + crowdsecMode: live + crowdsecLapiKey: "{{ if eq (env "CROWDSEC_BOUNCER_ENABLED") "1" }}{{ secret "crowdsec_lapi_key" }}{{ else }}please_set_CROWDSEC_BOUNCER_ENABLED_to_1{{ end }}" + crowdsecLapiHost: crowdsec:8080 + {{ end }} security: headers: frameDeny: true @@ -61,4 +71,4 @@ tls: certificates: - certFile: /run/secrets/ssl_cert keyFile: /run/secrets/ssl_key - {{ end }} \ No newline at end of file + {{ end }} diff --git a/traefik.yml.tmpl b/traefik.yml.tmpl index 28277b9..dc2a6d6 100644 --- a/traefik.yml.tmpl +++ b/traefik.yml.tmpl @@ -5,6 +5,11 @@ core: log: level: {{ env "LOG_LEVEL" }} maxAge: {{ env "LOG_MAX_AGE" }} +{{- if eq (env "CROWDSEC_ENABLED") "1" }} + filePath: "/var/log/traefik/traefik.log" +accessLog: + filePath: "/var/log/traefik/access.log" +{{- end }} providers: swarm: @@ -157,3 +162,11 @@ certificatesResolvers: - "1.1.1.1:53" - "9.9.9.9:53" {{- end }} + +{{ if eq (env "CROWDSEC_ENABLED") "1" }} +experimental: + plugins: + bouncer: + moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin + version: v1.6.0 +{{- end }} -- 2.52.0