// projet phare — homelab

SOC Dashboard

MONITORING SÉCURITÉ TEMPS RÉEL  ·  KILL CHAIN  ·  IA INTÉGRÉE

28 tuiles en production Refresh 60s CrowdSec · fail2ban nginx · GeoIP2 · CVE NVD v3.40 · Python · JavaScript LAN uniquement — solution locale
◉ PÉRIMÈTRE — Solution homelab déployée sur réseau local (LAN). Le dashboard SOC, le reverse proxy et l'assistant IA fonctionnent exclusivement dans un environnement privé et maîtrisé. Cette documentation présente la méthodologie et les briques techniques mises en œuvre — sans exposer de données de configuration ni de topologie réseau réelle.
28
TUILES EN PROD
60s
CYCLE REFRESH
21
MOIS CVE INDEXÉS
SYNC CVE / JOUR
8
CRONS ACTIFS
182
RÈGLES APPSEC WAF
4
SOURCES JSON
// chronologie de construction

$ git log --oneline --reverse

Le SOC Dashboard est le résultat d'une construction itérative sur plusieurs mois. Chaque étape apporte une couche supplémentaire de visibilité, de détection ou d'automatisation.

1
REVERSE PROXY nginx + SSL
Mise en place du reverse proxy nginx avec terminaison TLS (certbot Let's Encrypt). Vhosts séparés par domaine. Headers de sécurité : X-Frame-Options, X-Content-Type-Options, HSTS, Referrer-Policy. Configuration access_log JSON pour parsing structuré.
2
CROWDSEC WAF + BOUNCER NFTABLES
Installation CrowdSec avec bouncer nftables pour blocage kernel-space. Scénarios communautaires activés. AppSec collection nginx (182 règles WAF niveau applicatif). Exposition API locale pour requêtes programmatiques depuis monitoring_gen.py.
3
monitoring_gen.py — COLLECTE LOGS nginx
Script Python de collecte et agrégation. Parse les access.log + access.log.1 pour couverture cross-midnight. Interroge CrowdSec API, fail2ban socket, stats système. Génère monitoring.json toutes les 60 secondes via cron.
4
DASHBOARD HTML v1 — PREMIÈRES TUILES SYSTÈME
Premier dashboard HTML consommant monitoring.json. Tuiles CPU, RAM, disque, réseau. Fetch polling toutes les 60s. Architecture fichier unique sans dépendance externe — déployable par simple scp.
5
CYBER KILL CHAIN + GEOIP CARTOGRAPHIE CANVAS
Classification des menaces en 5 stages (Recon, Scan, Exploit, Brute, Delivery) avec scoring normalisé 0-100. Cartographie monde canvas avec arcs d'attaque géolocalisés via MaxMind GeoIP2. Heatmap 24h canvas.
6
CVE NVD — 21 MOIS D'HISTORIQUE INDEXÉS
Intégration de l'API NVD/NIST. Synchronisation 3 fois par jour via cron-cve-fetch.sh. Index local ~21 mois de CVE. Moteur de corrélation entre CVE récentes et signatures CrowdSec détectées en production.
7
INTÉGRATION JARVIS IA — AUTO-ENGINE, TTS, ACTIONS PROACTIVES
Connexion au moteur IA JARVIS (Flask localhost). Auto-engine surveille les deltas de trafic et déclenche des analyses LLM. Alertes vocales TTS si niveau ÉLEVÉ ou CRITIQUE. Routes SOC : ban-ip, unban-ip, restart-service via CrowdSec cscli.
8
RAPPORT SOC QUOTIDIEN + ALERTES EMAIL + SNAPSHOTS UFW
soc-daily-report.py génère un rapport complet chaque matin à 08h00 UTC : trafic 24h, CrowdSec, Kill Chain, top attaquants, état services, SSL, système. Snapshots UFW horodatés pour historique posture sécurité. Déclenchement manuel depuis le dashboard via raccourci [E].
// pipeline de données

$ cat pipeline.json

Le dashboard SOC est un fichier HTML unique (~35 000 lignes) qui consomme des fichiers JSON générés côté serveur. Le pipeline collecte les données de plusieurs sources (logs nginx, CrowdSec, fail2ban, système, CVE, Windows, Proxmox) et les centralise dans un JSON de monitoring actualisé toutes les 60 secondes.

nginx access.log
requêtes · erreurs · volumes
CrowdSec
décisions · bans actifs
fail2ban
jails · IPs bannies
Système
CPU · RAM · disque · réseau
monitoring_gen.py
agrégation · normalisation · cron 60s
monitoring.json
windows-disk.json
machine locale → VM
proto-live.json
protocoles 15s
◈ SOC DASHBOARD
monitoring-index.html · fetch JSON 60s
28 tuiles · Kill Chain · GeoIP
JARVIS IA
analyse LLM · TTS alertes
ban-ip · restart-service
──▶
CrowdSec
actions proactives
// sources complémentaires
01
CVE NVD
API NVD/NIST
3x/jour via cron
21 mois indexés
02
GeoIP2
Géolocalisation IPs
Cartographie monde
Arcs d'attaque
03
Threat Intel
Flux menaces externes
threat-fetch.sh
Synchronisation auto
04
Proxmox
CPU/RAM nœud
VMs actives
État stockage
05
Windows
windows-disk-report.ps1
Disques · GPU · CPU
Sauvegardes VMs
06
SSL
Certificats TLS
Jours restants
Statut par domaine
// classification des menaces

$ cat kill-chain.json

Chaque requête entrante est analysée et classifiée selon une adaptation de la Cyber Kill Chain de Lockheed Martin. Le score global est normalisé de 0 à 100 et détermine le niveau de menace affiché dans le dashboard. La classification est effectuée par monitoring_gen.py à chaque cycle et intégrée dans monitoring.json.

STAGE 1
RECON
robots.txt
.env probe
/.git access
sitemap.xml
UA crawler
+5 pts / signal
STAGE 2
SCAN
/wp-admin
/cgi-bin
/.php inexistant
masscan UA
path enum
+10 pts / signal
STAGE 3
EXPLOIT
CVE paths
path traversal
RCE probes
.env upload
xmlrpc abuse
+20 pts / signal
STAGE 4
BRUTE
401 répétés
même IP
Auth flooding
Login probing
>= 5 / cycle
+15 pts / signal
STAGE 5
DELIVERY
POST suspects
SQLi patterns
XSS payloads
LFI/RFI
shell upload
+25 pts / signal
// seuils de score normalisé (0-100)
SCORE 0 – 30
NOMINAL
──▶
SCORE 30 – 60
MODÉRÉ
──▶
SCORE 60 – 80
ÉLEVÉ
──▶
SCORE 80 – 100
CRITIQUE
// logique de détection — extrait
Stage Signaux détectés Score ajouté Action CrowdSec
RECON robots.txt, .env probe, /.git, sitemap, crawler UA +5 par signal Tag comportemental, surveillance accrue
SCAN /wp-admin, /cgi-bin, /.php inexistant, masscan UA +10 par signal Scénario http-probing déclenché
EXPLOIT CVE paths (traversal, RCE), .env upload, xmlrpc +20 par signal Ban immédiat via bouncer nftables
BRUTE 401 répétés >= 5 sur même IP en un cycle +15 par IP Jail fail2ban http-auth activée
DELIVERY POST payload suspect, SQLi, XSS, LFI/RFI patterns +25 par signal Ban immédiat + alerte JARVIS TTS
// moteur de collecte — monitoring_gen.py

$ python3 monitoring_gen.py --explain

monitoring_gen.py est le coeur du pipeline. Ce script Python (~73 000 lignes commentées) collecte, normalise et agrège les données de toutes les sources en un seul fichier monitoring.json. Il est déclenché toutes les 5 minutes par cron via monitoring.sh (wrapper de lancement).

// sources parsées
SRC 01
Logs nginx
access.log + access.log.1
Couverture 24h cross-midnight
Regex structuré JSON
SRC 02
CrowdSec API
API locale port 8080
Décisions actives
Scénarios déclenchés
SRC 03
fail2ban
Socket Unix local
Jails actives
Compteur IPs/jail
SRC 04
Proxmox API
REST API v2
CPU/RAM nœud
VMs status
SRC 05
SSL openssl
s_client -connect
Parsing not_after
Alerte si < 7j
SRC 06
SSH check
socket connect
Hôtes UP/DOWN
Uptime via ssh
SRC 07
Honeypot
URLs pièges vhosts
Détection accès
Tag EXPLOIT auto
// extrait Python — structure générique
monitoring_gen.py — structure générique
# monitoring_gen.py — structure générique
import json, re, subprocess
from datetime import datetime, timedelta
from pathlib import Path

LOG_FILES    = ['/var/log/nginx/access.log', '/var/log/nginx/access.log.1']
OUTPUT       = Path('/var/www/monitoring/monitoring.json')
HONEYPOT_PATHS = ['/wp-admin', '/wp-login.php', '/.env', '/cgi-bin/', '/xmlrpc.php']

LOG_RE = re.compile(
    r'(?P<ip>\S+) \S+ \S+ \[(?P<time>[^\]]+)\] '
    r'"(?P<method>\S+) (?P<path>\S+)[^"]*" (?P<status>\d{3}) (?P<size>\d+)'
)

def classify_kill_chain(entries):
    chain = {"recon": set(), "scan": set(), "exploit": set(), "brute": set()}
    status_count = {}
    for e in entries:
        ip, path, status = e['ip'], e['path'].lower(), int(e['status'])
        status_count.setdefault(ip, {}).setdefault(status, 0)
        status_count[ip][status] += 1
        if any(x in path for x in ['.env', 'robots.txt', '/.git', 'sitemap']):
            chain['recon'].add(ip)
        if any(x in path for x in ['/wp-admin', '/cgi-bin', '/.php', 'xmlrpc']):
            chain['exploit'].add(ip)
    # Brute force = 401 répétés sur même IP
    for ip, counts in status_count.items():
        if counts.get(401, 0) >= 5:
            chain['brute'].add(ip)
    return {k: list(v) for k, v in chain.items()}

def check_ssl_expiry(domain):
    result = subprocess.run(
        ['openssl', 's_client', '-connect', f'{domain}:443', '-servername', domain],
        capture_output=True, text=True, timeout=5, input=''
    )
    # parse not_after date — retourne nb jours restants
    ...
// crons actifs — srv-ngix
crontab -l (root@[MONITORING_SERVER])
# Monitoring JSON — toutes les 5 minutes
*/5 * * * * /opt/scripts/monitoring.sh >> /var/log/monitoring.log 2>&1

# Synchronisation CVE NVD — 3x par jour
0 6,13,21 * * * /opt/scripts/cron-cve-fetch.sh >> /var/log/cve-fetch.log 2>&1

# Rapport SOC quotidien — 08h00 UTC
0 8 * * * /opt/scripts/soc-daily-report.py >> /var/log/soc-report.log 2>&1

# Mise à jour GeoIP MaxMind — quotidien 03h00
0 3 * * * /usr/bin/geoipupdate >> /var/log/geoipupdate.log 2>&1

# Snapshot UFW — état pare-feu horodaté (toutes les 6h)
0 */6 * * * /opt/scripts/ufw-snapshot.sh >> /var/log/ufw-snapshot.log 2>&1

# Threat Intel — flux menaces externes
0 3 * * * /opt/scripts/threat-fetch.sh >> /var/log/threat-fetch.log 2>&1

# Proto-live — analyse protocoles réseau temps réel
*/1 * * * * /opt/scripts/proto-live.py >> /var/log/proto-live.log 2>&1

# Nettoyage logs rotatifs — hebdomadaire
0 2 * * 0 /opt/scripts/log-rotate-clean.sh >> /var/log/log-clean.log 2>&1
// performance — anti-freeze 60s

$ cat performance.md

Le dashboard rafraichit ses données toutes les 60 secondes. Sur des sessions longues (plusieurs heures), un rendu DOM naif provoquerait des freezes perceptibles. Deux mécanismes sont combinés pour garantir une expérience fluide en permanence, même sur machine peu puissante.

Mécanisme Implémentation Effet
If-Modified-Since Header HTTP + _lastModified stocké en mémoire 304 si fichier inchangé → 0 parsing, 0 DOM update
requestIdleCallback render(data) différé dans callback idle Exécution pendant créneau idle navigateur — 0 clipping
_lastGenAt Comparaison timestamp JSON côté client Double vérification applicative — ignorer si identique
Polling proto-live Aussi idle-schedulé (cycle 15s) Même protection pour le flux protocoles réseau
fetch JSON avec If-Modified-Since — dashboard SOC (extrait)
// fetch JSON avec If-Modified-Since — dashboard SOC
let _lastModified = null;

async function fetchMonitoring() {
  const headers = {};
  if (_lastModified) headers['If-Modified-Since'] = _lastModified;

  const res = await fetch('/monitoring.json', { headers });

  // 304 = fichier inchangé — rien à re-parser ni à re-rendre
  if (res.status === 304) return;

  _lastModified = res.headers.get('Last-Modified');
  const data = await res.json();

  // Différer le rendu pendant un créneau idle du navigateur
  if ('requestIdleCallback' in window) {
    requestIdleCallback(() => render(data), { timeout: 2000 });
  } else {
    setTimeout(() => render(data), 0);   // fallback navigateurs anciens
  }
}

// Refresh toutes les 60s
setInterval(fetchMonitoring, 60_000);
fetchMonitoring(); // premier appel immédiat
// inventaire des 28 tuiles

$ cat tiles-inventory.json

▶ HERO — MENACES EN COURS
WIDELIVE
CYBER KILL CHAIN
Canvas animé, liste IPs actives, phases d'attaque en cours, score global normalisé
WIDE
GEOIP — CARTOGRAPHIE 24H
Carte monde canvas, arcs d'attaque géolocalisés par pays source
▶ MENACES & PROTECTION
NIVEAU DE MENACE GLOBAL
Score 0-100 coloré selon sévérité : NOMINAL / MODÉRÉ / ÉLEVÉ / CRITIQUE
SERVICES
Services UP/DOWN sur le reverse proxy — nginx, crowdsec, fail2ban, ssh
THREAT INTEL SYNC
Flux menaces externes synchronisés — dernière mise à jour, nb entrées
FAIL2BAN — JAILS
Jails actives, IPs bannies — modal détail avec liste par jail
CROWDSEC
Analyse comportementale, décisions actives, scénarios en cours
CVE SYNC
Dernière MAJ NVD, 21 mois indexés, CVE critiques récentes
▶ TRAFIC & ACTIVITÉ
WIDE
ACTIVITÉ TEMPS RÉEL
Graphique barres requêtes/heure — 24 barres glissantes, légende 2xx/4xx/5xx
ACTIVITÉ & ATTAQUES 24H
Heatmap canvas 24h — densité des requêtes par heure et par type
PROTOCOLES ACTIFS
Donut canvas + légende — répartition HTTP/HTTPS/SSH/DNS/autres
TOP PAGES 24H
Tableau des pages les plus requêtées avec compteur et statut
TRAFIC 24H
Stats globales : total, 2xx, 4xx, 5xx, volume bytes, taux d'erreur
LIVE
FLUX LIVE
Barres protocoles fenêtre 5 minutes — source proto-live.json 15s
BANDE PASSANTE nginx
Sparklines RX/TX sur 24h — pic/moyen/actuel en Mo/s
SYSTÈME — SERVEUR
CPU ring animé, RAM barre, disque /var/www — seuils colorés
RÉSEAU — SERVEUR
Interfaces réseau RX/TX — graphique sparkline par interface
▶ INFRASTRUCTURE
PROXMOX — NŒUD
CPU/RAM/stockage hyperviseur — températures, uptime, version PVE
PROXMOX — VMs
Machines virtuelles actives/total — mémoire allouée, CPU vcores
WINDOWS — RESSOURCES
CPU/RAM/disques machine locale — modal détail avec historique
WINDOWS — SAUVEGARDES
Quota D:, dernières backups par VM — date, taille, statut rotation
IA
GPU RTX 5080
Stats GPU injectées dynamiquement par JARVIS : VRAM, temp, charge
CRONS — INFRASTRUCTURE
Tâches planifiées Windows et Linux — statut dernière exécution
IA
JARVIS — INTELLIGENCE
Statut ONLINE/OFFLINE, modèle LLM actif, compteurs session, uptime
IA
BLOCKLIST LLM GARDE-FOU
Journal tentatives tool calling bloquées — sécurité actions JARVIS
IA
OPÉRATIONS PROACTIVES
Journal actions JARVIS : ban-ip, restart-service — timestamp + résultat
SSL
Certificats TLS, jours restants par domaine — alerte si < 7 jours
CONNECTIVITÉ SSH
Statut UP/DOWN + uptime des 4 hôtes surveillés
// sources de données

$ cat data-sources.json

Fichier JSON Générateur Fréquence Contenu principal
monitoring.json monitoring_gen.py 60s (cron) nginx logs, CrowdSec, fail2ban, système, réseau, Proxmox, SSL, CVE, GeoIP, Kill Chain
windows-disk.json windows-disk-report.ps1 Chaque backup Disques Windows, GPU RTX, CPU, RAM, liste sauvegardes VMs avec tailles
proto-live.json proto-live.py 15s Répartition protocoles réseau en temps réel — fenêtre glissante 5 minutes
world.json Statique (MaxMind) GeoJSON frontières mondiales pour cartographie canvas des origines d'attaque
// intégration IA — auto-engine

$ cat jarvis-integration.json

JARVIS (assistant IA local Flask) est intégré au dashboard SOC via un auto-engine qui surveille les deltas de trafic et les métriques système. Quand un seuil critique est dépassé, JARVIS est automatiquement sollicité pour une analyse narrative LLM et une alerte vocale TTS.

// triggers auto-engine
Trigger Condition de déclenchement Badge tuile Action
Activité anormale +15 événements vs dernier check JSON Analyse auto Analyse LLM narrative + affichage résultat
Alerte CPU CPU serveur > 90% Alerte critique TTS + analyse LLM processus
Alerte IPs Bans actifs CrowdSec > 100 Alerte critique TTS + analyse LLM menaces
Erreurs HTTP 5xx > 5% du trafic total 24h Alerte critique TTS + analyse LLM services
Résumé quotidien Chaque jour à 08h00 (heure locale) Résumé du jour Email rapport + TTS briefing matinal
// routes JARVIS utilisées par le SOC
Route Méthode Usage SOC
/api/gpu GET Statut JARVIS + modèle LLM actif + stats GPU RTX
/api/chat POST Analyse LLM des données SOC — retourne synthèse narrative
/api/tts GET Lecture vocale des alertes via edge-tts fr-CA-AntoineNeural
/api/security GET Journal blocklist LLM — tentatives tool calling bloquées
/api/soc/ban-ip POST Ban IP via cscli decisions add — confirmation LLM requise
/api/soc/unban-ip POST Lève le ban CrowdSec pour une IP — traçabilité dans journal
/api/soc/restart-service POST Redémarre un service autorisé — liste blanche configurable
/api/soc/actions GET Journal opérations proactives — horodatage + résultat
// prompt SOC type envoyé à JARVIS
prompt-soc.txt — analyse automatique
Contexte : SOC Dashboard — analyse de sécurité automatique
Données disponibles : trafic nginx 24h, décisions CrowdSec, jails fail2ban,
                      Kill Chain actif, top IPs, scores protocoles

Analyse la situation sécurité actuelle :
- Y a-t-il des menaces actives à traiter en priorité ?
- Quels scénarios CrowdSec dominent ?
- Y a-t-il des anomalies dans le trafic HTTP ?
- Recommande des actions concrètes si nécessaire.

Format : 3-5 lignes concises, niveau [NOMINAL/MODÉRÉ/ÉLEVÉ/CRITIQUE],
         action si requise.
// système d'alertes

$ cat alert-thresholds.json

// seuils de déclenchement
Indicateur Seuil Niveau Action automatique
CPU serveur > 90% CRITIQUE Analyse JARVIS + alerte TTS
IPs bannies actives > 100 décisions CrowdSec CRITIQUE Analyse JARVIS + alerte TTS
Erreurs 5xx > 5% du trafic 24h CRITIQUE Analyse JARVIS + alerte TTS
SSL expiration < 7 jours restants ROUGE certbot renew --force-renewal
Disque /var/www > 85% utilisation ROUGE Nettoyage logs rotatifs automatique
RAM serveur > 85% ORANGE Surveillance accrue, analyse processus
Top IP 24h > 500 requêtes / IP SUSPICION Analyse GoAccess + éventuel ban manuel
AppSec WAF port Port 7422 non répondant ROUGE systemctl restart crowdsec
// rapport quotidien — soc-daily-report.py
Envoyé chaque matin à 08h00 UTC par soc-daily-report.py via cron
Contenu : trafic 24h · protocoles · CrowdSec bans · fail2ban jails · Kill Chain · top 10 attaquants · état services · SSL · système · sauvegardes
Déclenchement manuel possible via bouton RAPPORT dans le header dashboard (cooldown 60s entre deux envois)
Raccourci clavier [E] pour envoi rapide depuis le dashboard
// raccourcis clavier
Touche Action
[F] Ouvre le modal Firewall Matrix — règles nftables actives
[T] Ouvre le modal Analyse Trafic — vue détaillée par heure
[E] Envoie le rapport SOC par email (cooldown 60s)
[R] Force un refresh JSON immédiat (contourne les 60s)
[Z] Active le mode projection plein écran (salle de guerre)
// périmètre & défense en profondeur

$ cat defense-layers.txt

Cette solution est conçue pour un environnement homelab — réseau local uniquement. Le dashboard SOC n'est pas exposé sur internet. L'ensemble de la stack (reverse proxy, WAF, dashboard, IA locale) fonctionne dans un périmètre LAN maîtrisé. Cette architecture sert de laboratoire pour maîtriser les outils de défense en conditions réelles avant tout déploiement en environnement exposé.

// CrowdSec — scénarios détectés en production
Scénario Type d'attaque Fréquence observée
http-cve-2021-41773 Apache path traversal (CVE) Très fréquent — scans automatisés en continu
http-cve-2021-42013 RCE Apache (CVE) Vagues périodiques de scans massifs
http-bad-user-agent User-Agent malveillant connu Continu — plusieurs centaines / jour
http-probing Enumération de paths non existants Continu — scans automatisés botnets
http-admin-interface-probing Scan /admin /phpmyadmin /wp-admin Continu — plusieurs par heure
http-wordpress-scan Scan plugins/themes WordPress Fréquent — même sur serveurs sans WP
http-sensitive-files .env, backup.zip, .git, .DS_Store Fréquent — outils OSINT automatisés
http-open-proxy Tentative de proxy ouvert CONNECT Occasionnel — botnets recherchant relais
// origines géographiques typiques des attaques
DE US RU SG RO KR TW BG FR sources publiques — données GeoIP2 MaxMind
// honeypot — URLs pièges intégrées aux vhosts

Des URLs pièges sont configurées dans les vhosts nginx. Elles ne retournent aucun contenu légitime. Tout accès déclenche un tag immédiat dans les logs et une classification EXPLOIT par monitoring_gen.py, suivie d'un ban automatique CrowdSec.

// paths pièges (exemples génériques)
/wp-admin
/wp-login.php
/.env
/cgi-bin/test.cgi
/xmlrpc.php
/backup.zip
/.git/config
/phpmyadmin
/admin/login
// stats typiques 24h
50-100 HITS HONEYPOT / 24H
15-25 IPS UNIQUES PIÉGÉES
100% BLOQUÉES AVANT nginx