- Use two separate //go:generate directives (Ja4Tc for tc_capture.c, Ja4Ssl
for uprobe_ssl.c) to avoid duplicate LICENSE symbol and multi-file clang issue
- Update loader.go to hold tcObjs/sslObjs separately with correct field names:
UprobeSslSetFd, UprobeSslReadEntry, UretprobeSslReadExit,
KprobeAccept4Entry, KretprobeAccept4Exit
- Add systemd-rpm-macros to all three RPM build stages (el8/el9/el10)
so that %{_unitdir} macro resolves correctly
- RPMs now build successfully for el8, el9, el10
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
473 lines
16 KiB
Markdown
473 lines
16 KiB
Markdown
# Guide de déploiement — ja4-platform
|
||
|
||
## Prérequis
|
||
|
||
| Composant | Version minimale | Notes |
|
||
|-----------|-----------------|-------|
|
||
| ClickHouse | 23.8+ | Requis pour `REGEXP_TREE`, `IP_TRIE` dictionaries |
|
||
| Docker | 20.10+ | Pour build des images et RPMs |
|
||
| Make | 3.81+ | Orchestration des builds |
|
||
| OS cible (RPM) | Rocky/RHEL 8, 9, ou 10 | RPMs générés pour les 3 versions |
|
||
|
||
### Services et leur runtime
|
||
|
||
| Service | Runtime | Port par défaut |
|
||
|---------|---------|-----------------|
|
||
| ja4ebpf | Go binary + eBPF CO-RE (RPM) | — (capture réseau passive) |
|
||
| bot-detector | Python 3.11 (Docker) | 8080 (health check) |
|
||
| dashboard | Python 3.11 / FastAPI (Docker) | 8000 (API) |
|
||
|
||
---
|
||
|
||
## Étape 1 — Installation de ClickHouse
|
||
|
||
### Installation (Rocky Linux / RHEL)
|
||
|
||
```bash
|
||
sudo yum install -y yum-utils
|
||
sudo yum-config-manager --add-repo https://packages.clickhouse.com/rpm/clickhouse.repo
|
||
sudo yum install -y clickhouse-server clickhouse-client
|
||
sudo systemctl enable --now clickhouse-server
|
||
```
|
||
|
||
### Vérification
|
||
|
||
```bash
|
||
clickhouse-client --query "SELECT version()"
|
||
```
|
||
|
||
---
|
||
|
||
## Étape 2 — Déploiement du schéma ClickHouse
|
||
|
||
Le schéma est géré par **13 fichiers SQL ordonnés** dans `shared/clickhouse/` et un script de déploiement automatisé.
|
||
|
||
### Architecture des bases de données
|
||
|
||
Le système utilise **deux bases de données** séparées :
|
||
|
||
| Base | Variable d'env | Défaut | Contenu |
|
||
|------|---------------|--------|---------|
|
||
| **Logs** | `CLICKHOUSE_DB_LOGS` | `ja4_logs` | Logs bruts et parsés |
|
||
| **Traitement** | `CLICKHOUSE_DB_PROCESSING` | `ja4_processing` | Agrégations, ML, dictionnaires, vues, audit |
|
||
|
||
### Fichiers de migration
|
||
|
||
```
|
||
shared/clickhouse/
|
||
├── 00_database.sql # Création des bases ja4_logs + ja4_processing
|
||
├── 01_raw_tables.sql # ja4_logs.http_logs_raw (ingestion brute, TTL 2 heures)
|
||
├── 02_dictionaries.sql # ja4_processing : dict_iplocate_asn, ref_bot_networks, bot_ip, bot_ja4
|
||
├── 03_anubis_tables.sql # ja4_processing : anubis_ip_rules, anubis_asn_rules + 2 dicts (IP/CIDR + ASN)
|
||
├── 04_mv_http_logs.sql # ja4_logs.http_logs + mv_http_logs (parsing JSON → colonnes typées)
|
||
├── 05_aggregation_tables.sql # ja4_processing : agg_host_ip_ja4_1h, agg_header_fingerprint_1h + MVs + 4 dicts
|
||
├── 06_ml_tables.sql # ja4_processing : ml_detected_anomalies, ml_all_scores, view_ip_recurrence
|
||
├── 07_ai_features_view.sql # ja4_processing : view_ai_features_1h (feature engineering ~63 features)
|
||
├── 08_users.sql # Utilisateurs data_writer et analyst + permissions
|
||
├── 09_audit_table.sql # ja4_processing : audit_logs (trace SOC, TTL 90 jours)
|
||
├── 10_perf_indexes.sql # Index et projections de performance sur tables existantes
|
||
├── 11_views.sql # Vues métier du dashboard (bruteforce, rotation, user_agents, entities)
|
||
├── 12_thesis_features.sql # Tables d'agrégation avancées (path_sequences, request_timing,
|
||
│ # ip_behavior, resource_cascade) + MVs + vues thèse
|
||
└── deploy_schema.sh # Script de déploiement automatisé (substitution env vars)
|
||
```
|
||
|
||
### Déploiement avec les noms par défaut
|
||
|
||
```bash
|
||
cd shared/clickhouse/
|
||
chmod +x deploy_schema.sh
|
||
./deploy_schema.sh
|
||
```
|
||
|
||
### Déploiement avec des noms personnalisés
|
||
|
||
```bash
|
||
CLICKHOUSE_DB_LOGS=prod_logs \
|
||
CLICKHOUSE_DB_PROCESSING=prod_analysis \
|
||
CLICKHOUSE_HOST=clickhouse.internal \
|
||
CLICKHOUSE_PORT=9000 \
|
||
CLICKHOUSE_USER=default \
|
||
CLICKHOUSE_PASSWORD=MonMotDePasse \
|
||
./deploy_schema.sh
|
||
```
|
||
|
||
Le script effectue une substitution `sed` sur chaque fichier SQL avant de l'envoyer à `clickhouse-client --multiquery`.
|
||
|
||
### Déploiement manuel (fichier par fichier)
|
||
|
||
```bash
|
||
clickhouse-client --multiquery < shared/clickhouse/00_database.sql
|
||
clickhouse-client --multiquery < shared/clickhouse/01_raw_tables.sql
|
||
# ... etc., dans l'ordre
|
||
```
|
||
|
||
### Vérification du déploiement
|
||
|
||
```bash
|
||
# Tables dans ja4_logs
|
||
clickhouse-client --query "SHOW TABLES FROM ja4_logs"
|
||
# Attendu : http_logs, http_logs_raw
|
||
|
||
# Tables dans ja4_processing
|
||
clickhouse-client --query "SHOW TABLES FROM ja4_processing"
|
||
# Attendu : agg_header_fingerprint_1h, agg_host_ip_ja4_1h, agg_ip_behavior_1h,
|
||
# agg_path_sequences_1h, agg_request_timing_1h, agg_resource_cascade_1h,
|
||
# anubis_asn_rules, anubis_ip_rules, audit_logs, bot_ip, bot_ja4,
|
||
# ml_all_scores, ml_detected_anomalies, ref_bot_networks, ...
|
||
|
||
# Dictionnaires chargés
|
||
clickhouse-client --query "SELECT name, status FROM system.dictionaries WHERE database IN ('ja4_logs', 'ja4_processing')"
|
||
|
||
# Utilisateurs créés
|
||
clickhouse-client --query "SHOW USERS"
|
||
```
|
||
|
||
---
|
||
|
||
## Étape 3 — Configuration des utilisateurs ClickHouse
|
||
|
||
Le fichier `08_users.sql` crée deux utilisateurs avec des mots de passe par défaut **à changer impérativement** :
|
||
|
||
### Utilisateurs et permissions
|
||
|
||
| Utilisateur | Mot de passe défaut | Rôle | Permissions |
|
||
|-------------|-------------------|------|-------------|
|
||
| `data_writer` | `ChangeMe` | Ingestion (correlator) | `INSERT`, `SELECT` sur `ja4_logs.http_logs_raw` |
|
||
| `analyst` | `ChangeMe` | Lecture (dashboard, bot-detector) | `SELECT` sur `ja4_logs.http_logs`, `ja4_processing.ml_*`, `ja4_processing.view_*`, `ja4_processing.audit_logs` |
|
||
|
||
### Changement des mots de passe (obligatoire en production)
|
||
|
||
```bash
|
||
# Utiliser SHA256 pour la production
|
||
clickhouse-client --query "
|
||
ALTER USER data_writer IDENTIFIED WITH sha256_password BY 'VotreMotDePasseWriter';
|
||
ALTER USER analyst IDENTIFIED WITH sha256_password BY 'VotreMotDePasseAnalyst';
|
||
"
|
||
```
|
||
|
||
### Permissions supplémentaires pour le bot-detector
|
||
|
||
Le bot-detector a besoin d'écrire dans les tables ML. Ajoutez ces grants pour l'utilisateur utilisé par le bot-detector (ici `admin` ou un utilisateur dédié) :
|
||
|
||
```sql
|
||
-- Créer un utilisateur dédié pour le bot-detector
|
||
CREATE USER IF NOT EXISTS bot_writer IDENTIFIED WITH sha256_password BY 'VotreMotDePasse';
|
||
|
||
-- Lectures : features et récurrence (ja4_processing)
|
||
GRANT SELECT ON ja4_processing.view_ai_features_1h TO bot_writer;
|
||
GRANT SELECT ON ja4_processing.view_ip_recurrence TO bot_writer;
|
||
GRANT SELECT ON ja4_processing.ml_detected_anomalies TO bot_writer;
|
||
|
||
-- Écritures : résultats ML (ja4_processing)
|
||
GRANT INSERT ON ja4_processing.ml_all_scores TO bot_writer;
|
||
GRANT INSERT ON ja4_processing.ml_detected_anomalies TO bot_writer;
|
||
|
||
-- Lectures/écritures : tables Anubis (ja4_processing) — pour fetch_rules.py
|
||
-- Seules les règles IP/CIDR et ASN sont utilisées (UA et Country ont été supprimés)
|
||
GRANT SELECT, INSERT, ALTER ON ja4_processing.anubis_ip_rules TO bot_writer;
|
||
GRANT SELECT, INSERT, ALTER ON ja4_processing.anubis_asn_rules TO bot_writer;
|
||
GRANT SYSTEM RELOAD DICTIONARY ON *.* TO bot_writer;
|
||
```
|
||
|
||
### Permissions pour l'audit (dashboard)
|
||
|
||
```sql
|
||
-- Le dashboard doit pouvoir écrire dans audit_logs
|
||
GRANT INSERT ON ja4_processing.audit_logs TO analyst;
|
||
```
|
||
|
||
---
|
||
|
||
## Étape 4 — Fichiers de données externes
|
||
|
||
Certains dictionnaires ClickHouse chargent des fichiers CSV depuis le disque :
|
||
|
||
```bash
|
||
# Répertoire des fichiers utilisateur ClickHouse
|
||
sudo mkdir -p /var/lib/clickhouse/user_files/
|
||
|
||
# Fichiers requis (à fournir par l'opérateur) :
|
||
# - iplocate_asn.csv → dict_iplocate_asn (géolocalisation IP/ASN)
|
||
# - bot_ip.csv → bot_ip (IPs de bots connues)
|
||
# - bot_ja4.csv → bot_ja4 (signatures JA4 de bots)
|
||
# - asn_reputation.csv → dict_asn_reputation (réputation ASN)
|
||
|
||
# Exemple de format bot_ip.csv :
|
||
# prefix,bot_name
|
||
# 198.51.100.0/24,ExampleBot
|
||
# 203.0.113.42/32,ScannerBot
|
||
|
||
# Permissions
|
||
sudo chown -R clickhouse:clickhouse /var/lib/clickhouse/user_files/
|
||
```
|
||
|
||
---
|
||
|
||
## Étape 5 — Installation de ja4ebpf (RPM)
|
||
|
||
### Build des RPMs
|
||
|
||
```bash
|
||
# RPM ja4ebpf × 3 distros (el8, el9, el10)
|
||
make rpm-ja4ebpf
|
||
# → services/ja4ebpf/dist/rpm/el{8,9,10}/
|
||
```
|
||
|
||
Le build utilise un pipeline Docker multi-étapes Rocky Linux :
|
||
1. L’étape `go-builder` compile le bytecode eBPF (clang/llvm) puis le binaire Go statique
|
||
2. Les étapes `rpm-el8`, `rpm-el9`, `rpm-el10` exécutent `rpmbuild` pour chaque distro cible
|
||
3. L’étape `alpine` collecte les RPMs via `--output type=local`
|
||
|
||
### Installation du RPM
|
||
|
||
```bash
|
||
# Sur le serveur cible (Rocky 9 par exemple)
|
||
sudo yum install -y ./ja4ebpf-*.el9.x86_64.rpm
|
||
```
|
||
|
||
### Configuration de ja4ebpf
|
||
|
||
```bash
|
||
# Fichier de configuration principal
|
||
sudo cp /etc/ja4ebpf/config.yml.example /etc/ja4ebpf/config.yml
|
||
sudo vi /etc/ja4ebpf/config.yml
|
||
```
|
||
|
||
Variables d’environnement clés (dans `/etc/sysconfig/ja4ebpf`) :
|
||
|
||
| Variable | Défaut | Description |
|
||
|----------|--------|-------------|
|
||
| `JA4EBPF_INTERFACE` | `eth0` | Interface réseau à observer |
|
||
| `JA4EBPF_CLICKHOUSE_DSN` | — | DSN ClickHouse (ex: `clickhouse://data_writer:pwd@host:9000/ja4_logs`) |
|
||
| `JA4EBPF_TARGET_BINARY` | `/usr/sbin/httpd` | Binaire OpenSSL à hooker (uprobe SSL_read) |
|
||
| `JA4EBPF_BATCH_SIZE` | `500` | Taille des batchs d’insertion ClickHouse |
|
||
| `JA4EBPF_FLUSH_INTERVAL_MS` | `200` | Intervalle de flush (ms) |
|
||
| `JA4EBPF_SESSION_TIMEOUT_MS` | `500` | Timeout orphelin (ms) |
|
||
|
||
```bash
|
||
sudo systemctl enable --now ja4ebpf
|
||
sudo systemctl status ja4ebpf
|
||
journalctl -u ja4ebpf -f
|
||
```
|
||
|
||
### Capabilities Linux requises (SELinux Enforcing)
|
||
|
||
`ja4ebpf` ne tourne **pas** en root absolu. Le fichier systemd utilise les capabilities minimales :
|
||
|
||
| Capability | Raison |
|
||
|------------|--------|
|
||
| `CAP_BPF` | Chargement des programmes eBPF (kernel 5.8+) |
|
||
| `CAP_SYS_ADMIN` | Requis pour les uprobes et RHEL 8 (kernel 4.18 <5.8) |
|
||
| `CAP_NET_ADMIN` | Attachement des hooks TC ingress |
|
||
| `CAP_PERFMON` | Accès aux perf events pour les uprobes |
|
||
|
||
|
||
## Étape 6 — Installation des services Python (Docker)
|
||
|
||
### Bot-detector
|
||
|
||
```bash
|
||
cd services/bot-detector
|
||
|
||
# Copier et configurer .env
|
||
cp .env.example .env
|
||
vi .env # Renseigner CLICKHOUSE_HOST, mots de passe, etc.
|
||
```
|
||
|
||
Variables d'environnement clés :
|
||
|
||
| Variable | Défaut | Description |
|
||
|----------|--------|-------------|
|
||
| `CLICKHOUSE_HOST` | `clickhouse` | Hôte ClickHouse |
|
||
| `CLICKHOUSE_PORT` | `8123` | Port HTTP ClickHouse |
|
||
| `CLICKHOUSE_DB_PROCESSING` | `ja4_processing` | Base de traitement |
|
||
| `CLICKHOUSE_DB_LOGS` | `ja4_logs` | Base de logs |
|
||
| `CLICKHOUSE_USER` | `admin` | Utilisateur (utiliser `bot_writer` en prod) |
|
||
| `CLICKHOUSE_PASSWORD` | — | Mot de passe |
|
||
| `ANOMALY_THRESHOLD` | `-0.05` | Seuil de détection d'anomalies (fallback) |
|
||
| `CYCLE_INTERVAL_SEC` | `300` | Intervalle entre cycles de détection (secondes) |
|
||
| `RETRAIN_INTERVAL_HOURS` | `24` | Intervalle de réentraînement des modèles |
|
||
| `AE_WEIGHT` | `0.30` | Poids de l'Autoencoder dans l'ensemble (α) |
|
||
| `XGB_WEIGHT` | `0.20` | Poids de XGBoost dans l'ensemble (β) |
|
||
| `ENABLE_MULTIWINDOW` | `false` | Active les variantes 24h (Complet/Applicatif) |
|
||
| `HEALTH_PORT` | `8080` | Port du endpoint /health |
|
||
|
||
```bash
|
||
docker compose up -d
|
||
```
|
||
|
||
### Dashboard
|
||
|
||
```bash
|
||
cd services/dashboard
|
||
|
||
# Copier et configurer .env
|
||
cp .env.example .env
|
||
vi .env # Renseigner CLICKHOUSE_HOST, mots de passe, etc.
|
||
```
|
||
|
||
Variables d'environnement clés :
|
||
|
||
| Variable | Défaut | Description |
|
||
|----------|--------|-------------|
|
||
| `CLICKHOUSE_HOST` | `clickhouse` | Hôte ClickHouse |
|
||
| `CLICKHOUSE_PORT` | `8123` | Port HTTP ClickHouse |
|
||
| `CLICKHOUSE_DB_PROCESSING` | `ja4_processing` | Base de traitement |
|
||
| `CLICKHOUSE_DB_LOGS` | `ja4_logs` | Base de logs |
|
||
| `CLICKHOUSE_USER` | `analyst` | Utilisateur en lecture |
|
||
| `CLICKHOUSE_PASSWORD` | — | Mot de passe |
|
||
| `API_HOST` | `0.0.0.0` | Adresse d'écoute de l'API |
|
||
| `API_PORT` | `8000` | Port de l'API FastAPI |
|
||
| `CORS_ORIGINS` | `["http://localhost:3000"]` | Origines CORS autorisées |
|
||
|
||
```bash
|
||
docker compose up -d
|
||
```
|
||
|
||
---
|
||
|
||
## Étape 7 — Vérification de bout en bout
|
||
|
||
### 1. Vérifier que les services tournent
|
||
|
||
```bash
|
||
# Services systemd (Go)
|
||
sudo systemctl status ja4ebpf
|
||
|
||
# Services Docker (Python)
|
||
docker compose -f services/bot-detector/docker-compose.yml ps
|
||
docker compose -f services/dashboard/docker-compose.yaml ps
|
||
```
|
||
|
||
### 2. Vérifier l'ingestion des logs
|
||
|
||
```bash
|
||
# Logs bruts ingérés par ja4ebpf
|
||
clickhouse-client --query "SELECT count() FROM ja4_logs.http_logs_raw"
|
||
|
||
# Logs parsés par la vue matérialisée
|
||
clickhouse-client --query "SELECT count() FROM ja4_logs.http_logs"
|
||
|
||
# Derniers logs
|
||
clickhouse-client --query "
|
||
SELECT time, src_ip, method, host, path, ja4
|
||
FROM ja4_logs.http_logs
|
||
ORDER BY time DESC
|
||
LIMIT 5
|
||
"
|
||
```
|
||
|
||
### 3. Vérifier les agrégations
|
||
|
||
```bash
|
||
clickhouse-client --query "
|
||
SELECT window_start, count()
|
||
FROM ja4_processing.agg_host_ip_ja4_1h
|
||
GROUP BY window_start
|
||
ORDER BY window_start DESC
|
||
LIMIT 5
|
||
"
|
||
```
|
||
|
||
### 4. Vérifier les détections ML
|
||
|
||
```bash
|
||
clickhouse-client --query "
|
||
SELECT src_ip, anomaly_score, label, detected_at
|
||
FROM ja4_processing.ml_detected_anomalies
|
||
ORDER BY detected_at DESC
|
||
LIMIT 5
|
||
"
|
||
```
|
||
|
||
### 5. Tester le dashboard
|
||
|
||
```bash
|
||
curl -s http://localhost:8000/api/metrics | python3 -m json.tool | head -20
|
||
curl -s http://localhost:8000/api/health
|
||
```
|
||
|
||
---
|
||
|
||
## Scripts utilitaires
|
||
|
||
Les scripts dans `scripts/` facilitent l'initialisation et la maintenance de la stack :
|
||
|
||
### init-stack.sh — Initialisation complète
|
||
|
||
Déploie le schéma SQL, charge les données CSV de référence et vérifie que tous les composants sont opérationnels :
|
||
|
||
```bash
|
||
./scripts/init-stack.sh # init stack de dev
|
||
./scripts/init-stack.sh --container my-ch-1 # conteneur ClickHouse spécifique
|
||
./scripts/init-stack.sh --reset # DROP databases, tout recréer
|
||
./scripts/init-stack.sh --import-prod # init + import données prod
|
||
```
|
||
|
||
### import-prod-data.sh — Import de données de production
|
||
|
||
Importe les données exportées au format Native avec décalage temporel automatique :
|
||
|
||
```bash
|
||
./scripts/import-prod-data.sh # décalage auto (max(time) → now)
|
||
./scripts/import-prod-data.sh --shift 3600 # décalage manuel (secondes)
|
||
./scripts/import-prod-data.sh --no-truncate # conserver les données existantes
|
||
```
|
||
|
||
### reload-prod-logs.sh — Rechargement depuis la production
|
||
|
||
Exporte les `http_logs` de la production et les réimporte dans la base de dev :
|
||
|
||
```bash
|
||
./scripts/reload-prod-logs.sh # décalage auto
|
||
./scripts/reload-prod-logs.sh --days 7 # exporte les N derniers jours
|
||
./scripts/reload-prod-logs.sh --cron # mode silencieux (pour crontab)
|
||
```
|
||
|
||
### update-csv-data.sh — Mise à jour des données CSV
|
||
|
||
Télécharge et génère tous les fichiers CSV de référence (bot IPs, JA4, ASN) :
|
||
|
||
```bash
|
||
./scripts/update-csv-data.sh # génère tout
|
||
./scripts/update-csv-data.sh --install-stubs # copie aussi les stubs de test
|
||
```
|
||
|
||
---
|
||
|
||
## Schéma réseau récapitulatif
|
||
|
||
```
|
||
Trafic HTTPS/HTTP (port 80/443)
|
||
|
|
||
v
|
||
+-----------------+
|
||
| ja4ebpf | TC ingress hook -- L3/L4/L5 (SYN, TLS ClientHello)
|
||
| (eBPF CO-RE) | uprobe SSL_read -- L7 HTTPS (flux déchiffré)
|
||
| | kprobe tcp_recvmsg - L7 HTTP (port 80/8080)
|
||
+-----------------+
|
||
|
|
||
| INSERT batch (HTTP bulk)
|
||
v
|
||
+-----------------+ +------------------+
|
||
| ClickHouse |-- MV parse JSON -> | ja4_logs. |
|
||
| | | http_logs_raw |
|
||
| | | http_logs |
|
||
| |-- 6 MVs agg -----> | ja4_processing. |
|
||
| | | agg_*(x6) |
|
||
| | | ml_*(x2) |
|
||
+-----------------+ +------------------+
|
||
^
|
||
|
|
||
+-----------------+ SELECT view_ai_features
|
||
| bot-detector |<-- view_thesis_features
|
||
| (EIF+AE+XGB) |
|
||
| |--> INSERT ml_all_scores, ml_detected_anomalies
|
||
+-----------------+
|
||
+-----------------+
|
||
| dashboard |<-- ja4_processing.ml_*, agg_*, views
|
||
| (FastAPI) |<-- ja4_logs.http_logs
|
||
+-----------------+
|
||
```
|