Add run-e2e-test.sh with CLI parameters (--hits, --http-ratio, --dns, --tls, --src-ips, --keep-analysis, --up) for configurable traffic generation. Traffic runs from VM endpoints with multiple source IPs (alias IPs on eth0) to produce distinct sessions for the ML pipeline. Fix curl TLS flags (--tlsv1.2 instead of --tls-v1-2), skip redundant local verification in distributed mode, and fix dashboard is_available() cache that never retried after ClickHouse recovery. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
190 lines
7.4 KiB
Markdown
190 lines
7.4 KiB
Markdown
# Test E2E distribué — Stack de test complète ja4-platform
|
||
|
||
## Objectif
|
||
|
||
Valider le pipeline complet de bout en bout :
|
||
|
||
```
|
||
trafic simulé → ja4ebpf (capture eBPF) → ClickHouse (stockage + agrégation MV)
|
||
→ bot-detector (ML) → dashboard (visualisation)
|
||
```
|
||
|
||
Les tests unitaires et d'intégration existants testent la capture eBPF isolément.
|
||
Le test E2E distribué valide la **chaine complète** sur une architecture multi-VMs.
|
||
|
||
## Architecture
|
||
|
||
```
|
||
HOST (orchestrateur — run-e2e-test.sh)
|
||
│
|
||
├── centos8 (el8) ── nginx + ja4ebpf ──eth1──┐
|
||
├── rocky9 (el9) ── nginx + ja4ebpf ──eth1──┤ réseau privé ja4-e2e
|
||
├── rocky10 (el10) ── nginx + ja4ebpf ──eth1──┤ 192.168.42.0/24
|
||
│ │
|
||
│ analysis ────┘ 192.168.42.10 (fixe)
|
||
│ ├── Docker ClickHouse :9000/:8123
|
||
│ ├── Docker bot-detector :8080
|
||
│ └── Docker dashboard :8000
|
||
│
|
||
└── Trafic curl/httpx → endpoints :80/:443
|
||
```
|
||
|
||
### VMs
|
||
|
||
| VM | Rôle | Box | IP | Services |
|
||
|----|------|-----|-----|----------|
|
||
| centos8 | Endpoint el8 | centos/8 | DHCP eth0 | nginx, ja4ebpf |
|
||
| rocky9 | Endpoint el9 | generic/rocky9 | DHCP eth0 | nginx, ja4ebpf |
|
||
| rocky10 | Endpoint el10 | almalinux/10 | DHCP eth0 | nginx, ja4ebpf |
|
||
| analysis | Serveur central | generic/rocky9 | 192.168.42.10 (eth1 fixe) | Docker: ClickHouse, bot-detector, dashboard |
|
||
|
||
### Réseau
|
||
|
||
- **eth0** (NAT libvirt) : SSH depuis le host, réception du trafic de test
|
||
- **eth1** (réseau privé `ja4-e2e`) : communication inter-VMs
|
||
- Les endpoints utilisent eth1 pour envoyer les logs ja4ebpf vers `192.168.42.10:9000`
|
||
- Le host accède au dashboard et ClickHouse via l'IP eth0 de la VM analysis (routée via libvirt NAT)
|
||
|
||
## Pipeline de données
|
||
|
||
```
|
||
1. HOST → endpoints curl/httpx génère du trafic HTTP/HTTPS/H2
|
||
2. ja4ebpf Capture eBPF : TLS ClientHello (JA4), TCP SYN (L3/L4),
|
||
HTTP via uprobe SSL_read (L7)
|
||
3. → ClickHouse :9000 ja4ebpf écrit dans ja4_logs.http_logs_raw (batch 100 lignes, flush 1s)
|
||
4. MV mv_http_logs Materialized View : http_logs_raw → http_logs (parsed, corrélé)
|
||
5. MV mv_agg_host_ip_ja4_1h Agrégation horaire par (host, src_ip, ja4) → agg_host_ip_ja4_1h
|
||
6. view_ai_features_1h Vue qui joint les features pour le ML
|
||
7. bot-detector Cycle ML toutes les 30s (config de test) :
|
||
- Lit view_ai_features_1h
|
||
- Pipeline : NFEnsemble (M=5 NF) → ADWIN (River) → MLP fusion
|
||
- Écrit ml_all_scores + ml_detected_anomalies
|
||
8. dashboard API FastAPI sur :8000, requête ClickHouse
|
||
```
|
||
|
||
## Principe clé : DB vierge avant chaque test
|
||
|
||
Avant chaque exécution E2E, la Phase 1 fait un `docker compose down -v` qui supprime tous les volumes Docker (y compris les données ClickHouse). Cela garantit que :
|
||
- ClickHouse démarre avec un schéma vierge
|
||
- Les données observées sont exclusivement celles générées par le test
|
||
- Les vérifications de la Phase 5 sont déterministes
|
||
|
||
## Stack Docker (VM analysis)
|
||
|
||
Définie dans `tests/vm/analysis/docker-compose.yml` :
|
||
|
||
### ClickHouse
|
||
- Image : `clickhouse/clickhouse-server:24.8`
|
||
- Ports : `0.0.0.0:9000` (native, ja4ebpf), `0.0.0.0:8123` (HTTP, API)
|
||
- Schéma : 12 fichiers SQL de `shared/clickhouse/*.sql`, exécutés via `clickhouse-init.sh`
|
||
- Credentials : `user=default, password=""` (patché par clickhouse-init.sh)
|
||
- Dictionnaires : CSV stubs de `tests/integration/platform/csv-stubs/`
|
||
|
||
### bot-detector
|
||
- Build : `services/bot-detector/bot_detector/Dockerfile`
|
||
- Port : `0.0.0.0:8080` (health check)
|
||
- Configuration accélérée pour les tests :
|
||
- `CYCLE_INTERVAL_SEC: 30` (vs 300 en prod)
|
||
- `MIN_VALID_FEATURE_RATIO: 0.10` (vs 0.50 en prod)
|
||
- SHAP, clustering, multi-fenêtres désactivés
|
||
|
||
### dashboard
|
||
- Build : `services/dashboard/Dockerfile`
|
||
- Port : `0.0.0.0:8000`
|
||
- Routes de vérification : `/health`, `/api/overview`, `/api/detections`
|
||
|
||
## Phases du test (run-e2e-test.sh)
|
||
|
||
| Phase | Description | Durée |
|
||
|-------|-------------|-------|
|
||
| 0 | Setup : démarrage VMs, rsync, découverte IPs | ~2 min (si VMs existantes) |
|
||
| 1 | Stack analysis : purge volumes (DB vierge), `docker compose up -d --build`, attente healthy | ~3 min |
|
||
| 2 | Endpoints : nginx + ja4ebpf (DSN → analysis:9000), en parallèle | ~1 min |
|
||
| 3 | Trafic : 500 req/VM × 3 VMs, HTTP/HTTPS/H2, méthodes variées | ~5 min |
|
||
| 4 | Attente : flush ja4ebpf 15s, poll ml_all_scores (max 120s) | ~2 min |
|
||
| 5 | Vérifications : 15+ checks sur 4 layers | ~1 min |
|
||
|
||
## Vérifications (Phase 5)
|
||
|
||
### Layer 1 — Données brutes
|
||
- `ja4_logs.http_logs_raw` : lignes > 0
|
||
- `uniqExact(host)` : >= 2 hôtes distincts (multi-source)
|
||
|
||
### Layer 2 — Pipeline ClickHouse (MVs)
|
||
- `ja4_logs.http_logs` : JA4 fingerprints capturés
|
||
- `ja4_logs.http_logs` : méthodes HTTP capturées (L7 via uprobe SSL_read)
|
||
- `ja4_processing.agg_host_ip_ja4_1h` : agrégation horaire peuplée
|
||
- `ja4_processing.view_ai_features_1h` : features ML disponibles
|
||
|
||
### Layer 3 — ML bot-detector
|
||
- `ja4_processing.ml_all_scores` : classifications produites
|
||
- `ja4_processing.ml_detected_anomalies` : anomalies détectées (optionnel)
|
||
- Health check `:8080`
|
||
|
||
### Layer 4 — Dashboard
|
||
- `/health` : OK
|
||
- `/api/overview` : données non-vides
|
||
- `/api/detections` : accessible
|
||
|
||
## Utilisation
|
||
|
||
```bash
|
||
# Créer les 4 VMs
|
||
make e2e-up
|
||
|
||
# Test complet (500 req/VM, ~15 min)
|
||
make test-e2e
|
||
|
||
# Test rapide (100 req/VM)
|
||
make test-e2e-quick
|
||
|
||
# Garder les VMs après le test (pour debug)
|
||
KEEP_RUNNING=true make test-e2e
|
||
|
||
# Détruire les VMs
|
||
make e2e-down
|
||
```
|
||
|
||
## Accès manuel (debug)
|
||
|
||
```bash
|
||
# ClickHouse — vérifier les données
|
||
curl "http://192.168.42.10:8123/?query=SELECT+count()+FROM+ja4_logs.http_logs"
|
||
|
||
# Dashboard
|
||
curl http://192.168.42.10:8000/health
|
||
curl http://192.168.42.10:8000/api/overview | python3 -m json.tool
|
||
|
||
# bot-detector
|
||
curl http://192.168.42.10:8080/
|
||
|
||
# SSH dans la VM analysis
|
||
cd tests/vm && vagrant ssh analysis
|
||
|
||
# Logs des conteneurs
|
||
vagrant ssh analysis -- "docker logs bot_detector_ai --tail 50"
|
||
vagrant ssh analysis -- "docker logs ja4-dashboard --tail 50"
|
||
```
|
||
|
||
## Fichiers
|
||
|
||
| Fichier | Rôle |
|
||
|---------|------|
|
||
| `tests/vm/Vagrantfile` | Définition des 4 VMs + réseau ja4-e2e |
|
||
| `tests/vm/provision-analysis.sh` | Provisionneur VM analysis (Docker, firewall) |
|
||
| `tests/vm/analysis/docker-compose.yml` | Stack centralisée CH + bot-detector + dashboard |
|
||
| `tests/vm/run-e2e-test.sh` | Orchestrateur E2E 5 phases |
|
||
| `tests/vm/run-tests-vm.sh` | Script endpoint (modifié pour CH_HOST) |
|
||
| `Makefile` | Cibles e2e-up, e2e-down, test-e2e, test-e2e-quick |
|
||
|
||
## Dépannage
|
||
|
||
| Problème | Diagnostic |
|
||
|----------|------------|
|
||
| ClickHouse inaccessible | `vagrant ssh analysis -- "docker ps"` ; vérifier le port binding |
|
||
| ja4ebpf n'écrit pas | `vagrant ssh rocky9 -- "cat /tmp/ja4ebpf.log \| tail 20"` |
|
||
| Pas de JA4 | Le hook TC nécessite CAP_BPF ; vérifier `dmesg \| grep bpf` |
|
||
| bot-detector ne démarre pas | `vagrant ssh analysis -- "docker logs bot_detector_ai"` |
|
||
| Pas de données ML | Volume insuffisant pour les fenêtres d'agrégation horaire |
|
||
| Dashboard vide | Le bot-detector doit avoir complété au moins 1 cycle (30s) |
|