docs(specs): integrate CM-WALL-EGRESS-2026-06 v0.1.0-draft + agent context

Spec stored under docs/specs/ for source of truth.

Module : WALL (paire complémentaire WALL↔MIND), compagnon de
CM-MESH-MPCIE-2026-06. Détection egress + corrélation menaces sur
Gondwana-Air.

Frontière R1/R2 intangible :
  R1 — métadonnées (flux, DNS, TLS-méta, IP-intel, NIDS) : licite
       sur accès ouvert, détection passive par défaut.
  R2 — contenu (TLS-break, DPI profonde, file-extract) : segments
       consentis/gérés UNIQUEMENT, opt-in journalisé.

Couches L0-L5 décrites avec outils ARM64 (Suricata 7.x, Zeek,
unbound+RPZ, goflow2/nfdump, feeds abuse.ch/ET/Spamhaus/MISP).

Contrainte ECH 2026 actée : SNI chiffré → poids sur L0 flux + L2
JA4 + L3 IP-intel + cadence, jamais sur SNI seul.

packages/secubox-egress/CLAUDE.md : agent context complet, DoD §1,
garde-fous §2 (R1/R2 intangible, OPAD, ECH-ready, secrets hors
TOML, LCEN), arborescence §3, TOML §4, API §5 (5 endpoints), NIDS
§6, .deb §7, ordre tâches §8, tests bench Maurienne §9.

Refus runtime câblé dans api.py : POST /wall/quarantine avec
regime=r2 + vlan=open_access_vlan → 403 (interception illicite).
Corrélation correlate.py exige multi_signal_threshold concordants
avant verdict quarantine (anti-faux-positif cloud-intel).
This commit is contained in:
CyberMind-FR 2026-06-02 11:13:44 +02:00
parent 8a853ba3e8
commit 948774f7fc
2 changed files with 551 additions and 0 deletions

View File

