Aller au contenu

Pangolin : exposer CrowdSec Manager derrière le SSO

Foudreclair
Auteur
Foudreclair
Cryptolab est un blog personnel où je documente mes expérimentations techniques : infra, self-hosting, réseau, crypto et projets parfois inutiles, souvent instructifs.
Pangolin - Cet article fait partie d'une série.
Partie 2: Cet article

Dans le premier article sur Pangolin, j’avais volontairement laissé CrowdSec de côté.

Pas parce que CrowdSec n’est pas utile. Au contraire. Mais parce qu’une pile Pangolin doit d’abord être comprise avant d’ajouter des briques de sécurité, des bouncers, des dashboards et des automatisations. Une fois Pangolin stable, la question revient naturellement :

Comment visualiser proprement ce que CrowdSec voit et bloque, sans exposer une interface d’administration sensible sur Internet ?

C’est là que CrowdSec Manager devient intéressant.

L’objectif de ce test est simple :

  • installer CrowdSec Manager à côté de la stack CrowdSec ;
  • ne pas publier son port 8080 sur Internet ;
  • le rendre accessible uniquement via Pangolin ;
  • protéger l’accès avec le SSO Pangolin ;
  • garder les secrets Newt dans Gitea Actions, pas dans Git.

Dashboard CrowdSec Manager

Le problème à éviter
#

La première tentation, avec une interface web Docker, est d’ajouter un mapping de port :

ports:
  - "8080:8080"

Pour un outil comme CrowdSec Manager, c’est une mauvaise idée.

Cette interface donne de la visibilité sur CrowdSec, les décisions, les alertes, les bouncers, les conteneurs et certains éléments de configuration. Dans mon cas, elle a aussi besoin d’accéder au socket Docker :

volumes:
  - /var/run/docker.sock:/var/run/docker.sock

Ce montage est puissant. Très puissant. Il faut donc traiter cette interface comme une surface d’administration, pas comme une simple page web.

Le bon objectif n’est pas :

Internet -> IP_du_serveur:8080

mais plutôt :

Internet -> Pangolin -> SSO -> Newt -> crowdsec-manager:8080

Architecture retenue
#

Dans mon cas, Pangolin tourne sur un VPS, tandis que certains services sont exposés via des sites Newt.

Le point important est celui-ci :

La cible déclarée dans Pangolin doit être joignable depuis le node de sortie choisi.

Autrement dit, crowdsec-manager:8080 ne fonctionne que si le node sélectionné peut résoudre ce nom et joindre ce conteneur. Si le service est sur le même hôte Docker que le site Newt, le plus simple est de placer Newt et CrowdSec Manager dans le même docker-compose.yml, donc dans le même réseau Docker.

C’est ce qui évite d’ouvrir un port sur l’hôte tout en donnant à Pangolin un chemin propre vers le service.

L’architecture finale ressemble donc à ça :

flowchart LR
  A[Navigateur] --> B[Pangolin HTTPS]
  B --> C[SSO Pangolin]
  C --> D[Site Newt]
  D --> E[crowdsec-manager:8080]
  E --> F[CrowdSec]
  E --> G[Docker socket]
  E --> H[Logs Traefik]

Le service n’est pas exposé directement sur l’hôte. Il est seulement disponible pour les conteneurs du même réseau Docker.

Service CrowdSec Manager
#

Dans le docker-compose.yml, CrowdSec Manager est déclaré avec expose, pas avec ports.

