Agent integrity monitoring
De hub draait elke 10 minuten een IntegrityCheckWorker over alle actieve
agents. Hij genereert geen extra netwerk-verkeer naar de agents — het is een
puur server-side analyse van wat er al binnenkwam.
Wat wordt gecontroleerd
| Kind | Detectie | Severity |
|---|---|---|
unsigned_payload | Ingest zonder X-Monsys-Signature header (of agent zonder pinned pubkey) | medium / high |
signature_invalid | Sig faalt verificatie tegen pinned pubkey | critical |
clock_drift | Gemiddelde abs(captured_at − server_now) > 5 min over laatste 20 metrics | high |
cadence_anomaly | Mediaan tussen-ingest-gap buiten [7s, 23s] (verwacht 15s) | medium |
flat_metrics | CPU stddev < 0.001 over 30+ samples in 1u | high |
version_downgrade | Agent_version semver-lager dan eerder gezien | high |
Open / resolved model
integrity_anomalies is append-only voor de hub-app user (alleen INSERT
en UPDATE; DELETE/TRUNCATE is geRevokte privileges). Elk findings bestaat in
één van twee states:
- open —
resolved_at IS NULL - resolved — admin heeft “markeer resolved” geklikt of de check passeert weer in de volgende cyclus
Resolved items blijven bewaard als audit trail. Een auditor kan per agent exact zien wanneer welke afwijking is geconstateerd én wie/wanneer het gesloten heeft.
Dashboard
/integrity toont 6 KPI cards (één per kind) met aantal open items. De
tabel eronder geeft severity, agent (klikbaar), summary, raw-detail JSON,
detection-tijd en een resolve-knop.
Voorbeelden
Voorbeeld 1: signature_invalid bij gestolen token
Aanvaller stal ms_... token, probeert metrics te pushen vanaf eigen machine
zonder de signing key:
POST /api/v1/ingest Authorization: Bearer ms_<gestolen> Content-Type: application/json (geen X-Monsys-Signature)
→ 403 Forbidden→ integrity_anomalies row: kind: unsigned_payload severity: high summary: agent has a pinned signing_pubkey but sent no X-Monsys-Signature detected_at: 2026-05-09 22:03:40Het verschijnt op /integrity, kleurt rood in de KPI strip, en de admin
ziet binnen 30 sec via SWR refresh een open critical alert.
Voorbeeld 2: flat_metrics — agent stuurt fake telemetrie
Een aanvaller met root op de host vervangt de echte metrics-collector door een script dat constant CPU=4.20% stuurt:
SELECT STDDEV_SAMP(cpu_usage_percent), COUNT(*)FROM metricsWHERE agent_id = $1 AND time > NOW() - INTERVAL '1 hour';-- stddev: 0.000 (over 240 samples) → flat_metrics anomalyDe worker upsert na 10 min:
kind: flat_metricsseverity: highsummary: CPU stddev = 0 over het laatste uur — telemetrie lijkt gemanipuleerddetail: {"samples": 240, "stddev": 0.0}SQL voor de auditor
-- Alle open anomalies per agent, gesorteerd op severitySELECT a.name, ia.kind, ia.severity, ia.summary, ia.detected_at FROM integrity_anomalies ia JOIN agents a ON a.id = ia.agent_id WHERE ia.resolved_at IS NULL ORDER BY CASE ia.severity WHEN 'critical' THEN 1 WHEN 'high' THEN 2 WHEN 'medium' THEN 3 WHEN 'low' THEN 4 ELSE 5 END, ia.detected_at DESC;
-- Hoeveel resolved items per kind in de laatste 30 dagen?SELECT kind, count(*) FROM integrity_anomalies WHERE resolved_at > NOW() - INTERVAL '30 days' GROUP BY kind;
-- Wie heeft welk item gesloten?SELECT u.email, ia.kind, ia.summary, ia.resolved_at FROM integrity_anomalies ia JOIN users u ON u.id = ia.resolved_by WHERE ia.resolved_at > NOW() - INTERVAL '30 days' ORDER BY ia.resolved_at DESC;Beperkingen
flat_metricsheeft een minimum van 30 samples nodig — agents die net gestart zijn vallen tot 7-8 min onder de detectie-drempel.clock_driftgebruikt het hub-tijdstempel als referentie. Een aanvaller die ook de hub-host compromitteert (clock manipulatie) ontwijkt deze check.version_downgradeherkent alleen semver-stijl0.x.y. Build-suffixes als0.1.0-beta1worden voor 0.1.0 als gelijk beschouwd.