@ -0,0 +1,157 @@
# Détection egress & corrélation menaces — SecuBox-Deb (module WALL)
| | |
|---|---|
| **Réf.** | CM-WALL-EGRESS-2026-06 |
| **Module** | WALL (paire complémentaire **WALL↔MIND**) |
| **Compagnon de** | CM-MESH-MPCIE-2026-06 (plan RF / radios) |
| **Doctrine** | CM-WALL-OPAD-2026-05 (Off-Path Active Defense) |
| **Statut** | DRAFT |
| **Version** | v0.1.0-draft |
| **Date** | 2026-06-02 |
| **Programme** | Gondwana-Air — pilote Maurienne |
| **Licence** | LicenseRef-CMSD-1.0 (FR faisant foi) |
---
## 1. SITUATION
La passerelle SecuBox-Deb est le **point de vue privilégié** pour détecter, depuis les clients du mesh : intrusions, exfiltration (« évasions »), et trafic de commande-et-contrôle (C2) — y compris lorsqu'il se cache derrière des **providers cloud légitimes**.
Mais le réseau d'accès Gondwana-Air est **ouvert** (BYOH, public). Contrainte juridique structurante (LCEN, secret des correspondances) : **casser le TLS d'un usager anonyme = interception illicite.** Toute l'architecture se conçoit donc en **deux régimes séparés**.
---
## 2. MISSION
Détecter intrusion / exfil / C2 depuis les clients, **sans déchiffrer le contenu** sur l'accès ouvert ; réserver l'inspection de contenu aux segments consentis/gérés ; alimenter le **RDS** (rogue) et le **dashboard MIND** ; rester conforme **OPAD** (détection passive par défaut, réaction off-path opt-in, journalisée).
---
## 3. LES DEUX RÉGIMES (frontière non négociable)
| Régime | Périmètre | Licite sur accès ouvert | Posture |
|---|---|---|---|
| **R1 — Métadonnées** | flux, DNS, TLS-méta, IP-intel, signatures NIDS | **Oui** | détection passive par défaut |
| **R2 — Contenu (TLS-break / DPI profonde)** | déchiffrement, extraction fichiers | **Non** — segments **consentis/gérés** uniquement (quarantaine, honeypot, endpoints managés, infra de test) | régime restreint, opt-in explicite + traçabilité |
> **Invariant.** Le guardian/miroir sert à *voir* le MITM et l'exfil, et à *bloquer off-path* le rogue — **jamais à intercepter le contenu des usagers**. Sur l'ouvert : R1. Sur le consenti : R2.
---
## 4. COUCHES DE DÉTECTION (R1)
| # | Couche | Quoi détecter | Outil Debian ARM64 | OPAD |
|---|---|---|---|---|
| L0 | **Flux** | beaconing (périodicité), exfil volumique, destinations anormales | `conntrack`, NetFlow/IPFIX (`goflow2`/`nfdump`) | passif |
| L1 | **DNS** | DGA, DNS-tunneling, détection **DoH**, domaines malveillants | résolveur souverain (`unbound`/`knot`) + **RPZ** | passif (blocage RPZ = réaction off-path) |
| L2 | **TLS métadonnées** | empreinte **JA3/JA4** (stack cliente malware), issuer cert, SNI *(cf. ECH §6)* | **Suricata 7.x**, **Zeek** | passif |
| L3 | **IP / ASN / cloud-intel** | C2 hébergé sur clouds légitimes, fast-flux, infra connue | feeds **abuse.ch** (Feodo/SSLBL/ThreatFox), **ET Open**, Spamhaus DROP/EDROP, **MISP** | passif |
| L4 | **NIDS / NSM** | intrusion, latéralité, exfil, signatures | **Suricata** (IDS) / **Zeek** (logs conn/dns/ssl + intel framework + notice) | IDS passif ; **IPS inline = opt-in** |
| L5 | **Contenu** | payload malware, fichiers | Suricata file-extract, proxy **explicite** | **R2 — consenti only** |
---
## 5. CAS D'USAGE CIBLÉS
### 5.1 Évasions depuis les clients
Un client compromis menace les *autres* usagers et l'infra ; le détecter les protège.
- **Domain fronting / cloud-C2** — C2 logé sur AWS/Azure/GCP/Cloudflare/Fastly pour se fondre. → matching IP/ASN vs ThreatFox/Feodo + anomalie d'usage CDN. *(« providers cloud utilisés dans les attaques ».)*
- **DoH-C2 / DoT** — C2 dans du DNS chiffré. → détecter connexions vers résolveurs DoH connus + **forcer le DNS souverain** (RPZ).
- **DNS-tunneling** — entropie/longueur de sous-domaines, volume de requêtes.
- **Beaconing** — périodicité de flux (approche type RITA) ; **la cadence trahit le C2 même sur trafic chiffré**, sans lire le contenu.
### 5.2 Corrélation RDS (radio ↔ flux)
Signal composite : un **evil-twin détecté par le guardian-radio** (CM-MESH §4bis) **+** un client qui **beacon** vers une infra C2 = corrélation forte → escalade RDS, quarantaine off-path.
---
## 6. CONTRAINTE 2026 — ECH (Encrypted ClientHello) ⚠
ECH **chiffre le SNI** → la détection par nom d'hôte (L2 SNI) **s'effondre**.
**Conséquence de conception (à acter) :** déporter le poids de la détection sur **L0 flux + JA4 + L3 IP-intel + cadence (beaconing)**, indépendants du nom en clair. Ne pas bâtir la détection sur le SNI.
---
## 7. ARCHITECTURE SecuBox-Deb (module WALL)
### Pattern 3-broches
| Broche | Rôle |
|---|---|
| **CTL** | orchestration Suricata/Zeek/résolveur, gestion intel, décisions de réaction |
| **LXC** | isolation du plan d'inspection (capture en `netns` dédié, droits minimaux) |
| **BUNDLE** | `.deb` : moteurs NIDS + jeux de règles + feeds intel + RPZ + templates TOML |
### Consommateurs
- **RDS** — corrélation rogue-radio ↔ flux suspect.
- **MIND** (paire WALL↔MIND) — télémétrie flux/alertes vers le dashboard génératif (pipeline existant).
### Configuration TOML (extrait)
```toml
[wall.regime]
content_inspection = false # R2 désactivé par défaut (accès ouvert)
ips_inline = false # IDS passif par défaut ; inline = opt-in
[wall.flow]
ipfix = true
beaconing = true # détection de périodicité
[wall.dns]
resolver = "unbound"
rpz = true
doh_detect = true
[wall.tls]
ja4 = true
sni = "best_effort" # dégradé sous ECH (cf. §6)
[wall.intel]
feeds = ["abuse.ch/feodo", "abuse.ch/threatfox", "et-open", "spamhaus-drop"]
misp_url_ref = "file:///etc/secubox/secrets/misp"
[wall.nids]
engine = "suricata" # suricata | zeek | both
```
### API FastAPI / Uvicorn
```
GET /wall/flows # flux actifs + scores anomalie/beaconing
GET /wall/dns # requêtes, hits RPZ, suspicions tunneling/DoH
GET /wall/alerts # alertes NIDS
GET /wall/intel # état des feeds, derniers matchs cloud-C2
POST /wall/quarantine # quarantaine client (réaction off-path, journalisée)
```
### OPAD
Détection **passive par défaut** (IDS sur span/tap). Réaction **off-path, opt-in, journalisée** : RPZ block, drop nftables, **quarantaine VLAN**, steering. **IPS inline** et **R2** = opt-in explicite, tracés.
---
## 8. FRONTIÈRE LÉGALE (rappel opérationnel)
- **Accès ouvert****R1 (métadonnées) uniquement**. Conservation de logs conforme LCEN.
- **Contenu / TLS-break****R2** : seulement sur segment **consenti/géré/quarantaine** ou infra de test. Jamais en silence sur un usager.
- Le dispositif est **défensif** : détection + confinement d'un attaquant, pas interception de tiers.
---
## 9. POINTS OUVERTS
1. **ECH** — calibrer la bascule SNI→JA4/IP/cadence ; mesurer le taux de couverture résiduel.
2. **Charge sur Armada 7040** — Suricata/Zeek en ARM64 quad-A72 : dimensionner le débit inspectable (offload packet-processor 7040 ?).
3. **Fraîcheur intel** — cadence de mise à jour des feeds vs partitions mesh (nœuds isolés).
4. **Faux positifs cloud-intel** — un cloud légitime héberge bon et mauvais ; exiger corrélation multi-signaux avant quarantaine.
5. **Périmètre R2** — définir précisément les segments consentis (CGU portail, quarantaine) avant toute inspection de contenu.
---
*CyberMind — Gérald Kerma — Notre-Dame-du-Cruet (73130). Document interne, version FR faisant foi. LicenseRef-CMSD-1.0.*