crowdsec-manager:
  image: hhftechnology/crowdsec-manager:latest
  container_name: crowdsec-manager
  restart: unless-stopped
  expose:
    - "8080"
  environment:
    - PORT=8080
    - ENVIRONMENT=production
    - LOG_LEVEL=info
    - LOG_FILE=/app/logs/crowdsec-manager.log
    - DOCKER_HOST=unix:///var/run/docker.sock
    - COMPOSE_FILE=/app/docker-compose.yml
    - PANGOLIN_DIR=/app
    - CONFIG_DIR=/app/config
    - DATABASE_PATH=/app/data/settings.db
    - TRAEFIK_DYNAMIC_CONFIG=/app/config/traefik/dynamic_config.yml
    - TRAEFIK_CONTAINER_NAME=traefik
    - TRAEFIK_STATIC_CONFIG=/app/config/traefik/traefik_config.yml
    - TRAEFIK_ACCESS_LOG=/var/log/traefik/access.log
    - TRAEFIK_ERROR_LOG=/var/log/traefik/traefik.log
    - CROWDSEC_ACQUIS_FILE=/app/config/crowdsec/acquis.yaml
    - CROWDSEC_METRICS_URL=http://crowdsec:6060/metrics
    - ALERT_LIST_LIMIT=5000
    - BACKUP_DIR=/app/backups
    - RETENTION_DAYS=60
    - INCLUDE_CROWDSEC=true
  volumes:
    - /var/run/docker.sock:/var/run/docker.sock
    - ./config:/app/config
    - ./docker-compose.yml:/app/docker-compose.yml
    - ./crowdsec-manager/backups:/app/backups
    - ./crowdsec-manager/data:/app/data
    - ./crowdsec-manager/logs:/app/logs
    - ./config/traefik/logs:/var/log/traefik:ro
  depends_on:
    crowdsec:
      condition: service_healthy

La différence importante tient en une ligne :

expose:
  - "8080"

expose documente le port utilisé par le service et le garde dans le périmètre Docker Compose. Il ne publie pas le port sur l’IP du serveur. Depuis l’hôte, un test comme celui-ci doit donc échouer :

curl http://127.0.0.1:8080/api/health/stack

Ce n’est pas un bug. C’est justement ce que l’on veut.

La vraie protection vient de l’absence de mapping ports, du firewall de l’hôte, et du fait que le seul chemin exposé passe par Pangolin et son SSO.

Pour tester depuis le réseau Docker, on peut utiliser un conteneur temporaire :

docker run --rm --network pangolin curlimages/curl:latest \
  http://crowdsec-manager:8080/api/health/stack

Ne pas exposer les métriques CrowdSec
#

CrowdSec expose ses métriques sur 6060. Là aussi, je préfère éviter un mapping hôte inutile.

À éviter :

ports:
  - "6060:6060"

À utiliser :

expose:
  - "6060"

CrowdSec Manager peut toujours joindre :

http://crowdsec:6060/metrics

mais le port n’est pas publié sur Internet.

Ajouter Newt au même compose
#

Comme la cible Pangolin doit être joignable depuis le node de sortie, j’ai ajouté Newt dans le même docker-compose.yml que CrowdSec Manager.

newt:
  image: fosrl/newt:latest
  container_name: newt
  restart: unless-stopped
  environment:
    - PANGOLIN_ENDPOINT=${NEWT_PANGOLIN_ENDPOINT}
    - NEWT_ID=${NEWT_ID}
    - NEWT_SECRET=${NEWT_SECRET}

Dans mon cas, le fichier est généré par Ansible. Les valeurs ne sont donc pas écrites en clair dans le dépôt, mais injectées depuis Gitea Actions.

Variables et secrets Gitea
#

Le dépôt de déploiement utilise une action Gitea pour lancer Ansible. J’ai donc séparé les valeurs publiques et sensibles.

Dans les variables Gitea :

NEWT_PANGOLIN_ENDPOINT=https://pangolin.example.com

Dans les secrets Gitea :

NEWT_ID=...
NEWT_SECRET=...

Ces deux dernières valeurs sont fournies par Pangolin lors de la création du site Newt.

Le workflow transmet ensuite ces valeurs à Ansible :

- name: Run Ansible
  env:
    NEWT_PANGOLIN_ENDPOINT: ${{ vars.NEWT_PANGOLIN_ENDPOINT }}
    NEWT_ID: ${{ secrets.NEWT_ID }}
    NEWT_SECRET: ${{ secrets.NEWT_SECRET }}
  run: |
    ansible-playbook -i inventory/prod.ini playbook-pangolin-upgrade.yml

Côté variables Ansible :

newt_enabled: true
newt_version: "latest"
newt_pangolin_endpoint: "{{ lookup('env', 'NEWT_PANGOLIN_ENDPOINT') }}"
newt_id: "{{ lookup('env', 'NEWT_ID') }}"
newt_secret: "{{ lookup('env', 'NEWT_SECRET') }}"

Et j’ai ajouté une vérification pour éviter de déployer un conteneur Newt incomplet :

