feat(crowdsec): arm the bouncer everywhere, drop the per-host override #769

Merged
k.renner merged 1 commits from arm-crowdsec-proxy-1 into master 2026-09-02 18:57:10 +00:00
Member

proxy-2 setzt seit 14:21:54 ohne Zwischenfall durch. Der Rollen-Default wandert deshalb auf nftables und die host_vars-Datei fällt weg, statt für proxy-1 dupliziert zu werden. proxy-2s gerenderte Konfiguration ändert sich dadurch nicht — es startet also nicht neu, nur proxy-1 tut es.

Die Staffelung hat funktioniert

Ablesbar im Deploy-Log:

proxy-1: deployed in mode "dry-run"
proxy-2: deployed in mode "nftables"

Und nur proxy-2 hat neu gestartet, was sich als 1.887.882-Byte-Vollabzug von seiner Adresse allein zeigte.

Zustellung im scharfen Modus getestet

Mit einer Decision auf 192.0.2.1 (TEST-NET-1, RFC 5737 — kein echter Traffic betroffen):

Zeit Ereignis Beide Hosts
14:22:41 Ban gesetzt —
14:22:44 / :45 205 Byte Delta
14:23:33 gelöscht —
14:23:34 / :35 203 Byte Delta

Warum jetzt der zweite Host, statt länger zu warten

Was weiterhin nicht bewiesen ist: dass tatsächlich ein Paket fällt. Und die Messung dazu spricht dafür, den Rollout abzuschließen statt zu warten.

Requests von gebannten Adressen, die Traefik erreichten:

14:02   1
14:07   3
14:08  22        ← ein einzelner Burst
14:18   1
nach 14:21:54 (scharf):  0

Nach dem Scharfschalten keiner mehr. Aber 25 der 27 kamen in einem Burst davor, und proxy-1 lässt weiterhin alles durch — bei diesem Volumen ist das mit funktionierender Durchsetzung vereinbar, nicht ihr Beweis. Für den Nachweis einer 50-%-Reduktion ist die Stichprobe zu klein.

Mit beiden Hosts scharf wird die Aussage dagegen falsifizierbar: kein Request einer Adresse aus dem Decision-Set darf Traefik noch erreichen. Ein einziger wäre ein Beweis für einen Fehler — und das lässt sich fortlaufend gegen die Logs prüfen, ohne Host-Zugriff.

Rückweg

dry-run bleibt pro Host über inventory/host_vars verfügbar. Das ist auch, was ein neu hinzugefügter Proxy bekommen sollte, bevor er durchsetzt — der Kommentar in defaults/main.yml sagt das jetzt so, statt dry-run als globalen Default zu begründen.