View File

@ -0,0 +1,394 @@
# CLAUDE.md — module `secubox-egress`
> Emplacement cible : `packages/secubox-egress/CLAUDE.md`
> Réf. spec : CM-WALL-EGRESS-2026-06 **v0.1.0-draft** (2026-06-02) · Module : WALL ↔ MIND · Licence : LicenseRef-CMSD-1.0
> Spec complète : [`docs/specs/CM-WALL-EGRESS-2026-06.md`](../../docs/specs/CM-WALL-EGRESS-2026-06.md)
> Compagnon de : [`secubox-mesh`](../secubox-mesh/CLAUDE.md) (CM-MESH-MPCIE-2026-06)
Contexte opérationnel de l'agent pour construire le module **WALL/EGRESS** de SecuBox-Deb
(détection egress + corrélation menaces : exfil, C2, beaconing, evil-twin↔flux). Lis tout avant d'agir.
---
## 0. Contexte agent
Conventions héritées de `secubox-deb` (ne PAS dévier) :
- Plan de contrôle : **FastAPI + Uvicorn**. Jamais de RPCD.
- Config : **TOML** (`tomllib`), lecture seule au runtime.
- Packaging : **`.deb`/`apt`**, `debhelper` (`dh`).
- Pattern **3-broches** : CTL / LXC / BUNDLE.
- Mapping : **WALL↔MIND** (alimenter le dashboard génératif).
- Doctrine **OPAD** : détection passive par défaut, réaction off-path opt-in, journalisée.
---
## 1. Definition of Done
Le module est terminé quand TOUT ce qui suit est vrai :
1. `apt build` produit un `.deb` installable (`secubox-egress_*.deb`), lintian sans blocage.
2. `systemctl status secubox-egress` actif, Uvicorn écoute en local (port dédié).
3. Les 5 endpoints répondent (cf. §5).
4. La config se charge depuis `/etc/secubox/egress.toml` ; secrets hors TOML.
5. **R1 (métadonnées) actif par défaut** ; **R2 (contenu) désactivé** ; `ips_inline = false`.
6. Suricata OU Zeek tourne en mode IDS passif (`engine = suricata|zeek|both`), capture sur span/tap dédié.
7. `unbound` souverain + RPZ chargé ; détection DoH active.
8. Feeds intel (abuse.ch Feodo/ThreatFox, ET Open, Spamhaus DROP/EDROP) téléchargés + intégrés en mémoire.
9. En-têtes `LicenseRef-CMSD-1.0` sur chaque fichier source.
---
## 2. Garde-fous (NON négociables)
### 2.1 Frontière R1/R2 — INTANGIBLE
- **Sur accès ouvert (BYOH, public)** : R1 uniquement (métadonnées : flux, DNS, TLS-méta, IP-intel, NIDS signatures).
- **R2 (TLS-break / inspection de contenu)** : autorisé UNIQUEMENT sur segments **consentis/gérés** (quarantaine, honeypot, endpoints managés, infra de test). Toute activation R2 doit :
- être déclenchée par appel API authentifié explicite,
- être journalisée immuablement,
- cibler un VLAN/segment dont le consentement est tracé (référence CGU/quarantaine).
- **Jamais de TLS-break en silence sur un usager du réseau ouvert.** Le module DOIT refuser d'activer R2 sur le VLAN de l'accès ouvert (validation TOML + runtime).
### 2.2 OPAD
- **Détection passive par défaut** (IDS sur span/tap, pas inline).
- **Réaction off-path, opt-in, journalisée** : RPZ block, drop nftables, quarantaine VLAN, steering.
- **IPS inline** = opt-in explicite, tracé.
- Pas d'auto-quarantaine sur un seul signal — exiger corrélation multi-signaux (§9 point 4 de la spec).
### 2.3 ECH-readiness
ECH (Encrypted ClientHello) chiffre le SNI. Le module NE DOIT PAS bâtir ses détections sur le seul SNI. **Poids principal** sur :
- **L0 flux** (cadence/beaconing)
- **L2 JA4** (empreinte TLS cliente, indépendante du SNI)
- **L3 IP/ASN/cloud-intel**
SNI = `best_effort` dégradé en TOML, jamais critère unique de décision.
### 2.4 Secrets / Intel
- Clés MISP, tokens feeds privés : `misp_url_ref` et `feeds.X.token_ref` = `file://` ou `vault://`, jamais en clair dans le TOML.
- Feeds publics (abuse.ch, ET Open, Spamhaus DROP) : pas de secret, juste URL + hash de pinning optionnel.
### 2.5 Légalité (LCEN)
- Conservation logs R1 conforme à la durée légale.
- Pas d'exfiltration de données R1 vers un tiers sans base légale documentée.
- Documenter dans le `README.md` du package les bases juridiques d'opération.
---
## 3. Arborescence à créer
```
packages/secubox-egress/
├── CLAUDE.md # ce fichier
├── pyproject.toml
├── secubox_egress/
│ ├── __init__.py
│ ├── api.py # router FastAPI (CTL)
│ ├── models.py # schémas pydantic
│ ├── config.py # loader TOML + résolution secrets
│ ├── flow.py # L0 : conntrack/IPFIX + détection beaconing (RITA-like)
│ ├── dns.py # L1 : unbound + RPZ + détection DoH/DGA/tunneling
│ ├── tls_meta.py # L2 : JA3/JA4 + issuer cert (+ SNI dégradé sous ECH)
│ ├── intel.py # L3 : ingestion feeds (abuse.ch/ET/Spamhaus/MISP)
│ ├── nids.py # L4 : Suricata/Zeek control plane
│ ├── correlate.py # corrélation RDS (radio↔flux), multi-signaux
│ └── react.py # OPAD réactions off-path (quarantaine VLAN, drop, RPZ)
├── conf/
│ ├── egress.toml # template TOML (BUNDLE)
│ ├── unbound-rpz.conf.j2
│ ├── suricata.yaml.j2
│ └── zeek-local.zeek.j2
├── rules/
│ ├── feodo.rules.example # placeholder ; vrais feeds téléchargés au runtime
│ └── threatfox.rules.example
├── systemd/
│ └── secubox-egress.service
└── debian/
├── control
├── rules
├── changelog
├── compat
├── secubox-egress.postinst
└── secubox-egress.install
```
---
## 4. Schéma TOML (`conf/egress.toml`)
```toml
# /etc/secubox/egress.toml — LicenseRef-CMSD-1.0
schema_version = 1
[wall.regime]
content_inspection = false # R2 désactivé par défaut (accès ouvert)
ips_inline = false # IDS passif par défaut ; inline = opt-in
open_access_vlan = 100 # VLAN de l'accès ouvert (R2 INTERDIT dessus)
[wall.flow]
ipfix = true
ipfix_port = 4739
beaconing = true # détection de périodicité (RITA-like)
beaconing_min_samples = 32 # nombre min de flux avant scoring
[wall.dns]
resolver = "unbound"
rpz = true
rpz_zones = ["malware.rpz", "phishing.rpz"]
doh_detect = true
[wall.tls]
ja4 = true
sni = "best_effort" # dégradé sous ECH (cf. §6 spec)
[wall.intel]
feeds = [
"abuse.ch/feodo",
"abuse.ch/threatfox",
"abuse.ch/sslbl",
"et-open",
"spamhaus-drop",
]
refresh_interval_s = 3600
misp_url_ref = "file:///etc/secubox/secrets/misp" # JAMAIS en clair
[wall.nids]
engine = "suricata" # suricata | zeek | both
capture_iface = "wlan-bh" # span/tap du backhaul mesh
[wall.react]
quarantine_vlan = 99 # VLAN de quarantaine (consenti, OK pour R2)
multi_signal_threshold = 2 # nb min de signaux concordants avant auto-quarantaine
[opad]
reactive = false # passif par défaut
```
---
## 5. Contrat API (FastAPI — `api.py`)
| Méthode | Route | Rôle |
|---|---|---|
| GET | `/wall/flows` | flux actifs + scores anomalie/beaconing |
| GET | `/wall/dns` | requêtes, hits RPZ, suspicions tunneling/DoH |
| GET | `/wall/alerts` | alertes NIDS (Suricata/Zeek) |
| GET | `/wall/intel` | état des feeds, derniers matchs cloud-C2 |
| POST | `/wall/quarantine` | quarantaine client (réaction off-path, journalisée) |
Réponses typées pydantic. Pas d'I/O bloquante dans le handler — `asyncio.to_thread` pour les wrappers `subprocess` / lecteurs IPFIX.
### Stub `api.py`
```python
# packages/secubox-egress/secubox_egress/api.py — LicenseRef-CMSD-1.0
from __future__ import annotations
import asyncio
from fastapi import APIRouter, HTTPException
from .config import load_config
from .models import Flow, DNSEvent, Alert, IntelStatus, QuarantineRequest
from . import flow, dns, nids, intel, react
router = APIRouter(prefix="/wall", tags=["egress"])
_cfg = load_config() # /etc/secubox/egress.toml
@router.get("/flows", response_model=list[Flow])
async def flows() -> list[Flow]:
return await asyncio.to_thread(flow.list_flows, _cfg)
@router.get("/dns", response_model=list[DNSEvent])
async def dns_events() -> list[DNSEvent]:
return await asyncio.to_thread(dns.recent_events, _cfg)
@router.get("/alerts", response_model=list[Alert])
async def alerts() -> list[Alert]:
return await asyncio.to_thread(nids.list_alerts, _cfg)
@router.get("/intel", response_model=IntelStatus)
async def intel_status() -> IntelStatus:
return await asyncio.to_thread(intel.status, _cfg)
@router.post("/quarantine")
async def quarantine(req: QuarantineRequest) -> dict:
# OPAD : action off-path, journalisée.
# Refuse R2 (TLS-break) sur VLAN de l'accès ouvert.
if req.regime == "r2" and req.vlan == _cfg.wall.regime.open_access_vlan:
raise HTTPException(403, "R2 interdit sur le VLAN de l'accès ouvert")
return await asyncio.to_thread(react.quarantine, req, _cfg)
```
### Stub `correlate.py` (corrélation RDS multi-signaux)
```python
# secubox_egress/correlate.py — LicenseRef-CMSD-1.0
"""
Corrélation RDS : un signal n'est PAS suffisant.
Exige multi_signal_threshold signaux concordants pour escalader vers
quarantaine. Pondère par fraîcheur de l'intel et par confiance source.
"""
from __future__ import annotations
import logging
from .models import Signal, Verdict
log = logging.getLogger("secubox.egress.correlate")
def correlate(signals: list[Signal], cfg) -> Verdict:
"""
Inputs typés :
- radio : evil-twin détecté par guardian-radio (CM-MESH §4bis)
- flow : beaconing périodique
- dns : RPZ hit ou suspicion DoH/tunneling
- intel : match cloud-C2 (ASN/IP/JA4)
"""
fresh = [s for s in signals if s.is_fresh()]
if len(fresh) < cfg.wall.react.multi_signal_threshold:
return Verdict(action="observe", reason="single-signal, OPAD passif")
log.info("Multi-signal verdict: %d signaux concordants", len(fresh))
return Verdict(
action="quarantine",
reason=f"corrélation {[s.kind for s in fresh]}",
signals=fresh,
)
```
---
## 6. NIDS — Suricata / Zeek
### Suricata 7.x
- Mode IDS passif (`af-packet` sur l'interface de capture, pas `nfq`).
- Règles : ET Open Ruleset + custom rules ingérées depuis `wall.intel.feeds`.
- `eve.json` consommé par `nids.py` pour exposer `/wall/alerts`.
- JA4 activé via `tls.fingerprint.ja4` (Suricata 7.0+).
### Zeek (alternative)
- Logs `conn.log` / `dns.log` / `ssl.log` / `notice.log` consommés.
- Intel framework chargé avec les feeds.
- Plus de flexibilité scripting, charge CPU souvent meilleure que Suricata sur ARM64.
Le choix se fait via `wall.nids.engine = suricata | zeek | both`. Les deux peuvent tourner en parallèle si la charge le permet (Armada 7040 quad-A72 — point ouvert §9 spec).
---
## 7. Packaging `.deb`
### `debian/control`
```
Source: secubox-egress
Section: net
Priority: optional
Maintainer: Gérald Kerma <root@cybermind.fr>
Build-Depends: debhelper-compat (= 13), dh-python, python3-all
Standards-Version: 4.6.2
Package: secubox-egress
Architecture: arm64
Depends: ${python3:Depends}, ${misc:Depends},
python3-fastapi, python3-uvicorn, python3-jinja2,
python3-aiohttp, python3-yaml,
suricata, zeek, unbound, conntrack, nftables,
nfdump, goflow2 | nfacctd
Recommends: misp-modules, python3-pymisp
Description: SecuBox-Deb EGRESS module — flow/DNS/TLS-meta/NIDS detection + RDS correlation (OPAD)
EOF
```
### `debian/secubox-egress.postinst`
```bash
#!/bin/sh
set -e
case "$1" in
configure)
install -d -m 0700 /etc/secubox/secrets
install -d -m 0755 /var/lib/secubox/egress/intel
install -d -m 0755 /var/lib/secubox/egress/rpz
deb-systemd-helper enable secubox-egress.service >/dev/null || true
deb-systemd-invoke start secubox-egress.service >/dev/null || true
;;
esac
#DEBHELPER#
```
### `systemd/secubox-egress.service`
```ini
[Unit]
Description=SecuBox-Deb EGRESS control plane (flow + DNS + NIDS + intel)
After=network.target suricata.service unbound.service
Wants=suricata.service unbound.service
[Service]
ExecStart=/usr/bin/uvicorn secubox_egress.app:app --host 127.0.0.1 --port 8745
Restart=on-failure
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/run /var/lib/secubox/egress /etc/secubox
[Install]
WantedBy=multi-user.target
```
---
## 8. Ordre des tâches
1. Échafauder l'arborescence (§3) + `pyproject.toml` + licences.
2. `models.py` (Flow, DNSEvent, Alert, Intel, Signal, Verdict, QuarantineRequest) + `config.py` (loader TOML + résolution secrets).
3. `intel.py` (ingestion feeds, refresh background, cache local sous `/var/lib/secubox/egress/intel/`).
4. `dns.py` (unbound + RPZ + DoH detection via known-resolver IP list).
5. `flow.py` (NetFlow/IPFIX collector via goflow2 ou nfacctd, scoring beaconing RITA-like).
6. `tls_meta.py` (JA3/JA4 depuis Suricata `eve.json`).
7. `nids.py` (control plane Suricata/Zeek, parse `eve.json` / Zeek logs).
8. `correlate.py` (corrélation multi-signaux + verdict OPAD).
9. `react.py` (quarantaine VLAN via nftables, RPZ block, drop targeted).
10. `api.py` (5 endpoints, `to_thread`, validation R2-not-on-open-access).
11. `debian/` + unit ; build `.deb` ; lintian.
12. Tests DoD §1 sur banc Maurienne.
---
## 9. Tests d'acceptation (bench Maurienne)
- **Beaconing** : générer un flux périodique vers une IP de test, vérifier détection après ≥ `beaconing_min_samples` flux.
- **DoH detection** : forcer un client à `1.1.1.1:443` via DoH, vérifier alerte `wall.dns.doh_detect`.
- **DNS tunneling** : pousser des requêtes à entropie élevée vers un domaine test, vérifier alerte.
- **Intel match** : injecter une IP du feed Feodo dans le flux, vérifier hit + alerte.
- **Corrélation RDS** : simuler un evil-twin (signal radio) + un client beacon (signal flow) → vérifier `correlate.correlate()` renvoie `action=quarantine`.
- **R2 refus** : POST `/wall/quarantine` avec `regime=r2, vlan=open_access_vlan` → 403.
- **ECH** : simuler un client ECH (SNI chiffré), vérifier que la détection bascule sur JA4 + IP-intel sans s'effondrer.
---
## 10. Hors périmètre (NE PAS faire)
- **TLS-break sur l'accès ouvert** (R2 réservé aux segments consentis).
- App cliente (séparée).
- Couche L3 MirrorNet / `did:plc` / HamCoin (consommateur en aval, pas dans ce module).
- Détection bâtie sur le SNI seul (ECH le casse — §6 spec).
- Quarantaine sur signal unique (corrélation multi-signaux requise).
- Stocker les payloads R1 en clair (métadonnées uniquement, conformément LCEN).
---
## 11. Points ouverts (à instrumenter avant gel CSPN)
Repris du §9 de la spec :
1. **ECH** — calibrer la bascule SNI→JA4/IP/cadence ; mesurer le taux de couverture résiduel.
2. **Charge sur Armada 7040** — dimensionner le débit inspectable.
3. **Fraîcheur intel** — cadence de refresh vs partitions mesh (nœuds isolés).
4. **Faux positifs cloud-intel** — exiger corrélation multi-signaux (déjà câblé dans `correlate.py`).
5. **Périmètre R2** — définir précisément les segments consentis avant toute activation.
---
*CyberMind — Gérald Kerma. Document interne, FR faisant foi. LicenseRef-CMSD-1.0.*