CrowdSec auf Ubuntu 24.04 mit Traefik (Docker) einsetzen

CrowdSec auf Ubuntu 24.04 mit Traefik (Docker) einsetzen
Photo by McKayla Crump / Unsplash

Wenn im Homelab oder in einer Self-Hosting-Umgebung mehrere Dienste über einen Reverse-Proxy veröffentlicht werden, ist eine zuverlässige Schutzschicht gegen automatisierte Angriffe unerlässlich.

Besonders Systeme, die über Traefik auf den Ports 80 und 443 erreichbar sind, werden regelmäßig von Bots, Scannern und Exploit-Frameworks durchsucht.

Typische Angriffe sind beispielsweise:

  • Brute-Force-Versuche auf Login-Seiten
  • automatisierte Vulnerability-Scanner
  • Bot-Netze, die nach bekannten Exploits suchen
  • aggressive Web-Crawler und Scraper

Eine sehr elegante Lösung für diesen Schutz bietet CrowdSec.

CrowdSec analysiert Logdateien von Services wie Webservern oder Reverse-Proxys und erkennt darin typische Angriffsmuster. Sobald ein Angriff erkannt wird, kann CrowdSec automatisch Gegenmaßnahmen auslösen – beispielsweise das Blockieren der Angreifer-IP über die Firewall des Hosts.

Nachdem wir im vorherigen Beitrag die Einrichtung für den Nginx-Proxy-Manager umgesetzt haben, führt dieser Beitrag durch die Einrichtung für Traefik als Reverse-Proxy:

  • Installation von CrowdSec auf Ubuntu 24.04
  • Einbindung der Traefik-Access-Logs
  • Einsatz des iptables Firewall-Bouncers
  • Integration in ein bestehendes Docker-Setup

Die Architektur sieht dabei typischerweise so aus:

Internet
   ↓
Traefik (Docker Reverse Proxy)
   ↓
Traefik Access Logs
   ↓
CrowdSec Agent (Host)
   ↓
iptables Bouncer (Host Firewall)
   ↓
Angreifer-IP wird geblockt

Der große Vorteil dieses Ansatzes:

Der Angriff wird auf Host-Ebene blockiert, bevor der Traffic erneut den Reverse-Proxy oder einen Container erreicht.

CrowdSec auf Ubuntu 24.04 installieren

Offizielle Installationsanleitung:

Linux | CrowdSec
New to CrowdSec? Start with the introduction to understand the components and prerequisites.

Repository hinzufügen

curl -s https://install.crowdsec.net | sudo bash

Danach installieren:

sudo apt update
sudo apt install crowdsec

Status prüfen:

sudo systemctl status crowdsec
sudo cscli version

iptables installieren (falls noch nicht vorhanden)

Auf den meisten Ubuntu-Servern ist iptables bereits installiert. Falls nicht:

sudo apt install iptables -y

CrowdSec Firewall-Bouncer installieren

Der Bouncer sorgt dafür, dass erkannte Angreifer-IP-Adressen in iptables eingetragen werden.

sudo apt install crowdsec-firewall-bouncer-iptables -y

Status prüfen

sudo systemctl status crowdsec-firewall-bouncer

Docker-Logs von Traefik verfügbar machen

In diesem Abschnitt richten wir jetzt CrowdSec so ein, dass es direkt die Logfiles von Traefik auswertet und Angreifer-IP-Adressen über iptables auf dem Host blockiert.

Das folgende docker-compose.yml kann in folgender Verzeichnisstruktur betrieben werden:

# Verzeichnis für Traefik - docker-compose.yml
mkdir -p /opt/docker/apps/traefik
# Verzeichnis für Traefik - Dateien und Konfiguration
mkdir -p /opt/docker/volumes/traefik

docker-compose.yml

Das docker-compose.yml verwendet die Hetzner API für die Bereitstellung der Letsencrypt-Zertifikate über die DNS-01-Challenge und muss gegebenfalls an den eigenen DNS-Provider angepasst werden.