- name: Validate Newt secrets
  assert:
    that:
      - newt_pangolin_endpoint | length > 0
      - newt_id | length > 0
      - newt_secret | length > 0
    fail_msg: "Newt is enabled, but NEWT_PANGOLIN_ENDPOINT, NEWT_ID or NEWT_SECRET is missing from the environment."
  when: newt_enabled | bool
  no_log: true

no_log: true évite que les secrets soient affichés dans les logs Ansible.

Ressource Pangolin
#

Une fois Newt connecté, la ressource se crée dans Pangolin comme une ressource HTTPS classique. Le choix du node est essentiel : il faut sélectionner le site Newt qui tourne dans le même environnement que CrowdSec Manager.

Configuration de la cible :

Node de sortie : le site Newt du serveur où tourne CrowdSec Manager
Protocole : http
Host : crowdsec-manager
Port : 8080

Ressource Pangolin CrowdSec Manager protégée par SSO avec cible interne crowdsec-manager:8080

Puis, côté accès :

Authentification Pangolin : activée
Utilisateurs/groupes : administrateurs uniquement

C’est ce point qui donne le résultat recherché :

  • pas de port 8080 publié ;
  • pas d’accès direct depuis Internet ;
  • accès via domaine HTTPS ;
  • passage obligatoire par le SSO Pangolin.

Vérifications utiles
#

Après déploiement, docker ps doit montrer quelque chose de ce type :

crowdsec-manager   8080/tcp
crowdsec           6060/tcp

Il ne doit pas y avoir :

0.0.0.0:8080->8080/tcp
0.0.0.0:6060->6060/tcp

Pour vérifier que CrowdSec Manager répond depuis son propre conteneur :

docker exec crowdsec-manager wget -qO- \
  http://127.0.0.1:8080/api/health/stack

Pour vérifier depuis le réseau Docker :

docker run --rm --network pangolin curlimages/curl:latest \
  http://crowdsec-manager:8080/api/health/stack

Et depuis l’extérieur, le seul chemin valide doit être l’URL Pangolin protégée par SSO :

https://crowdsec.example.com

Si la cible crowdsec-manager:8080 ne répond pas dans Pangolin, le problème vient presque toujours de là : le node sélectionné n’est pas celui qui peut joindre le conteneur.

Ce que l’interface apporte
#

Une fois connecté, CrowdSec Manager donne une vue beaucoup plus lisible de l’activité CrowdSec :

  • décisions actives ;
  • alertes récentes ;
  • bouncers connectés ;
  • état des conteneurs ;
  • historique d’activité ;
  • métriques de remédiation ;
  • scénarios, parsers, collections et composants installés.

Ce n’est pas indispensable pour faire fonctionner CrowdSec. Mais pour comprendre rapidement ce qui se passe, c’est beaucoup plus confortable qu’une suite de commandes cscli lancées à la main.

La valeur principale, pour moi, est la réduction du flou :

Qu’est-ce qui est bloqué, pourquoi, par quel scénario, et est-ce que mes bouncers répondent encore ?

Ce que permet CrowdSec Manager
#

CrowdSec fonctionne très bien en ligne de commande. cscli permet déjà de consulter les décisions, les alertes, les bouncers, les scénarios installés et l’état de l’instance. Le problème n’est pas l’absence d’information. Le problème, c’est la dispersion.

CrowdSec Manager rassemble ces informations dans une interface unique. Pour un homelab ou un petit VPS, ce n’est pas seulement plus joli. C’est surtout plus rapide pour répondre aux questions d’exploitation.

Dashboard général
#

La page d’accueil donne immédiatement les signaux importants :

  • nombre de décisions actives ;
  • volume d’alertes sur les derniers jours ;
  • nombre de bouncers connectés ;
  • état des conteneurs surveillés ;
  • historique des alertes et décisions ;
  • carte des sources détectées.

Ce tableau de bord sert de point d’entrée. Il ne remplace pas l’analyse, mais il indique où regarder. Si le nombre d’alertes grimpe brusquement, si un bouncer disparaît, ou si les décisions actives augmentent sans raison évidente, on le voit tout de suite.

Dans mon cas, l’intérêt est très concret : je peux vérifier en quelques secondes si CrowdSec continue à voir le trafic Traefik et si la remédiation reste active.

Alertes et décisions
#

CrowdSec distingue les alertes et les décisions.

Une alerte correspond à une détection : un comportement a déclenché un scénario. Une décision correspond à une action appliquée : bannissement temporaire, captcha, décision transmise à un bouncer, etc.

