Ga naar inhoud

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

KindDetectieSeverity
unsigned_payloadIngest zonder X-Monsys-Signature header (of agent zonder pinned pubkey)medium / high
signature_invalidSig faalt verificatie tegen pinned pubkeycritical
clock_driftGemiddelde abs(captured_at − server_now) > 5 min over laatste 20 metricshigh
cadence_anomalyMediaan tussen-ingest-gap buiten [7s, 23s] (verwacht 15s)medium
flat_metricsCPU stddev < 0.001 over 30+ samples in 1uhigh
version_downgradeAgent_version semver-lager dan eerder gezienhigh

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:

  • openresolved_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:40

Het 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 metrics
WHERE agent_id = $1 AND time > NOW() - INTERVAL '1 hour';
-- stddev: 0.000 (over 240 samples) → flat_metrics anomaly

De worker upsert na 10 min:

kind: flat_metrics
severity: high
summary: CPU stddev = 0 over het laatste uur — telemetrie lijkt gemanipuleerd
detail: {"samples": 240, "stddev": 0.0}

SQL voor de auditor

-- Alle open anomalies per agent, gesorteerd op severity
SELECT 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_metrics heeft een minimum van 30 samples nodig — agents die net gestart zijn vallen tot 7-8 min onder de detectie-drempel.
  • clock_drift gebruikt het hub-tijdstempel als referentie. Een aanvaller die ook de hub-host compromitteert (clock manipulatie) ontwijkt deze check.
  • version_downgrade herkent alleen semver-stijl 0.x.y. Build-suffixes als 0.1.0-beta1 worden voor 0.1.0 als gelijk beschouwd.