~/blog/fr/crowdsec-bouncer-locked-me-out
CrowdSec m'a bloqué l'accès à mon propre serveur

CrowdSec est l’une des meilleures choses qui soient arrivées au self-hosting. Il lit vos journaux, reconnaît les motifs d’attaque et bloque les récidivistes au niveau du pare-feu — et la blocklist communautaire fait qu’une attaque contre le serveur de quelqu’un d’autre protège le vôtre.
C’est aussi un système de prévention d’intrusion doté de l’autorité de bloquer n’importe quelle IP, et rien dans sa conception ne dit que votre IP est spéciale. Voici comment il m’a bloqué l’accès à mon propre serveur, et ce que j’ai changé pour que cela ne puisse plus se reproduire.
Ce qui s’est passé
D’un seul coup : les sessions SSH sont mortes en pleine commande, l’interface web a cessé de répondre, et chaque nouvelle connexion est partie en timeout. Pas en refus — en timeout, ce qui est la signature d’un filtre de paquets sans règle pour vous répondre.
Le homelab joint son VPS depuis une seule IP publique. Tout mon trafic — SSH, HTTP, le scraper de surveillance — apparaît à ce serveur comme une seule adresse. Quand un scénario CrowdSec sur le VPS a décidé que cette adresse était un attaquant, le bouncer du pare-feu a tout bloqué depuis elle au niveau du noyau. SSH n’échappe pas à un filtre de paquets. Rien d’autre non plus.
Les scénarios qui déclenchent cela sont ordinaires :
crowdsecurity/ssh-bf brute-force SSH
crowdsecurity/http-backdoors-attempts probing for known backdoors
crowdsecurity/http-crawl-non_statics aggressive crawling
crowdsecurity/http-sensitive-files hunting for .env, .git
crowdsecurity/http-cve-2021-41773 a specific exploit attempt
Ajoutez un script de surveillance qui retente une vérification défaillante toutes les 30 secondes, ou quelques connexions échouées après une rotation de clés, et vous avez écrit le motif qui déclenche l’un de ces scénarios. Le système a fait exactement ce pour quoi il était configuré.
Comment revenir
Deux voies, et il vaut la peine de connaître les deux avant d’en avoir besoin.
Depuis une IP qui n’est pas bannie. Un téléphone en données mobiles, un autre serveur, n’importe quoi hors de la plage bloquée. Connectez-vous en SSH, supprimez la décision et ajoutez la whitelist. C’est le chemin facile, et la raison de garder un accès hors bande.
Depuis la console de l’hôte. Quand aucune IP non bloquée n’est disponible, un redémarrage matériel depuis la console du fournisseur d’hébergement fonctionne, parce que les règles du bouncer vivent dans la mémoire du noyau et ne survivent pas à un reboot. La machine démarre avec un ensemble de règles vide — puis le bouncer démarre environ dix secondes plus tard et récupère les décisions existantes depuis l’API, vous bannissant à nouveau. La fenêtre est donc courte et délibérée : boot, connexion immédiate, ajout de la règle de whitelist.
# la règle accept doit être posée avant que la décision ne se propage à nouveau
nft insert rule ip crowdsec crowdsec-input ip saddr { 10.99.99.0/24, 203.0.113.10 } accept
nft list ruleset > /etc/nftables.conf
Ensuite, supprimez la décision elle-même, sinon elle revient au prochain rafraîchissement :
cscli decisions delete -i 203.0.113.10
Supprimer le ban sans mettre en whitelist signifie simplement que cela se reproduira au prochain événement correspondant. La whitelist est le correctif ; la suppression n’est que du nettoyage.
Deux couches, dont une seule est durable
C’est la partie que j’ai ratée la première fois, et celle qui vaut la peine d’être retenue.
Couche 1 — la whitelist du parser, sur l’instance CrowdSec qui prend les décisions. Ajoutez vos propres adresses à la whitelist d’enrichissement pour que la décision ne soit jamais créée :
# /etc/crowdsec/parsers/s02-enrich/whitelists.yaml
name: crowdsecurity/whitelists
whitelist:
- "203.0.113.10/32" # l'IP publique du labo
- "10.99.99.0/24" # la plage interne
Une IP en whitelist n’est pas évaluée, donc pas d’alerte, pas de décision, rien à appliquer. C’est la couche durable — elle vit dans la configuration propre à CrowdSec et rien ne la recrée dans votre dos.
Couche 2 — une règle accept dans la chaîne de pare-feu du bouncer. Une seconde chance pour le trafic que la première couche aurait manqué :
nft insert rule ip crowdsec crowdsec-input ip saddr { 10.99.99.0/24, 203.0.113.10 } accept
nft list ruleset > /etc/nftables.conf
systemctl enable nftables
Utile, et pas durable. Le bouncer vide et recrée ses propres tables à chaque redémarrage ou mise à jour, ce qui supprime une règle insérée manuellement. Sauvegarder l’ensemble de règles dans /etc/nftables.conf ne vous sauve pas non plus, parce que le bouncer reconstruit sa table de zéro après le boot. Après n’importe quel redémarrage du bouncer, la règle accept doit être réinsérée.
J’avais la seconde couche et je croyais que c’était la protection. C’est un bonus.
Quatre pièges qui coûtent du temps réel
Le nom de la chaîne a changé entre les versions du bouncer. Dans les anciennes versions, la chaîne était crowdsec ; à partir de la v0.0.34, c’est crowdsec-input. Une commande stockée issue d’un article écrit pour l’ancienne version insère une règle dans une chaîne qui n’existe plus, et nft ne signale rien — la règle est simplement absente. Confirmez le nom de la chaîne sur votre propre système avant de faire confiance à n’importe quel extrait, y compris celui-ci :
nft list tables
nft list table ip crowdsec
Le shell fish casse la syntaxe des ensembles nft. { 10.99.99.0/24, 203.0.113.10 } est une expansion d’accolades pour fish, qui retire les accolades et transmet à nft quelque chose d’invalide. Exécutez-le via bash -c — et, plus généralement, vérifiez quel shell interprète réellement vos commandes quand quelque chose « marche dans le terminal » mais pas dans un script.
Le nom de l’unité est obsolète. L’unité systemd du bouncer est crowdsec-firewall-bouncer.service. Une partie de la documentation fait référence à crowdsec-firewall-bouncer-nftables.service, qui n’existe pas sur les paquets actuels — donc systemctl is-active sur ce nom rapporte inactive alors que le bouncer tourne et bloque. Avant de conclure qu’un service est arrêté, trouvez la vraie unité : systemctl list-units | grep crowdsec.
Le blocage est invisible quand c’est votre propre trafic. Rien dans les journaux du serveur ne dit « votre IP est bannie » — les paquets sont supprimés avant que quoi que ce soit puisse les journaliser. Si l’accès meurt d’un seul coup et que les connexions partent en timeout plutôt que d’être refusées, pensez d’abord au filtre de paquets.
Ce que je ferais différemment
Mettez vos propres adresses de sortie en whitelist dès le premier jour, avant d’en avoir besoin. Le mode de défaillance d’une whitelist mal configurée est une alerte que vous ignorez ; le mode de défaillance d’une whitelist absente est la perte d’accès à la machine qui vous permettrait de la corriger.
Gardez un chemin hors bande — une console, une seconde IP, des données mobiles. Tout système capable de bloquer votre unique route d’entrée finira par user de ce pouvoir, et « finira » tend à signifier un samedi.
Et sachez quelle couche persiste. Une règle de pare-feu et un moteur de décisions sont deux types de protection différents, et une seule des deux survit à un redémarrage de service.