CrowdSec Manager rend cette différence plus lisible. On peut inspecter les alertes récentes, suivre les IP concernées, comprendre quels scénarios se déclenchent, puis vérifier si une décision est toujours active.

Analyse des alertes CrowdSec Manager

Ce point est important pour éviter deux erreurs classiques :

  • croire qu’une IP est bloquée alors qu’il n’y a eu qu’une alerte ;
  • supprimer une décision sans comprendre le scénario qui l’a produite.

La bonne démarche reste la même : regarder le contexte, vérifier le scénario, puis seulement agir.

Analyse des décisions CrowdSec Manager avec IPs masquées

Bouncers et remédiation
#

Un CrowdSec sans bouncer, c’est surtout un détecteur. Le bouncer est la brique qui applique la décision côté service exposé.

Dans une stack Pangolin, le bouncer Traefik est central : il permet de faire appliquer les décisions CrowdSec au niveau du reverse proxy. CrowdSec Manager permet de vérifier rapidement que les bouncers sont bien présents et actifs.

C’est le genre de détail que l’on oublie facilement après une mise à jour. Les conteneurs sont verts, le site répond, mais le bouncer peut ne plus appliquer correctement les décisions. Avoir cette vue dans l’interface réduit le risque de s’en rendre compte trop tard.

Bouncers CrowdSec Manager avec adresses internes masquées

Scénarios, collections et parsers
#

CrowdSec repose sur des collections, des parsers, des scénarios et des postoverflows.

En ligne de commande, tout est consultable, mais il faut déjà savoir quoi chercher. L’interface aide à parcourir les composants installés et à comprendre la couverture actuelle :

  • collections liées à Traefik ;
  • scénarios d’attaque web ;
  • règles AppSec ;
  • parsers de logs ;
  • composants de remédiation.

Pour moi, c’est utile surtout après une mise à jour ou un changement de configuration. Je peux vérifier que les collections attendues sont toujours là, que les scénarios ne sont pas absents, et que la pile ne s’est pas dégradée silencieusement.

Logs et diagnostic
#

CrowdSec Manager peut aussi servir de point de lecture pour les logs de la stack.

Dans cette intégration, je lui donne accès aux logs Traefik :

- ./config/traefik/logs:/var/log/traefik:ro

Le montage est en lecture seule côté logs Traefik, ce qui suffit pour l’analyse. L’interface peut alors aider à relier ce que Traefik voit, ce que CrowdSec détecte, et ce que les bouncers appliquent.

Cette corrélation est probablement l’un des vrais intérêts de l’outil. Une alerte isolée n’est pas toujours parlante. Une alerte reliée au trafic reverse proxy devient beaucoup plus exploitable.

Gestion des allowlists
#

Les allowlists sont pratiques, mais dangereuses si elles deviennent un dépotoir.

CrowdSec Manager permet de visualiser et gérer plus confortablement les IP ou plages que l’on veut explicitement autoriser. C’est utile pour :

  • éviter de bloquer son IP d’administration ;
  • autoriser un réseau de supervision ;
  • documenter les exceptions ;
  • réduire les faux positifs répétitifs.

Je garde quand même une règle simple : une allowlist doit être justifiée. Si une IP est autorisée uniquement parce qu’elle a été bloquée un jour sans investigation, c’est une dette de sécurité.

Sauvegardes et changements
#

CrowdSec Manager propose aussi des fonctions autour des sauvegardes et de la configuration. C’est intéressant, car CrowdSec n’est pas seulement un conteneur : c’est une base de décisions, des fichiers de configuration, des collections, des parsers, des scénarios et des intégrations.

Dans ma stack, j’ai prévu des volumes dédiés :

- ./crowdsec-manager/backups:/app/backups
- ./crowdsec-manager/data:/app/data

Cela permet de séparer les données de l’application du reste de la configuration Pangolin. Pour une exploitation propre, je préfère que ces répertoires soient inclus dans la stratégie de sauvegarde de l’hôte.

Mise à jour de la stack
#

CrowdSec Manager peut aider à visualiser les composants et l’état de la stack, mais je garde la mise à jour principale pilotée par Ansible.

Dans mon rôle pangolin_upgrade, les versions sont maintenant variabilisées :

