1. Architecture de sécurité (10 couches)
| # | Couche | Technologie |
|---|---|---|
| 1 | DNS | DNSSEC ECDSA P256-SHA256 |
| 2 | CDN + WAF Cloud | Cloudflare WAF + DDoS + AI Crawl Control |
| 3 | Réseau | CrowdSec nftables Bouncer |
| 4 | Firewall | Netgear PR60X SPI |
| 5 | WAF Local | ModSecurity + OWASP CRS 4.x |
| 6 | IDS/IPS | CrowdSec Agent + scénarios SSH/HTTP |
| 7 | HTTPS | TLS 1.3 + HSTS preload |
| 8 | DNS-TLS | DoH port 853 |
| 9 | Application | Grav CMS + CSP + Secure cookies |
| 10 | Monitoring | BetterStack + CrowdSec poller + Vector |
2. CrowdSec → Cloudflare Sync (crowdsec-cf-sync.py)
Emplacement : /usr/local/bin/crowdsec-cf-sync.py
Service : crowdsec-cf-sync.service
Logs : /var/log/crowdsec/cf-sync.log
Fonctionnalités
- Synchronise les bans CrowdSec actifs → Cloudflare IP Access Rules
- Reporte les IPs bannies → AbuseIPDB
- Escalade récidivistes : 1er ban CrowdSec gère | 2ème → 24h | 3ème+ → 7j
- ModSecurity score ≥ 5 → ban CF immédiat 2h + report AbuseIPDB
- Ban /24 automatique : 2+ IPs du même bloc en 7j → 24h
State files
| Fichier | Rôle |
|---|---|
/var/log/crowdsec/abuseipdb-reported.json |
IPs déjà reportées à AbuseIPDB |
/var/log/crowdsec/recidivists.json |
Compteur de récidive par IP |
/var/log/crowdsec/modsec-banned.json |
Bans ModSec actifs |
/var/log/crowdsec/cidr-banned.json |
Blocs /24 bannis |
Tags Cloudflare
| Tag | Source | Durée |
|---|---|---|
crowdsec-local-ban |
CrowdSec/cscli | Selon escalade |
modsec-ban |
ModSecurity score ≥ 5 | 2h |
crowdsec-cidr-ban |
2+ IPs même /24 | 24h |
Bugs corrigés (avril 2026)
cs_originvsorigindansget_recent_local_bans()- Pagination API REST → remplacé par
cscli decisions list --origin Items→items(minuscule) pour la allowlist CrowdSec
Commandes utiles
# Statut du service
systemctl status crowdsec-cf-sync
# Logs en temps réel
journalctl -fu crowdsec-cf-sync | grep -E "bans|Ajouté|CIDR|ModSec|RÉCIDIVE"
# Redémarrer
systemctl restart crowdsec-cf-sync
# Voir les récidivistes
cat /var/log/crowdsec/recidivists.json | python3 -c "
import json,sys
d=json.load(sys.stdin)
for ip,v in sorted(d.items(), key=lambda x: x[1]['count'], reverse=True):
print(f'{ip:20} count={v[\"count\"]} last={v[\"last_seen\"]}')
"3. Allowlist CrowdSec
Nom : my_allowlist
Synchronisation : Script cloudflare-allowlist-update.py (cron horaire)
Sources : BetterStack IPs + Cloudflare IPv4/IPv6
# Voir le contenu
cscli allowlists inspect my_allowlist
# Nombre d'entrées
cscli allowlists list4. Nginx — CSP (Content Security Policy)
Fichier : /etc/nginx/nginx.conf (map $csp_header)
CSP publique (default)
Migration v2 : nonces dynamiques. Voir De 46 hashes à zéro pour le détail.
Fix httpoxy (avril 2026)
Ajouté dans /etc/nginx/fastcgi.conf :
fastcgi_param HTTP_PROXY "";5. Hugo CMS
Racine : /home/jm/hugo-site/ (VM KVM 192.168.122.69)
Thème : LoveIt
Build : hugo --minify via deploy.sh
Déploiement : rsync vers /var/www/hugo/ (host NUC)
Fichiers importants
| Fichier | Rôle |
|---|---|
hugo.toml |
Config Hugo (baseURL, langues, theme) |
content/<route>/index.{fr,en}.md |
Pages bilingues |
themes/LoveIt/ |
Thème (submodule git) |
static/ |
Assets statiques |
deploy.sh |
Build + rsync + purge CF |
Commandes utiles
# Build local pour test
cd ~/hugo-site && hugo --minify
# Déploiement complet
~/deploy.sh
# Lancer le serveur dev
hugo server -D --bind 0.0.0.06. Cloudflare
Règles de sécurité (ordre)
| # | Nom | Action |
|---|---|---|
| 1 | GOOD BITS | Ignorer (allowlist) |
| 2 | BLOCK ALL BAD | Bloquer |
| 3 | AI Crawl Control | Bloquer (géré automatiquement) |
| 4 | Filter NON EU/US | Challenge |
GOOD BITS — conditions
- BetterStack Uptime Bot
- Catégories bots légitimes (Search Engine, Monitoring, Security…)
- CloudflareBrowserRenderingCrawler
ip.src in $allowed_ip
AI Crawl Control — bots bloqués
GPTBot, ClaudeBot, Bytespider, CCBot, ChatGPT-User, FacebookBot, Meta-ExternalAgent, Perplexity, MistralAI, OAI-SearchBot, AmazonBot…
💡 Note : BingBot passe via GOOD BITS (Search Engine Crawler). 💡 Note : DeepSeekBot bloqué par Filter NON EU/US (hébergé en Chine).
Règles d’accès IP (dynamiques)
Gérées automatiquement par crowdsec-cf-sync.py :
crowdsec-local-ban— bans CrowdSec locauxmodsec-ban— bans ModSecurity 2hcrowdsec-cidr-ban— blocs /24
7. Monitoring & Alertes
BetterStack : status.arleo.eu
Badge footer : https://status.arleo.eu/fr/badge
Cloudflare Analytics token : stocké dans /etc/secrets/ (non publié)
8. Certificats SSL
Gérés automatiquement par Cloudflare (renouvellement auto). Qualys SSL Labs : A+
9. Points de vigilance
- Le script inline Cloudflare challenge (
__CF$cv$params) change à chaque requête → erreur CSP inévitable, non bloquante - La allowlist CrowdSec (
my_allowlist) est la source unique de vérité — synchronisée vers Cloudflare - Les bans
cscli(escalade récidivistes) ne sont PAS visibles dans l’API REST CrowdSec avec?limit=1000— utilisercscli decisions list --origin cscli - Le token Cloudflare et les credentials AbuseIPDB sont stockés hors du repo dans
/etc/secrets/avecchmod 600