CrowdSec protège tous mes serveurs : il lit les journaux, détecte les comportements hostiles (force brute SSH, scans web…) et fait bloquer les adresses fautives par un « bouncer » au niveau du pare-feu. Cinq machines sous Rocky Linux étaient déjà en version 1.8.1, installée depuis le dépôt officiel de CrowdSec. Restait le Raspberry Pi qui fait DNS et DHCP, sous Debian 12, avec la version 1.4.6 des dépôts Debian. Cet article raconte le passage de CrowdSec sur Debian à la 1.8 : pourquoi réinstaller, le piège du postinst, puis la checklist pour vérifier que la machine est réellement protégée.

En un coup d’œil
| Étape | Ce qu’il faut retenir |
|---|---|
| Pourquoi | La 1.4.6 de Debian a des années de retard, et un parc homogène simplifie le rôle Ansible |
| Méthode | Désinstaller puis réinstaller depuis le dépôt officiel : les deux paquets de bouncer entrent en conflit |
| Sauvegarde | /etc/crowdsec et la base SQLite, avec .backup et integrity_check |
| Piège | Sur une installation neuve, désactiver l’assistant laisse CrowdSec sans source de journaux et il refuse de démarrer |
| Correction | Déposer l’acquis.yaml avant le premier apt-get install |
| Vérification | Sept points, de la version jusqu’à la mémoire du Pi |
Pourquoi quitter la version de CrowdSec sur Debian
- 1.4.6 a des années de retard : scénarios, analyseurs et liste communautaire ont beaucoup évolué depuis ;
- un parc homogène : un seul rôle Ansible, une seule version, un seul comportement à connaître ;
- le bouncer Debian (0.0.25) avait besoin de contournements (type de service systemd, fichier de configuration parasite) que la version officielle n’exige plus.
Réinstaller plutôt que mettre à jour
On ne peut pas simplement ajouter le dépôt officiel et lancer apt upgrade pour mettre à jour CrowdSec sur Debian. Le bouncer Debian s’appelle crowdsec-firewall-bouncer, et celui du dépôt officiel crowdsec-firewall-bouncer-nftables : ce sont deux paquets différents qui fournissent les mêmes fichiers, donc ils entrent en conflit. Et avec state: present, Ansible ne remplacerait pas une version déjà installée. La solution propre est de désinstaller, puis de réinstaller depuis le dépôt officiel.
Étape 1 : sauvegarder
systemctl stop crowdsec-firewall-bouncer crowdsec
tar czf /root/backup/crowdsec-pre18.tgz /etc/crowdsec
sqlite3 /var/lib/crowdsec/data/crowdsec.db ".backup /root/backup/crowdsec-pre18.db"
sqlite3 /root/backup/crowdsec-pre18.db "PRAGMA integrity_check;" # doit répondre ok
La base SQLite contient les décisions locales et l’historique des alertes. .backup utilise l’API de sauvegarde de SQLite, ce qui donne une copie cohérente même si un processus y accède encore. Le integrity_check vérifie que la copie est saine avant d’aller plus loin.
Étape 2 : purger, en gardant de quoi revenir en arrière
DEBIAN_FRONTEND=noninteractive apt-get purge -y crowdsec crowdsec-firewall-bouncer
for d in /etc/crowdsec /etc/systemd/system/crowdsec-firewall-bouncer.service.d; do
[ -e "$d" ] && mv "$d" "$d.old-deb"
done
systemctl daemon-reload
Deux remarques. purge supprime aussi les fichiers de configuration du paquet, contrairement à remove : on repart d’une base propre. Et le purge supprime lui-même /var/lib/crowdsec, d’où l’importance de la sauvegarde de la base à l’étape 1.
Pendant cette fenêtre, le Pi n’a plus de protection CrowdSec. Le DNS, lui, continue de fonctionner : il ne dépend pas de CrowdSec. C’est une affaire de quelques minutes, le temps de l’étape suivante, détaillée dans la section ci-dessous… avec un piège inattendu.
Le piège du postinst
Le paquet crowdsec du dépôt officiel lance, à l’installation, un assistant : cscli setup unattended. Il détecte les services présents (sshd, nginx, postfix…) et crée tout seul les sources de journaux dans /etc/crowdsec/acquis.d/setup.*.yaml, puis installe les collections correspondantes. C’est pratique sur une machine gérée à la main, mais gênant quand Ansible gère déjà tout ça : on se retrouve avec deux sources pour les mêmes journaux, donc des événements comptés deux fois.
La variable prévue pour ça… et son effet de bord
CROWDSEC_SETUP_UNATTENDED_DISABLE=true apt-get install -y crowdsec
Cette variable désactive l’assistant. Sur une machine où CrowdSec a déjà une configuration, c’est parfait. Mais sur une installation neuve, sans assistant, CrowdSec n’a aucune source de journaux. Or il refuse de démarrer sans au moins une source :
FATAL crowdsec init: while loading acquisition config: no datasource enabled
La suite est une réaction en chaîne :
- le postinst du paquet essaie de démarrer le service, qui échoue, donc le postinst sort en erreur ;
- dpkg laisse le paquet « à moitié configuré » (
iFdansdpkg -l) ; - à l’
apt-get installsuivant (le bouncer, par exemple), dpkg essaie de finir la configuration en attente et relance le postinst de crowdsec. Cette fois, la variable n’est plus dans l’environnement, et l’assistant s’exécute.
Résultat : exactement ce qu’on voulait éviter. Des fichiers setup.*.yaml sont créés, des collections inutiles installées (auditd, une liste blanche « bons robots »…), et en prime le bouncer échoue à son installation, puisque l’API locale de CrowdSec n’était pas encore démarrée au moment où il s’est configuré.
La correction
Il suffit que CrowdSec trouve une source de journaux dès son premier démarrage. Le rôle Ansible dépose donc sa propre configuration avant d’installer le paquet, uniquement si CrowdSec n’est pas encore présent :
- name: Check whether CrowdSec is already installed
ansible.builtin.stat:
path: /usr/bin/crowdsec
register: _crowdsec_binary
- name: Seed acquisition config before the first install
when: not _crowdsec_binary.stat.exists
ansible.builtin.template:
src: acquis.yaml.j2 # auth.log + syslog sur Debian
dest: /etc/crowdsec/acquis.yaml
Avec un acquis.yaml déjà en place, le premier démarrage réussit, le postinst se termine normalement, et l’assistant reste désactivé.
Nettoyer si c’est déjà arrivé
dpkg --configure -a # finir les configurations en attente
mkdir -p /root/backup/setup-leftovers
mv /etc/crowdsec/acquis.d/setup.*.yaml /root/backup/setup-leftovers/
cscli collections remove crowdsecurity/auditd crowdsecurity/whitelist-good-actors
systemctl restart crowdsec crowdsec-firewall-bouncer
Un dernier piège, côté Ansible : si un run échoue en cours de route, les handlers déjà notifiés (« redémarrer crowdsec ») ne s’exécutent pas. Le run suivant voit des fichiers déjà à jour et ne notifie plus rien. Les services tournent alors avec l’ancienne configuration. Après une correction, redémarrez-les vous-même.
Vérifier que ça protège vraiment
Deux services « active » ne prouvent pas grand-chose. CrowdSec peut tourner sans lire le bon journal, et le bouncer peut tourner sans rien bloquer. Voici la checklist que j’applique après chaque installation ou mise à jour, avec ce que chaque vérification démontre.
1. Les versions et les services
cscli version | head -1 # version: v1.8.1…
systemctl is-active crowdsec crowdsec-firewall-bouncer crowdsec-nft-resync.timer
2. Le pare-feu : un seul hook, au bon endroit
nft list ruleset | grep -E "^table|hook"
# table ip crowdsec
# type filter hook input priority filter; policy accept;
# table ip6 crowdsec6
# type filter hook input priority filter; policy accept;
Le bouncer doit filtrer le trafic entrant (hook input) en IPv4 et en IPv6. Une chaîne forward ou output en trop serait un reste d’ancienne configuration. Oublier l’IPv6, c’est laisser une porte grande ouverte.
3. Un seul bouncer enregistré, le bon
cscli bouncers list
# crowdsec-firewall-bouncer 127.0.0.1 ✔️ …
Le paquet du bouncer s’enregistre tout seul sous un nom aléatoire (cs-firewall-bouncer-<horodatage>), et l’installation Ansible ajoute le sien. Il ne doit en rester qu’un, sinon on ne sait plus lequel est vraiment utilisé.
4. Les journaux sont lus et compris
cscli metrics show acquisition # auth.log et syslog avec des lignes lues
cscli explain --type syslog \
--log "Oct 23 10:00:00 pi sshd[1]: Invalid user admin from 203.0.113.9 port 4242"
cscli explain fait passer une ligne de journal dans toute la chaîne d’analyse, et montre quels analyseurs la reconnaissent et quels scénarios elle alimente. Si aucun scénario ssh n’apparaît, la détection de force brute SSH ne fonctionnera jamais, quel que soit l’état des services.
5. La liste communautaire
cscli capi status # « You can successfully interact with Central API »
cscli decisions list -a -o raw | tail -n +2 | wc -l
Juste après une installation neuve, la liste est vide : une machine nouvellement enregistrée met jusqu’à deux heures à recevoir sa première liste de blocage communautaire. Le lendemain, le Pi bloquait plus de 15 000 adresses, contre 3 600 avec l’ancienne version.
6. Les ensembles nftables correspondent aux décisions
Le bouncer de pare-feu a longtemps eu un bug qui pouvait laisser les ensembles nftables se désynchroniser des décisions. Un petit timer de resynchronisation compare les deux et rajoute ce qui manque. Son journal doit indiquer still_missing=0 :
journalctl -u crowdsec-nft-resync --since -1h | grep still_missing | tail -2
# ipv4: active=15301 set=15301 … still_missing=0
7. La mémoire, sur un petit Pi
Sur un Raspberry Pi qui fait aussi DNS, je vérifie que CrowdSec n’affame pas le reste : free -m, la mémoire résidente de chaque processus et l’usage du swap. Après une journée, CrowdSec occupait environ 100 Mo, et il restait 350 Mo de libres. Si ça devenait serré, désactiver le support grok de RE2 dans feature.yaml réduit nettement l’empreinte.
Une fois ces sept points au vert, on peut dire que CrowdSec sur Debian protège réellement la machine, et pas seulement que des services tournent.
Ce que j’en retiens
- Sauvegardez avant de purger : le purge supprime
/var/lib/crowdsec, et la copie SQLite doit passerintegrity_check; - Fournissez une source de journaux dès l’installation si vous désactivez l’assistant, sinon CrowdSec ne démarre pas et dpkg relance le postinst sans la variable ;
- Après un run Ansible en échec, redémarrez vous-même les services : les handlers notifiés n’ont pas tourné ;
- Deux services « active » ne prouvent rien : contrôlez le hook nftables (IPv4 et IPv6), le bouncer unique,
cscli explain, la liste communautaire etstill_missing=0; - Sur un petit Pi, surveillez la mémoire de CrowdSec sur Debian après une journée de fonctionnement.
Laisser un commentaire