gerbil_version: "1.4.0"
pangolin_version: "ee-1.18.3"
traefik_version: "v3.6.15"
badger_version: "v1.4.0"
crowdsec_traefik_version: "v1.6.0"
crowdsec_version: "latest"
crowdsec_manager_version: "latest"
newt_version: "latest"

L’intérêt est de garder Git comme source de vérité. L’interface aide à exploiter et diagnostiquer ; le rôle Ansible garde le déploiement reproductible.

Workflows utiles au quotidien
#

Après quelques minutes d’utilisation, les workflows qui ressortent sont assez nets.

Vérifier qu’une attaque est bien remédiée
#

Quand une vague d’alertes apparaît :

  1. ouvrir le dashboard ;
  2. regarder les alertes récentes ;
  3. inspecter les décisions actives ;
  4. vérifier le bouncer Traefik ;
  5. consulter les logs associés.

Le but n’est pas seulement de voir que CrowdSec a détecté quelque chose. Le but est de confirmer que la décision est réellement appliquée au bon endroit.

Traiter un faux positif
#

Si une IP légitime se fait bloquer :

  1. vérifier le scénario déclenché ;
  2. regarder les requêtes associées ;
  3. supprimer la décision si nécessaire ;
  4. ajouter une allowlist seulement si le cas est justifié ;
  5. documenter la raison.

CrowdSec Manager rend ce workflow moins pénible, mais il ne doit pas encourager à cliquer trop vite. Un faux positif est une information. Il dit parfois qu’un service, un bot légitime ou une sonde interne se comporte bizarrement.

Vérifier l’état après une mise à jour
#

Après une mise à jour Pangolin, Traefik ou CrowdSec :

  • le dashboard doit répondre ;
  • les conteneurs doivent être vus comme actifs ;
  • le bouncer doit être connecté ;
  • les métriques CrowdSec doivent être accessibles ;
  • les logs Traefik doivent continuer à remonter ;
  • les collections attendues doivent rester installées.

C’est un bon contrôle post-déploiement, plus rapide que de relire tous les fichiers à la main.

État de santé CrowdSec Manager

Ce que CrowdSec Manager ne remplace pas
#

Il faut être clair : CrowdSec Manager ne transforme pas CrowdSec en sécurité automatique magique.

Il ne remplace pas :

  • la compréhension des scénarios ;
  • la lecture des logs bruts quand l’analyse devient sérieuse ;
  • une politique claire d’allowlist ;
  • une stratégie de sauvegarde ;
  • une supervision externe ;
  • la maîtrise de ce qui est exposé par Pangolin.

Il ajoute surtout une couche de lisibilité. Et c’est déjà beaucoup, tant que l’on garde en tête qu’une interface d’administration est elle-même une surface à protéger.

Points de vigilance
#

CrowdSec Manager reste une interface sensible.

Même derrière Pangolin, je garde quelques règles :

  • accès limité à un groupe admin ;
  • 2FA activée côté Pangolin ;
  • pas de publication directe du port 8080 ;
  • pas de publication directe du port 6060 ;
  • sauvegarde des volumes data et backups ;
  • revue régulière des permissions liées au socket Docker.

Le socket Docker mérite une mention spéciale. Monter /var/run/docker.sock dans un conteneur revient à lui donner une capacité d’administration très large sur l’hôte Docker. Ce n’est pas anodin. L’intérêt du SSO Pangolin est justement de réduire l’exposition de cette interface au strict nécessaire.

Conclusion
#

Cette intégration valide bien l’intérêt de Pangolin comme couche d’accès : on peut exposer une interface utile sans ouvrir un port d’administration sur Internet.

Le montage final est simple à raisonner :

CrowdSec Manager reste local au réseau Docker.
Newt le rend joignable depuis Pangolin.
Pangolin applique le HTTPS et le SSO.
L'utilisateur n'accède jamais directement au port 8080.

C’est exactement le type d’usage où Pangolin devient plus qu’un reverse proxy confortable. Il devient une frontière propre entre les outils d’administration et Internet.

CrowdSec Manager ne remplace pas la compréhension de CrowdSec, mais il rend l’exploitation quotidienne plus lisible. Et tant qu’il reste derrière Pangolin, avec une authentification forte et un accès limité, il trouve assez bien sa place dans une stack homelab sérieuse.

Pangolin - Cet article fait partie d'une série.
Partie 2: Cet article

Articles connexes