proxy-2 setzt seit 14:21:54 ohne Zwischenfall durch. Der Rollen-Default wandert deshalb auf `nftables` und die `host_vars`-Datei fällt weg, statt für proxy-1 dupliziert zu werden. proxy-2s gerenderte Konfiguration ändert sich dadurch nicht — es startet also nicht neu, nur proxy-1 tut es. ## Die Staffelung hat funktioniert Ablesbar im Deploy-Log: proxy-1: deployed in mode "dry-run" proxy-2: deployed in mode "nftables" Und nur proxy-2 hat neu gestartet, was sich als 1.887.882-Byte-Vollabzug **von seiner Adresse allein** zeigte. ## Zustellung im scharfen Modus getestet Mit einer Decision auf `192.0.2.1` (TEST-NET-1, RFC 5737 — kein echter Traffic betroffen): | Zeit | Ereignis | Beide Hosts | |---|---|---| | 14:22:41 | Ban gesetzt | — | | 14:22:44 / :45 | | **205 Byte** Delta | | 14:23:33 | gelöscht | — | | 14:23:34 / :35 | | **203 Byte** Delta | ## Warum jetzt der zweite Host, statt länger zu warten Was weiterhin **nicht** bewiesen ist: dass tatsächlich ein Paket fällt. Und die Messung dazu spricht dafür, den Rollout abzuschließen statt zu warten. Requests von gebannten Adressen, die Traefik erreichten: 14:02 1 14:07 3 14:08 22 ← ein einzelner Burst 14:18 1 nach 14:21:54 (scharf): 0 Nach dem Scharfschalten keiner mehr. Aber 25 der 27 kamen in einem Burst davor, und proxy-1 lässt weiterhin alles durch — bei diesem Volumen ist das mit funktionierender Durchsetzung **vereinbar**, nicht ihr Beweis. Für den Nachweis einer 50-%-Reduktion ist die Stichprobe zu klein. Mit beiden Hosts scharf wird die Aussage dagegen falsifizierbar: **kein** Request einer Adresse aus dem Decision-Set darf Traefik noch erreichen. Ein einziger wäre ein Beweis für einen Fehler — und das lässt sich fortlaufend gegen die Logs prüfen, ohne Host-Zugriff. ## Rückweg `dry-run` bleibt pro Host über `inventory/host_vars` verfügbar. Das ist auch, was ein neu hinzugefügter Proxy bekommen sollte, bevor er durchsetzt — der Kommentar in `defaults/main.yml` sagt das jetzt so, statt `dry-run` als globalen Default zu begründen.
claude-bot added 1 commit 2026-09-02 14:28:54 +00:00
feat(crowdsec): arm the bouncer everywhere, drop the per-host override
ci/woodpecker/pr/pr-review Pipeline was successful
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
b96260cef2
proxy-2 has been enforcing since 14:21:54 without incident, so the role
default moves to nftables and the host_vars override goes away rather than
being duplicated for proxy-1. proxy-2's rendered config is unchanged by this,
so it will not restart; only proxy-1 does.

The staged rollout did its job and can be read off the deploy log:

  proxy-1: deployed in mode "dry-run"
  proxy-2: deployed in mode "nftables"

and only proxy-2 restarted, which showed up as a 1,887,882-byte startup pull
from its address alone.

The delivery path was tested in enforcing mode with a decision on 192.0.2.1
(TEST-NET-1): both hosts had the ban 3s later as a 205-byte delta, and the
revocation as a 203-byte delta 1-2s after deletion.

What is still not proven is that a packet is actually dropped, and the
measurement for that argues for finishing the rollout rather than waiting.
Requests from banned addresses reaching Traefik stopped after proxy-2 armed —
1 at 14:02, 3 at 14:07, 22 at 14:08, 1 at 14:18, none after — but 25 of those
27 arrived in a single burst beforehand, so at this volume that is consistent
with enforcement rather than evidence of it. With both hosts armed the claim
becomes falsifiable instead: no request from an address in the decision set
should reach Traefik at all, and a single one would prove otherwise.

dry-run remains available per host through inventory/host_vars, which is what
a newly added proxy should get before it enforces.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
review-bot left a comment
Member

🤖 Automated review — model CLI default (complexity: complex), commit b96260cef24086d53540e9bd0bbef33d37f806ba.

Advisory review by the review-bot pipeline. It never approves; a human merges. Push new commits to get a fresh review.


Summary

Flips the netbird_proxy group's default crowdsec_bouncer_mode from dry-run to nftables in ansible/roles/crowdsec-edge-bouncer/defaults/main.yml, and drops the now-redundant inventory/host_vars/proxy-2.renner.uno.yml override that previously pinned proxy-2 to the same value. Net effect: proxy-2's rendered config is unchanged (no restart), proxy-1 picks up enforcement for the first time. I checked the reasoning against the actual role/template/handler logic and the referenced whitelist, and it holds up — no blocking issues.

🟡 Suggestions

  • ansible/plays/install-netbird-proxy.yml:29-31 — the comment above the crowdsec-edge-bouncer role entry still reads "Deployed in dry-run: it logs what it would block and creates no nftables rules until crowdsec_bouncer_mode is flipped per host." That description is now stale: the role default is nftables (enforcing) as of this PR, and the "flip per host" rollout mechanism this comment describes no longer exists (rollback, not rollout, is now what inventory/host_vars is for, per the new comment in defaults/main.yml:35-38). Worth updating alongside the defaults file so a future reader of the play doesn't get the opposite impression of what gets deployed.