services:
  traefik:
    image: traefik:latest
    container_name: traefik
    restart: unless-stopped

    command:
      # Dashboard
      - "--api.dashboard=true"
      - "--api.insecure=false"

      # EntryPoints
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"

      # Docker Provider
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"

      # ===== ACME via Hetzner DNS =====
      - "--certificatesresolvers.hetzner.acme.dnschallenge=true"
      - "--certificatesresolvers.hetzner.acme.dnschallenge.provider=hetzner"
      - "--certificatesresolvers.hetzner.acme.dnschallenge.delayBeforeCheck=30"
      - "--certificatesresolvers.hetzner.acme.email=vorname.nachname@domain.tld"
      - "--certificatesresolvers.hetzner.acme.storage=/letsencrypt/acme.json"
      - "--certificatesresolvers.hetzner.acme.dnschallenge.resolvers=1.1.1.1:53,8.8.8.8:53"
      - "--certificatesresolvers.hetzner.acme.dnschallenge.delayBeforeCheck=60"

      # Test-Server (optional beim Einrichten)
      # - "--certificatesresolvers.hetzner.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"

      # Logging
      - "--log.level=DEBUG"

      # Access Logs
      - "--accesslog=true"
      - "--accesslog.filepath=/var/log/traefik/access.log"
      - "--accesslog.format=json"
      - "--accesslog.bufferingsize=100"

    ports:
      - "80:80"
      - "443:443"

    env_file:
      - .env

    environment:
      # ===== Hetzner DNS API =====
      - HETZNER_API_TOKEN=${HETZNER_API_TOKEN}

    labels:
      - "traefik.enable=true"

      # Dashboard Route
      - "traefik.http.routers.traefik.rule=Host(`traefik.domain.tld`)"
      - "traefik.http.routers.traefik.entrypoints=websecure"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.routers.traefik.tls=true"
      - "traefik.http.routers.traefik.tls.certresolver=hetzner"

      # Basic Auth
      - "traefik.http.routers.traefik.middlewares=auth"
      - "traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$05$$1mlLUFUH2qLtgq2nSlEHPu2vgq9eU/3BOChZ9gkuzjaKPMj08c5Ky"

      # Optional: Security Headers
      - "traefik.http.middlewares.secure.headers.stsSeconds=31536000"
      - "traefik.http.middlewares.secure.headers.stsIncludeSubdomains=true"
      - "traefik.http.middlewares.secure.headers.stsPreload=true"

    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /opt/docker/volumes/traefik/letsencrypt:/letsencrypt
      - /opt/docker/volumes/traefik/logs:/var/log/traefik

    networks:
      - traefik

networks:
  traefik:
    external: true

Für das eigene Setup müssen folgende Parameter angepasst werden:

...
- "--certificatesresolvers.hetzner.acme.email=vorname.nachname@domain.tld"
...
- "traefik.http.routers.traefik.rule=Host(`traefik.domain.tld`)"
...
- "traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$05$$1mlLUFUH2qLtgq2nSlEHPu2vgq9eU/3BOChZ9gkuzjaKPMj08c5Ky"
...

Das Passwort für das Traefik-Admin-Dashboard lässt sich mit folgendem Befehl erstellen:

echo $(htpasswd -nbB admin 'MeinSuperPasswort') | sed -e s/\\$/\\$\\$/g
💡
In der docker-compose.yml müssen die $ Zeichen verdoppelt werden, wenn man nur htpasswd ausführt.
Der sed-Befehl am Ende übernimmt diese Aufgabe bereits.

Der Token für die Hetzner-API wird in die Datei .env ausgelagert.
Die Datei sollte mit den Berechtigungen 0600 abgesichert werden, sodass nur der Besitzer Zugriff hat.

umask 177 && printf "HETZNER_API_TOKEN=12345ABCD\n" > .env

Traefik Collection installieren

sudo cscli collections install crowdsecurity/traefik

Damit werden passende Parser und Szenarien installiert.

Zusätzlich können optional noch Szenarien für eine WAF-Funktionalität mit installiert werden:

sudo cscli collections install crowdsecurity/appsec-generic-rules crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-crs

Acquisition-Datei für CrowdSec erstellen

Nun erstellen wir eine neue Konfigurationsdatei für CrowdSec:

sudo nano /etc/crowdsec/acquis.d/traefik.yaml

Inhalt:

filenames:
  - /opt/docker/volumes/traefik/logs/*.log
labels:
  type: traefik
source: file

Erklärung

  • access.log

Mit der Standard-Konfiguration von eben wird der komplette Traffic, welcher über Traefik läuft in das access.log geschrieben. Das Pattern ist aber absichtlich so weit gefasst, dass auch angepasste Logs (z. B. access-webseite-01.log) mit berücksichtigt werden.

CrowdSec neu starten

sudo systemctl restart crowdsec

Prüfen, ob die Logs eingelesen werden

Wichtig:
Die Dateien erscheinen erst in den Metrics, nachdem sie nach dem Neustart verändert wurden.

Also:

  • Entweder warten, bis echter Traffic kommt
  • Oder selbst deine Website aufrufen
  • Oder Test-Traffic erzeugen

Dann prüfen:

sudo cscli metrics show acquisition

Dort sollten Einträge erscheinen wie:

Funktionsweise nach erfolgreicher Einrichtung

Sobald:

  • Ein Bot die Seite scannt
  • Eine Brute-Force-Anfrage erfolgt
  • Ein bekannter Exploit-Versuch erkannt wird

passiert Folgendes:

  1. CrowdSec erkennt das Muster in den Logs
  2. Eine Entscheidung wird erstellt
  3. Der Firewall-Bouncer aktualisiert iptables
  4. Die IP wird auf dem Docker-Host blockiert
💡
Der Traffic wird damit geblockt, bevor er den Container erneut erreicht.

Zusammenfassung

Für Traefik benötigt man:

  • iptables
  • crowdsec-firewall-bouncer-iptables
  • crowdsecurity/traefik Collection
  • Eine passende acquis.yaml mit Logfiles

Damit erhält man:

  • Automatischen Schutz für alle Proxy Hosts
  • Hostbasierte IP-Sperren
  • Saubere Trennung zwischen Docker und Security-Layer