RousselTMLEARNING

Observabilité

Protéger Traefik avec CrowdSec : le plugin bouncer

Mettre en place le bouncer CrowdSec dans Traefik : plugin, middleware, modes stream et live, IP réelle derrière un CDN, logs d'accès et WAF AppSec.

1. Le principe #

Un plugin et deux rôles.

Deux intégrations distinctes #

Traefik et CrowdSec se complètent de deux façons :

  • Détection : CrowdSec lit les logs d'accès de Traefik grâce à la collection crowdsecurity/traefik.
  • Blocage : le plugin communautaire crowdsec-bouncer-traefik-plugin interroge la LAPI et renvoie 403 aux adresses bannies.

Le client passe par un CDN puis Traefik, dont le middleware interroge la Local API avant de transmettre à l’application

2. La mise en place #

Configuration statique et dynamique.

La clé #

docker compose exec crowdsec cscli bouncers add traefik
# ou, côté image CrowdSec : BOUNCER_KEY_traefik=une-cle-longue-et-aleatoire

Configuration statique #

entryPoints:
  web:
    address: ":80"
    forwardedHeaders:
      trustedIPs:          # uniquement si un proxy ou un CDN est devant Traefik
        - 10.0.0.0/8
accessLog:
  filePath: /var/log/traefik/access.log
providers:
  file:
    filename: /etc/traefik/dynamic.yml
experimental:
  plugins:
    bouncer:
      moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin
      version: v1.8.1

Redémarrez Traefik : il télécharge le plugin au démarrage. Il a donc besoin d'accéder à Internet à ce moment-là.

Configuration dynamique #

http:
  middlewares:
    crowdsec:
      plugin:
        bouncer:
          enabled: true
          crowdsecMode: stream
          updateIntervalSeconds: 15
          crowdsecLapiScheme: http
          crowdsecLapiHost: crowdsec:8080
          crowdsecLapiKey: VOTRE_CLE
          forwardedHeadersTrustedIPs:
            - 10.0.0.0/8
  routers:
    app:
      rule: "Host(`app.example.com`)"
      entryPoints: [web]
      service: app
      middlewares: [crowdsec]
  services:
    app:
      loadBalancer:
        servers:
          - url: "http://app:8080"

Avec les labels Docker :

services:
  whoami:
    image: traefik/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
      - "traefik.http.routers.whoami.middlewares=crowdsec@docker"
      - "traefik.http.middlewares.crowdsec.plugin.bouncer.enabled=true"
      - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecmode=stream"
      - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdseclapihost=crowdsec:8080"
      - "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdseclapikey=VOTRE_CLE"

Les modes du plugin #

ModeFonctionnement
noneUne requête à la LAPI par requête reçue
livePareil, avec un cache par IP de defaultDecisionSeconds (60 s). Mode par défaut
streamCache local des IP bannies, synchronisé toutes les updateIntervalSeconds (60 s). Recommandé
aloneSans LAPI locale : liste de la CAPI
appsecUniquement l’inspection AppSec

3. Le piège de l’IP réelle #

Derrière un CDN ou un load balancer.

Le symptôme #

Tout semble fonctionner, mais une IP bannie continue de passer. Nous l'avons reproduit : sans la confiance de l'entrypoint, Traefik écrase X-Forwarded-For. Le plugin voit l'adresse du proxy, jamais celle du client.

Configuration testéeIP bannie
Sans forwardedHeaders.trustedIPs sur l’entrypoint200 : pas de blocage
Avec, en mode stream403 après la synchronisation
Avec, décision supprimée200 de nouveau

La solution #

Il faut déclarer le proxy de confiance à deux endroits : forwardedHeaders.trustedIPs sur l'entrypoint, et forwardedHeadersTrustedIPs dans le plugin. Limitez ces plages à vos vrais proxys : un client ne doit pas pouvoir falsifier son adresse.

Pour exclure votre réseau interne du contrôle, utilisez clientTrustedIPs.

4. Aller plus loin #

Détection et WAF.

Lire les logs de Traefik #

filenames:
  - /var/log/traefik/access.log
labels:
  type: traefik
docker compose exec crowdsec cscli collections install crowdsecurity/traefik
docker compose exec crowdsec cscli metrics show acquisition parsers

Activer AppSec #

crowdsecAppsecEnabled: true
crowdsecAppsecHost: crowdsec:7422
crowdsecAppsecFailureBlock: true
crowdsecAppsecUnreachableBlock: true
Attention à la disponibilité. Avec crowdsecAppsecUnreachableBlock: true (valeur par défaut), le site est bloqué si AppSec est injoignable. Choisissez ce comportement en connaissance de cause.

Sources #

Blocage vérifié sur Traefik 3.7.17, plugin 1.8.1 et CrowdSec 1.8.2.

Articles liés

CrowdSec : comprendre le pare-feu collaboratif

Ce qu'est CrowdSec, comment il détecte et bloque les attaques : Security Engine, parsers, scénarios, Local AP…

CrowdSec ou Fail2ban : quelles différences ?

Comparaison de CrowdSec et Fail2ban : détection, blocage, partage, performances, multi-serveurs, et méthode p…

Installer et configurer CrowdSec : paquets, Docker, acquisition

Installer CrowdSec avec les paquets ou Docker, comprendre ses fichiers, déclarer les logs à lire, enrôler la …

Pour aller plus loin

Soutenir

♥ SOUTENIR

Soutenez RousselTM Learning

Les formations, articles, TP et attestations restent gratuits et sans publicité intrusive. Une contribution libre, du montant de votre choix, finance l’hébergement, les environnements de TP et l’écriture de nouveaux contenus.

Contribuer avec PayPal Montant libre · carte bancaire ou compte PayPalEn savoir plus
QR code PayPal
Ou scannez ce QR code avec votre téléphone

Merci, chaque contribution compte !