Tests

No automated tests apply here (Ansible role/inventory change, no test suite in this repo for that). The PR body substitutes operational evidence instead: staged rollout logs showing only proxy-1 restarted, and a live delivery test against an RFC 5737 test address (192.0.2.1) showing consistent traffic deltas across ban/unban. I independently verified the two structural safety claims the body leans on:

  • ansible/inventory/host_vars/proxy-2.renner.uno.yml is not referenced anywhere else in the repo, so deleting it is safe, and since its value (nftables) now matches the new role default, proxy-2's rendered config is byte-for-byte unchanged — consistent with the "only proxy-1 restarts" claim.
  • The capi_whitelists.yaml ConfigMap in kubernetes/infrastructure/crowdsec/helmrelease.yaml:59-67 does carry proxy-1, proxy-2, and netbird.renner.uno's addresses, backing the new comment's claim that this exists to protect the proxies' own outbound control connection from the no-conntrack INPUT hook.

That's an adequate substitute for a test suite given the nature of this change (a live firewall enforcement flip on two internet-facing hosts) — it can't reasonably be unit tested.

Recommendation

Looks reasonable — no blocking issues; the comment above is optional.

🤖 **Automated review** — model `CLI default` (complexity: complex), commit `b96260cef24086d53540e9bd0bbef33d37f806ba`. > Advisory review by the `review-bot` pipeline. It never approves; a human merges. Push new commits to get a fresh review. --- ## Summary Flips the `netbird_proxy` group's default `crowdsec_bouncer_mode` from `dry-run` to `nftables` in `ansible/roles/crowdsec-edge-bouncer/defaults/main.yml`, and drops the now-redundant `inventory/host_vars/proxy-2.renner.uno.yml` override that previously pinned proxy-2 to the same value. Net effect: proxy-2's rendered config is unchanged (no restart), proxy-1 picks up enforcement for the first time. I checked the reasoning against the actual role/template/handler logic and the referenced whitelist, and it holds up — no blocking issues. ## 🟡 Suggestions - `ansible/plays/install-netbird-proxy.yml:29-31` — the comment above the `crowdsec-edge-bouncer` role entry still reads "Deployed in dry-run: it logs what it would block and creates no nftables rules until crowdsec_bouncer_mode is flipped per host." That description is now stale: the role default is `nftables` (enforcing) as of this PR, and the "flip per host" rollout mechanism this comment describes no longer exists (rollback, not rollout, is now what `inventory/host_vars` is for, per the new comment in `defaults/main.yml:35-38`). Worth updating alongside the defaults file so a future reader of the play doesn't get the opposite impression of what gets deployed. ## Tests No automated tests apply here (Ansible role/inventory change, no test suite in this repo for that). The PR body substitutes operational evidence instead: staged rollout logs showing only proxy-1 restarted, and a live delivery test against an RFC 5737 test address (192.0.2.1) showing consistent traffic deltas across ban/unban. I independently verified the two structural safety claims the body leans on: - `ansible/inventory/host_vars/proxy-2.renner.uno.yml` is not referenced anywhere else in the repo, so deleting it is safe, and since its value (`nftables`) now matches the new role default, proxy-2's rendered config is byte-for-byte unchanged — consistent with the "only proxy-1 restarts" claim. - The `capi_whitelists.yaml` ConfigMap in `kubernetes/infrastructure/crowdsec/helmrelease.yaml:59-67` does carry proxy-1, proxy-2, and `netbird.renner.uno`'s addresses, backing the new comment's claim that this exists to protect the proxies' own outbound control connection from the no-conntrack INPUT hook. That's an adequate substitute for a test suite given the nature of this change (a live firewall enforcement flip on two internet-facing hosts) — it can't reasonably be unit tested. ## Recommendation Looks reasonable — no blocking issues; the comment above is optional. <!-- pr-review:sha=b96260cef24086d53540e9bd0bbef33d37f806ba -->
k.renner merged commit 1951497175 into master 2026-09-02 18:57:10 +00:00
Sign in to join this conversation.