CrowdSec #
CrowdSec wertet die Access-Logs von Traefik aus, erkennt Angriffsmuster anhand von Szenarien und legt daraus Entscheidungen ab, etwa “IP x ist für 4 Stunden gesperrt”. Umgesetzt werden die Entscheidungen von einem Bouncer, hier einem Traefik-Plugin.
Die App wird stufenweise eingeführt:
| Phase | Inhalt | Stand |
|---|---|---|
| 0 | Access-Log von Traefik als JSON (apps/traefik) |
live |
| 1 | LAPI und Agent, nur erkennen, kein Bouncer | diese App |
| 2 | Bouncer-Plugin in Traefik an einer einzelnen Route | offen |
| 3 | Bouncer am Entrypoint websecure und ws-alternate |
offen |
| 4 | AppSec mit Virtual Patching | offen |
Solange kein Bouncer registriert ist, sperrt CrowdSec niemanden. Alarme und
Entscheidungen entstehen trotzdem und lassen sich mit cscli prüfen
(Abschnitt Betrieb).
Quelle #
- Chart
crowdsecaus den CrowdSec-Helm-Charts, Werte invalues.yaml. Aufgebaut nach dem HA-Beispiel im README des Charts und der Kubernetes-Anleitung. - Datenbank: Chart
postgresder CloudPirates-Charts mit dem offiziellen Imagepostgres, Werte invalues-database.yaml. - Images
crowdsecurity/crowdsecundalpine/kubectlmit festem Tag invalues.yaml, Renovate hebt sie.
Parser, Szenarien und Collections lädt der Agent beim Start vom CrowdSec
Hub (COLLECTIONS und PARSERS in values.yaml). Sie haben keine
pinbaren Versionen, ein Neustart kann neuere Fassungen bringen.
Komponenten #
| Objekt | Art | Zweck |
|---|---|---|
crowdsec-lapi |
Deployment, 2 Replikas | Local API: speichert Alarme und Entscheidungen, spricht mit der Central API und der Console |
crowdsec-agent |
DaemonSet auf den Control-Plane-Nodes | liest /var/log/containers/traefik-*_kube-system_*.log |
crowdsec-postgres |
StatefulSet | Datenbank der LAPI, Volume crowdsec-db |
crowdsec-capi-register-job |
Job, Helm-Hook pre-install,pre-upgrade (Argo CD: PreSync) |
registriert die Instanz einmalig bei der Central API und legt das Secret crowdsec-capi-credentials an |
crowdsec-service, crowdsec-agent-service |
ServiceMonitor | Metriken für apps/prometheus |
Der Agent läuft nur dort, wo Traefik läuft: Traefik ist per nodeSelector
auf die Control-Plane-Nodes festgelegt (apps/traefik/values.yaml). Ändert
sich das, muss der nodeSelector des Agents mitziehen.
Die LAPI hat kein eigenes Volume. Alles, was sie behalten muss, liegt in PostgreSQL oder in Secrets. Deshalb laufen zwei Replikas, und ein Update rollt ohne Unterbrechung aus.
Die NetworkPolicy crowdsec-postgres lässt nur die LAPI an die Datenbank.
Konfiguration #
- Datenbank, Aufräumregeln (
flush) und automatische Registrierung der Agents stehen inconfig.config.yaml.localinvalues.yaml, wie im Beispiel der Doku. allowed_rangesder automatischen Registrierung umfasst nur das Pod-Netz des Clusters.- Eigene Adressen stehen in der Whitelist
zyria-whitelist.yaml(config.parsers.s02-enrich), dieselben wie in der Middlewarelocalnetvonapps/traefik. Private Bereiche deckt der Parsercrowdsecurity/whitelistsab. Eine Adresse auf der Whitelist erzeugt keinen Alarm, keine Entscheidung und kein Signal an die Central API.
Central API und Console #
Die Central API ist eingeschaltet. CrowdSec meldet erkannte Angreifer-IPs mit Szenario und Zeitpunkt an die CrowdSec SAS (Frankreich) und bezieht dafür die Community-Blockliste. Anfrageinhalte und Nutzerdaten werden nicht übertragen.
Die Console (app.crowdsec.net) ist vorbereitet: Die LAPI meldet sich dort
an, sobald das Secret crowdsec-keys einen ENROLL_KEY enthält. Ohne
den Schlüssel überspringt das Startskript die Anmeldung. Über die Console
fließen zusätzlich Alarme und Metriken ab. Die angemeldete Instanz muss in
der Console einmal angenommen werden.
Secrets #
| Secret | Herkunft | Schlüssel | Zweck |
|---|---|---|---|
crowdsec-keys |
secretGenerator in kustomization.yaml |
postgres-password |
Superuser postgres |
CUSTOM_USER, CUSTOM_DB, CUSTOM_PASSWORD |
Rolle und Datenbank crowdsec |
||
csLapiSecret |
Signierschlüssel der LAPI | ||
registrationToken |
Token für die automatische Registrierung der Agents | ||
ENROLL_KEY |
optional, Anmeldung an der Console | ||
crowdsec-capi-credentials |
angelegt vom Job crowdsec-capi-register-job |
online_api_credentials.yaml |
Zugang zur Central API, nicht im Repository |
Das Chart würde csLapiSecret und registrationToken selbst erzeugen,
per lookup und Zufallswert. Unter Kustomize liefert lookup nichts, jedes
Rendern durch Argo CD ergäbe neue Werte. Deshalb kommen beide aus
crowdsec-keys (secrets.externalSecret in values.yaml).
Angelegt wird crowdsec-keys mit diesem Befehl aus dem Wurzelverzeichnis
des Repositories. Er erzeugt die Werte, ohne sie auszugeben, und setzt
.secretGenerator neu. Für eine bestehende Datenbank nur zusammen mit
einem leeren Datenverzeichnis verwenden, denn PostgreSQL liest die
Passwörter nur beim ersten Start:
1cd "$(git rev-parse --show-toplevel)/apps/crowdsec" \
2 && export ADMIN_PW="$(openssl rand -hex 24)" OWNER_PW="$(openssl rand -hex 24)" \
3 LAPI_SECRET="$(openssl rand -hex 32)" REG_TOKEN="$(openssl rand -hex 24)" \
4 && yq -i '.secretGenerator = [
5 {"name": "crowdsec-keys", "namespace": "crowdsec", "literals": [
6 "postgres-password=" + strenv(ADMIN_PW),
7 "CUSTOM_USER=crowdsec",
8 "CUSTOM_DB=crowdsec",
9 "CUSTOM_PASSWORD=" + strenv(OWNER_PW),
10 "csLapiSecret=" + strenv(LAPI_SECRET),
11 "registrationToken=" + strenv(REG_TOKEN)]}]
12 | (.secretGenerator[].literals[] | select(test("password=|PASSWORD=|csLapiSecret=|registrationToken="))) line_comment = "gitleaks:allow"' kustomization.yaml \
13 && unset ADMIN_PW OWNER_PW LAPI_SECRET REG_TOKEN \
14 && git diff --stat kustomization.yamlDen Enroll-Key der Console (app.crowdsec.net, “Security Engines”,
“Enroll command”) ergänzt dieser Befehl. Er fragt den Schlüssel verdeckt ab
und hängt ihn an crowdsec-keys an:
1cd "$(git rev-parse --show-toplevel)/apps/crowdsec" \
2 && printf 'Enroll key: ' && read -rs ENROLL && echo \
3 && test -n "${ENROLL}" \
4 && export ENROLL \
5 && yq -i '(.secretGenerator[] | select(.name == "crowdsec-keys") | .literals) += ["ENROLL_KEY=" + strenv(ENROLL)]
6 | (.secretGenerator[].literals[] | select(test("^ENROLL_KEY="))) line_comment = "gitleaks:allow"' kustomization.yaml \
7 && unset ENROLL \
8 && git diff --stat kustomization.yamlcrowdsec-capi-credentials gehört nicht zu Argo CD und bleibt beim
Entfernen der App stehen. Wird es gelöscht, registriert der Job die
Instanz beim nächsten Sync neu.
Betrieb #
Alle Befehle laufen in einem LAPI-Pod:
1kubectl -n crowdsec exec deploy/crowdsec-lapi -- cscli alerts list
2kubectl -n crowdsec exec deploy/crowdsec-lapi -- cscli decisions list
3kubectl -n crowdsec exec deploy/crowdsec-lapi -- cscli machines list
4kubectl -n crowdsec exec deploy/crowdsec-lapi -- cscli metricsEine Entscheidung gegen eine eigene Adresse aufheben und die Adresse danach
in zyria-whitelist.yaml aufnehmen:
1kubectl -n crowdsec exec deploy/crowdsec-lapi -- cscli decisions delete --ip 192.0.2.10Ob der Agent die Traefik-Zeilen versteht, zeigt cscli metrics im
Agent-Pod (Abschnitt “Acquisition Metrics”, Spalten “Lines parsed” und
“Lines unparsed”). Das allgemeine Log von Traefik steht als Text im selben
Stream und landet unter “unparsed”.
1kubectl -n crowdsec exec ds/crowdsec-agent -- cscli metrics show acquisition parsersInstallation #
Die App wird von Argo CD über manifests.yaml ausgerollt. Lokal prüfen:
1kubectl kustomize --enable-helm apps/crowdsec