Corrélations SMART : comment 15 pipelines indépendants deviennent une vue priorisée
Des alertes isolées sont une machine à tickets. La vraie menace vit dans la combinaison. Comment monsys connecte CVE scanning, honeypots, capacity et process DNA via des corrélations SMART.
Une plateforme de monitoring qui ne fait que balancer des alertes est une machine à tickets. Chaque pipeline — matching CVE, honeypots, capacity, kernel tracker, integrity — produit ses propres signaux, mais la vraie menace vit presque toujours dans la combinaison.
Voici comment monsys connecte ces pipelines via des corrélations SMART.
Le problème des pipelines isolés
Imaginons : vous avez trois événements sur le même serveur en dix minutes :
- Une CVE de sévérité Medium sur un package npm (
axios@0.27.2, GHSA-2025-xxxx) - Une alerte capacity disque : 89 % plein, plein prévu dans 4 heures
- Une déviation Process DNA :
/usr/bin/nodea un hash inconnu
Isolément : la CVE Medium est low priority. Le disque plein est opérationnel. Process DNA est suspect mais peut-être un auto-update.
Ensemble : une binaire Node silencieusement remplacée, combinée à une activité disque anormale et une dépendance vulnérable dans le même processus, c'est un incident actif.
Les corrélations SMART construisent ces liens automatiquement.
Architecture : une seule table signal_streams
Tous les pipelines écrivent dans la même hypertable via une interface Go uniforme :
emitter.Emit(ctx, tenantID, signals.Signal{
Source: "process_dna", // ou "cve_match", "honeypot", "capacity", ...
SubjectType: "agent",
SubjectID: agentID,
Key: "binary.hash_mismatch",
Value: map[string]any{
"exe_path": "/usr/bin/node",
"baseline_hash": "a3f2c1...",
"observed_hash": "b7e4d2...",
},
Severity: signals.SeverityCritical,
ObservedAt: time.Now().UTC(),
})
Tout worker qui veut ajouter un nouveau type de corrélation n'a qu'à mettre à jour SourceToCategory et placer un appel Emit(). Le reste de l'infrastructure (dashboards, Trust Score, evidence packs, alertes) le capte automatiquement.
Les neuf workers de corrélation
1. Priorisation CVE par blast-radius
Toutes les CVE ne sont pas aussi urgentes. Une Critical sur un serveur connecté à rien est moins aiguë qu'une Medium sur un load balancer derrière lequel 40 services de production sont exposés.
Le CapacityPredictorWorker (cadence 1h) fait un Breadth-First Search sur le graphe de topologie pour calculer la distance en hops de chaque nœud au point d'entrée Internet le plus proche :
GET /api/v1/topology/exposure?map_id=<id>
Response:
{
"nodes": [
{ "agent_id": "web-edge-01", "internet_hops": 0, "exposure_score": 1.0 },
{ "agent_id": "api-server-03", "internet_hops": 1, "exposure_score": 0.7 },
{ "agent_id": "db-primary", "internet_hops": 2, "exposure_score": 0.4 }
]
}
Les recommandations CVE sont réordonnées sur cvss_base × exposure_score × epss_probability. Une CVSS 7.5 sur le serveur de base de données avec EPSS 0.02 marque moins qu'une CVSS 5.5 sur le serveur edge avec EPSS 0.34.
2. Capacity-comme-CVE
Disque plein sonne opérationnel, pas sécurité. Mais un serveur dont le disque est plein à 100 % ne peut plus écrire de logs, créer de core dumps, ou démarrer des outils de sécurité. C'est une condition sécurité.
Le worker fitte une régression linéaire dans Postgres :
SELECT
regr_slope(disk_used_pct, EXTRACT(EPOCH FROM observed_at)) AS slope,
regr_intercept(disk_used_pct, EXTRACT(EPOCH FROM observed_at)) AS intercept,
regr_r2(disk_used_pct, EXTRACT(EPOCH FROM observed_at)) AS r2
FROM agent_metrics
WHERE agent_id = $1
AND mount_point = $2
AND observed_at > NOW() - INTERVAL '30 days'
Sur la base de slope et intercept, on calcule quand le disque atteindra 100 %. C'est émis comme un finding capacity.disk_full, traité comme une vulnérabilité avec deadline.
3. Détection de mouvement latéral
C'est la corrélation qui surprend le plus souvent en démo :
-- LateralMovementWorker, cadence 60s
SELECT
hp.agent_id AS source_agent,
hp.canary_path,
ae.target_agent_id,
ae.auth_user,
ae.src_ip,
ae.observed_at
FROM honeypot_events hp
JOIN auth_events ae
ON ae.src_ip IN (
SELECT ip_address FROM agent_ips WHERE agent_id = hp.agent_id
)
AND ae.observed_at BETWEEN hp.observed_at - INTERVAL '5 min'
AND hp.observed_at + INTERVAL '5 min'
AND ae.success = true
AND ae.auth_type = 'ssh'
WHERE hp.tenant_id = $1
AND hp.observed_at > NOW() - INTERVAL '70 seconds'
Un trigger honeypot sur le serveur A suivi d'une connexion SSH réussie depuis le serveur A vers le serveur B émet un événement lateral_movement_suspected avec les tags MITRE T1021 (Remote Services) et T1078 (Valid Accounts). Les deux événements sont liés dans le record de détection — la trace forensique est déjà prête.
4. Alertes érosion de conformité
La conformité n'est pas un point statique — elle s'érode silencieusement quand des workers crashent, des clés expirent, ou la génération de preuves échoue.
-- ComplianceErosionWorker, cadence 24h
INSERT INTO compliance_evidence_history (tenant_id, control_id, evidence_count, snapshot_date)
SELECT tenant_id, control_id, COUNT(*), CURRENT_DATE
FROM compliance_evidence
GROUP BY tenant_id, control_id;
-- Alerte si perte > 50 % vs il y a 7 jours
SELECT
h1.control_id,
h1.evidence_count AS current_count,
h7.evidence_count AS week_ago_count,
(1.0 - h1.evidence_count::float / NULLIF(h7.evidence_count, 0)) AS loss_rate
FROM compliance_evidence_history h1
JOIN compliance_evidence_history h7
ON h1.control_id = h7.control_id
AND h7.snapshot_date = CURRENT_DATE - INTERVAL '7 days'
WHERE h1.snapshot_date = CURRENT_DATE
AND (1.0 - h1.evidence_count::float / NULLIF(h7.evidence_count, 0)) > 0.5
Cela capte des situations qui ne génèrent pas d'alertes mais constituent un problème de conformité : un worker de backup qui s'est arrêté silencieusement, un scanner de certificats qui échoue, un pipeline de logs qui se vide.
5. Trust Score pondéré par centralité
Le Trust Score (0-100) est une moyenne pondérée sur 8 catégories de conformité. Mais tous les agents ne pèsent pas pareil. Un serveur chokepoint (load balancer, VPN gateway, database) qui tombe a un impact plus grand qu'un nœud feuille.
CentralityRefreshWorker (horaire) :
→ Calculer betweenness centrality (algo de Brandes) sur topology_edges
→ Persister dans topology_node_centrality
→ Le Trust Score pondère chaque agent par (1 + centrality)
→ centrality max ≈ 1.0 → un chokepoint compte jusqu'à 2× plus
Un serveur avec une centralité 0.8 qui a un contrôle de conformité en échec fait baisser le Trust Score plus que le même contrôle en échec sur un nœud feuille. Les SPOFs sont automatiquement pondérés plus lourdement.
6. Apprentissage des faux positifs
Toute règle de détection qui est acquittée dans les 5 minutes plus de 50 % du temps est probablement réglée trop agressivement.
GET /api/v1/detection/rules/flake-stats
Response:
[
{
"rule_id": "cpu_threshold_prod",
"fires_30d": 84,
"quick_ack_30d": 52,
"flake_rate": 0.619,
"opinion": "Montez le seuil de 85 % à 92 %, ou ajoutez un filtre durée : CPU>85 % pendant >15min"
}
]
C'est piloté par l'opérateur : la suggestion est affichée, jamais appliquée automatiquement. Les auditeurs veulent des règles reproductibles et approuvées par un humain — pas un système qui s'ajuste tout seul.
7. Time-machine diff
L'enquête forensique commence presque toujours par : « qu'est-ce qui a changé entre lundi et vendredi ? »
GET /api/v1/time-machine/diff?agent_id=web-edge-01&from=2026-05-19T00:00:00Z&to=2026-05-23T23:59:59Z
Response:
{
"packages": {
"added": ["libssl3 3.0.15-1"],
"removed": [],
"upgraded": [
{ "name": "openssl", "from": "3.0.13-1", "to": "3.0.15-1" }
]
},
"services": {
"added": ["monsys-agent"],
"removed": ["rsync"]
},
"kernel": { "from": "6.8.0-51", "to": "6.8.0-55" },
"open_ports": {
"added": [{ "port": 9100, "process": "node_exporter" }],
"removed": []
}
}
Un appel API donne une timeline forensique de tous les changements d'inventaire. Plus de comparaison manuelle de fichiers de log.
Comment les corrélations influencent le Trust Score
Le Trust Score (0-100) reflète la sortie combinée de tous les pipelines. Quelques exemples de l'impact des corrélations :
| Événement | Impact sur le score |
|---|---|
| Mouvement latéral détecté (non acquitté) | -15 à -25 points (selon la centralité des nœuds concernés) |
| Érosion de conformité > 50 % sur ISO 27001 A.8.7 | -8 points par contrôle en échec |
| CVE Critical sur nœud internet-facing (EPSS > 0.1) | -12 points |
| Mismatch Process DNA non résolu > 24h | -10 points |
| Tous les canaries honeypot intacts | +5 points (signal positif) |
Le score est reproductible via inputs_hash dans l'evidence pack — un auditeur peut recalculer pourquoi le score était X un jour donné.
Implications opérationnelles
Les workers de corrélation ajoutent un peu de charge à la base de données du hub. Notes opérationnelles :
LateralMovementWorker(60s) est le plus lourd : JOIN sur deux tables avec time window. Optimisé via un index composite sur(tenant_id, src_ip, observed_at)surauth_events.- Tous les workers sont idempotents : ils peuvent être relancés sans générer d'événements dupliqués.
- Un cold-start delay de 2-5 minutes après redémarrage du hub évite que des requêtes lourdes ne se déclenchent pendant que la base est encore en warmup.
Ce que cela signifie en pratique
Sans corrélations : trois alertes séparées, chacune triée séparément par un analyste, conclusion incertaine.
Avec corrélations : un seul événement de détection lateral_movement_suspected avec le contexte forensique complet — quel honeypot a été déclenché, quelle connexion SSH a suivi, sur quels serveurs, avec quel utilisateur. L'analyste n'a pas à corréler — le système l'a fait.
C'est la différence entre une machine à tickets et une plateforme de monitoring.
Les corrélations SMART sont documentées dans docs.monsys.ai/fr/security/smart-correlations. Les cinq premiers serveurs gratuits : monsys.ai/fr/signup.