Traefik avec CrowdSec
Architecture
CrowdSec analyse les logs Traefik, détecte les comportements malveillants et applique des décisions via un plugin Traefik natif (crowdsec-bouncer-traefik-plugin).
Utilisateur → Traefik (plugin CrowdSec) → Application
│
├── IP sans décision → accès direct
├── Décision captcha → page Turnstile → accès après résolution
└── Décision ban → HTTP 403
| Type de scénario | Remédiation | Condition |
|---|---|---|
| HTTP (crawl, probing, etc.) | Captcha Turnstile | ≤ 3 décisions en 24h |
| HTTP récidiviste | Ban (403) | > 3 décisions en 24h |
| Non-HTTP (SSH brute force, etc.) | Ban (403) | Toujours |
Après résolution du captcha, grâce de 30 minutes avant qu'un nouveau captcha soit présenté.
Prérequis
Acquisition des logs (acquis.yaml)
Créer /opt/crowdsec/crowdsec-config/acquis.yaml :
Whitelist API CrowdSec (config.yaml)
Ce fichier est généré automatiquement au premier démarrage de CrowdSec. Après le premier lancement, éditer /opt/crowdsec/crowdsec-config/config.yaml :
api:
server:
trusted_ips:
- 127.0.0.1
- 172.0.0.0/4 # Réseau Docker
- ::1
prometheus:
enabled: true
listen_addr: 0.0.0.0
listen_port: 6060
Puis redémarrer : docker compose restart crowdsec
Fichiers secrets
Placer ces fichiers dans /opt/traefik/conf/ :
| Fichier | Contenu | Comment l'obtenir |
|---|---|---|
crowdsec-api-key.txt |
Clé API bouncer | docker exec crowdsec cscli bouncers add crowdsecBouncer -o raw |
turnstile-site-key.txt |
Site Key Turnstile | dash.cloudflare.com > Turnstile — domaine albt.org |
turnstile-secret-key.txt |
Secret Key Turnstile | Même page Cloudflare |
# Écrire les clés (sans retour à la ligne)
echo -n 'CLE_BOUNCER' > /opt/traefik/conf/crowdsec-api-key.txt
echo -n 'SITE_KEY' > /opt/traefik/conf/turnstile-site-key.txt
echo -n 'SECRET_KEY' > /opt/traefik/conf/turnstile-secret-key.txt
Déploiement Docker Compose
services:
crowdsec:
image: crowdsecurity/crowdsec
container_name: crowdsec
environment:
GID: "${GID-1000}"
COLLECTIONS: "crowdsecurity/linux crowdsecurity/traefik"
volumes:
- /opt/crowdsec/crowdsec-db:/var/lib/crowdsec/data/
- /opt/crowdsec/crowdsec-config:/etc/crowdsec/
- /opt/traefik/log:/var/log/traefik/:ro
- $INFRASTRUCTURE_FOLDER_LOCATION/variable-crowdsec-profiles.yaml:/etc/crowdsec/profiles.yaml:ro
networks:
- frontend
restart: unless-stopped
traefik:
image: traefik
container_name: traefik
restart: always
networks:
- frontend
ports:
- "80:80"
- "443:443"
- "8081:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /opt/traefik/certs:/etc/traefik/certs/
- /opt/traefik/conf:/etc/traefik/conf/
- /opt/traefik/log:/var/log/traefik/
- /opt/traefik/plugins-storage:/plugins-storage
- $INFRASTRUCTURE_FOLDER_LOCATION/variable-traefik.yaml:/etc/traefik/traefik.yaml:ro
- $INFRASTRUCTURE_FOLDER_LOCATION/variable-crowdsec-captcha.html:/captcha.html:ro
- $INFRASTRUCTURE_FOLDER_LOCATION/variable-crowdsec-middleware.yaml:/etc/traefik/conf/middleware-crowdsec.yaml:ro
environment:
- CF_DNS_API_TOKEN=$CF_DNS_API_TOKEN
/opt/traefik/plugins-storage: nécessaire car Traefik tourne en non-root et doit pouvoir télécharger les plugins.
Prérequis Réseau : IPv6 Natif Docker
Par défaut, Docker utilise un proxy (Userland Proxy) pour gérer le trafic IPv6 entrant. Ce proxy pose un problème majeur de sécurité : il masque la véritable adresse IPv6 publique du client en la remplaçant par l'adresse IP de la passerelle du réseau Docker (ex: fd01::1).
Conséquence : si CrowdSec détecte une menace, il bannira l'adresse de la passerelle, bloquant ainsi tous les utilisateurs IPv6.
Pour résoudre ce problème et permettre à Traefik de voir les vraies adresses IPv6, il est impératif d'activer le routage IPv6 natif via ip6tables dans le démon Docker de l'hôte.
Éditez le fichier /etc/docker/daemon.json sur le serveur hôte :
Redémarrez ensuite le service Docker (sudo systemctl restart docker) et recréez vos réseaux (docker compose down && docker compose up -d).
Configuration Traefik
Configuration statique (variable-traefik.yaml)
Important : La directive
forwardedHeaders.trustedIPsest cruciale. Elle indique à Traefik de faire confiance aux proxys locaux (comme le bridge Docker) pour lire la véritable adresse IP du client dans les en-têtes HTTP.
global:
checkNewVersion: false
sendAnonymousUsage: false
api:
dashboard: true
insecure: true
entryPoints:
web:
address: :80
http:
middlewares:
- crowdsec-bouncer@file
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: :443
forwardedHeaders:
trustedIPs:
- "127.0.0.1/32"
- "::1/128"
- "fd00::/8"
- "172.16.0.0/12"
- "192.168.0.0/16"
- "10.0.0.0/8"
http:
middlewares:
- crowdsec-bouncer@file
certificatesResolvers:
cloudflare:
acme:
email: "votre.mail@mail.org"
storage: /etc/traefik/certs/cloudflare-acme.json
caServer: 'https://acme-v02.api.letsencrypt.org/directory'
keyType: EC256
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
serversTransport:
insecureSkipVerify: true
providers:
docker:
exposedByDefault: false
endpoint: 'unix:///var/run/docker.sock'
watch: true
file:
directory: /etc/traefik/conf/
watch: true
log:
level: "INFO"
filePath: "/var/log/traefik/traefik.log"
accessLog:
filePath: "/var/log/traefik/access.log"
experimental:
plugins:
bouncer:
moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin
version: v1.5.0
Configuration dynamique (variable-crowdsec-middleware.yaml)
Middleware chargé par le file provider (/etc/traefik/conf/). Configure le plugin bouncer en mode live avec Cloudflare Turnstile comme captcha provider. Les clés sont lues depuis les fichiers secrets dans /etc/traefik/conf/.
Profil CrowdSec (variable-crowdsec-profiles.yaml)
Monté en :ro sur /etc/crowdsec/profiles.yaml (surcharge le fichier du volume principal).
- Scénarios contenant
http→ décision captcha - Après 3 captchas en 24h → bascule vers ban
- Scénarios non-HTTP → ban direct
Template captcha (variable-crowdsec-captcha.html)
Page HTML affichée à l'utilisateur quand une décision captcha est active pour son IP.
Commandes utiles
Toutes les commandes s'exécutent via docker exec crowdsec cscli ...
Décisions
cscli decisions list # Voir les décisions actives
cscli decisions add --ip <IP> -d 10m --type captcha # Forcer un captcha (test)
cscli decisions add --ip <IP> -d 10m --type ban # Forcer un ban (test)
cscli decisions delete --ip <IP> # Supprimer une décision
cscli decisions delete --all # Tout supprimer
Alertes
cscli alerts list # Historique des alertes
cscli alerts list --ip <IP> # Alertes pour une IP
cscli alerts inspect <ID> # Détails d'une alerte
Maintenance
cscli hub update # Mettre à jour le hub
cscli hub upgrade # Mettre à jour les scénarios installés
cscli scenarios list # Scénarios actifs
cscli parsers list # Parsers actifs
cscli bouncers list # État des bouncers connectés