Ga naar inhoud

Auditor — evidence ophalen en verifiëren

Deze pagina veronderstelt dat de auditor een eigen account heeft in /auditor met read-only scope. De cliënt geeft géén shell-access en géén dashboard-admin — alle evidence is signed en offline verifieerbaar.

1. Kwartaalaudit NIS2 — wat heb ik

In het dashboard

  1. Login als auditor in /auditor → Sidebar → Audit Packs
  2. Download .jsonl.gz + .pdf + .sig voor de maand
  3. Klik ‘Download verify-CLI’ om de offline verifier op te halen
  4. Run CLI tegen pubkey — krijgt vier groene checkmarks

Open /audit-packs. Je ziet één rij per maand voor de gekozen tenant. Download:

  • 2026-04.jsonl.gz — alle ruwe events (machine-leesbaar)
  • 2026-04.pdf — human-readable rapport, 12-15 pagina’s
  • 2026-04.sig — Ed25519-handtekening over manifest_hash

Verifieer lokaal (geen netwerk-roundtrip naar monsys):

Of via API (geavanceerd — voor automatisering)

Terminal window
wget https://get.monsys.ai/monsys-verify-eat-linux-x64
chmod +x monsys-verify-eat-linux-x64
./monsys-verify-eat-linux-x64 verify-pack \
--pack 2026-04.jsonl.gz \
--sig 2026-04.sig \
--pubkey https://transparency.monsys.ai/pubkeys/hub.pub

Wat de CLI checkt:

  1. Berekent manifest_hash = sha256(manifest) — moet matchen met .sig-inhoud
  2. Loopt door elke regel in JSONL.gz, ketent sha256 → moet eindigen op hash_chain_root in de manifest
  3. Verifieert Ed25519-signature met de gepubliceerde hub-pubkey

Output bij succes:

✓ manifest_hash matches signature
✓ hash chain root matches manifest
✓ Ed25519 signature valid against pubkey 7c34a9e2b1f0…
✓ 1247 entries in pack, 0 tampered

2. Bewijs dat CVE-2026-XXXX binnen 7 dagen gepatched is

In het dashboard

  1. Sidebar → Kernel CVE’s → zoek CVE-2026-XXXX
  2. Tab ‘Tijdlijn’ toont per host: detected, patched, operator
  3. Filter ‘Time to patch > 7 days’ isoleert SLA-breaches
  4. Knop ‘Export voor audit’ → CSV met alle kolommen

Drie vragen voor de auditor:

  1. Wanneer is de CVE eerst gedetecteerd?
  2. Wanneer is hij gepatched per host?
  3. Wie heeft de actie uitgevoerd?

In één SQL-rapport:

Of via API (geavanceerd — voor automatisering)

WITH first_detected AS (
SELECT agent_id, MIN(detected_at) AS first_seen
FROM kernel_cve_findings
WHERE tenant_id = $1::UUID AND cve_id = 'CVE-2026-XXXX'
GROUP BY agent_id
),
patched AS (
SELECT r.agent_id, MIN(r.boot_time) AS rebooted_at, r.eat_id
FROM kernel_reboot_history r
JOIN first_detected fd ON fd.agent_id = r.agent_id
WHERE r.tenant_id = $1::UUID
AND r.expected = true
AND r.boot_time > fd.first_seen
GROUP BY r.agent_id, r.eat_id
)
SELECT a.hostname,
fd.first_seen,
p.rebooted_at,
p.rebooted_at - fd.first_seen AS time_to_patch,
u.email AS operator
FROM first_detected fd
LEFT JOIN patched p ON p.agent_id = fd.agent_id
LEFT JOIN agents a ON a.id = fd.agent_id
LEFT JOIN emergency_tokens et ON et.id = p.eat_id
LEFT JOIN users u ON u.id = et.user_id
ORDER BY time_to_patch NULLS FIRST;

Een rij met time_to_patch IS NULL = host nog niet gepatched. Een rij met operator IS NULL = reboot was niet EAT-driven (manueel) — minder robuust evidence, maar wel een rij in kernel_reboot_history met expected=false.


3. Geef me elke privileged actie van laatste kwartaal

In het dashboard

  1. Sidebar → Audit log (onder MANAGE)
  2. Filter: event_type = emergency_token_issued + datum-range Q1
  3. Per rij: operator, target, actions JSON, exit_code
  4. Knop ‘Verify in transparency log’ opent externe verifier per nonce

Of via API (geavanceerd — voor automatisering)

SELECT et.issued_at,
u.email AS operator,
a.hostname AS target,
et.level AS escalation,
et.actions::TEXT AS actions,
et.reason AS reason,
(et.result->>'exit_code')::INT AS exit_code
FROM emergency_tokens et
LEFT JOIN users u ON u.id = et.user_id
LEFT JOIN agents a ON a.id = et.agent_id
WHERE et.tenant_id = $1::UUID
AND et.issued_at >= '2026-01-01' AND et.issued_at < '2026-04-01'
ORDER BY et.issued_at DESC;

Voor offline verificatie: elke nonce zit in de transparency log. Auditor kan onafhankelijk valideren:

Terminal window
./monsys-verify-eat-linux-x64 verify-eat \
--nonce 7a3c… \
--log-endpoint https://transparency.monsys.ai/api/v1/transparency-log/entry \
--pubkey https://transparency.monsys.ai/pubkeys/hub.pub

→ Bevestigt dat het EAT door de legitieme hub-key is uitgegeven én dat de log-entry niet retroactief gemanipuleerd is (hash-chain verify).


4. Welke NIS2/CRA-controls vallen tekort

In het dashboard

  1. Sidebar → Compliance → kies framework NIS2
  2. Matrix toont per control: coverage + evidence count + reviewed status
  3. Filter op reviewed_status=‘draft’ om openstaande review-werk te zien
  4. Knop ‘Export as CSV’ voor je kwartaalrapport

/compliance/NIS2 toont een matrix:

ControlCoverageEvidence countReviewed
NIS2-Art21-2-aautomatic247
NIS2-Art21-2-bpartial12draft
NIS2-Art21-2-cmanual0draft

coverage_level=automatic = monsys voert de evidence query elke nacht uit en stort het resultaat in compliance_evidence. partial = deels geautomatiseerd, deels manuele attestatie. manual = enkel een tekstveld voor menselijke verklaring.

reviewed_status='draft' betekent: nog niet juridisch gevalideerd. Tot deze flag op reviewed staat én COMPLIANCE_PRODUCTION=1 is gezet op de hub, krijg je in de PDF een waarschuwingsbanner “draft mapping — not suitable for legal claims”.

Voor het kwartaalrapport download je deze matrix als CSV via:

Of via API (geavanceerd — voor automatisering)

Terminal window
curl 'https://app.monsys.ai/api/v1/compliance/coverage?framework=NIS2&format=csv' \
-H "Authorization: Bearer $TOKEN" > nis2-coverage-2026-Q1.csv

5. Verifieer cryptografische integriteit van één specifieke evidence-rij

In het dashboard

  1. Sidebar → Audit Packs → kies de maand
  2. Klik ‘Tamper check’ knop in download view
  3. Paste de verdachte JSONL regel + lijnnummer
  4. UI toont expected vs computed hash + verdict

Stel de auditor twijfelt of regel #847 in 2026-04.jsonl.gz echt zo geregistreerd was, of dat de operator hem achteraf heeft aangepast.

Of via API (geavanceerd — voor automatisering)

Terminal window
zcat 2026-04.jsonl.gz | sed -n '847p' > suspicious-line.json
sha256sum suspicious-line.json
# 7c34a9e2b1f0…

Vergelijk met de hash_chain in de manifest — elke regel in JSONL voegt zijn sha256 toe aan de keten:

Terminal window
zcat 2026-04.jsonl.gz | ./monsys-verify-eat-linux-x64 chain-position --line 847
# expected_position: 7c34a9e2b1f0…
# computed_position: 7c34a9e2b1f0…
# ✓ line 847 matches the chain

Mismatch = bewijs van retroactieve manipulatie. Geen mismatch = de regel is identiek aan toen hij geschreven werd op signed_at.


6. Welke users hebben admin-rechten over alle systemen

In het dashboard

  1. Sidebar → RBAC → tab ‘Admin overzicht’
  2. Per user: alle hosts + EATs uitgevoerd laatste 90d
  3. Sorteer op eats_last_90d ascending — admins die nooit gebruiken
  4. Klik ‘Downgrade to editor’ voor least-privilege oprationalisatie

Of via API (geavanceerd — voor automatisering)

SELECT u.email,
ARRAY_AGG(DISTINCT a.hostname) FILTER (WHERE a.hostname IS NOT NULL) AS hosts,
ARRAY_AGG(DISTINCT iu.username) AS local_users,
COUNT(DISTINCT et.id) AS eats_last_90d
FROM users u
LEFT JOIN role_assignments r ON r.user_id = u.id
LEFT JOIN inventory_users iu ON iu.email = u.email -- explicit link, no auto-correlate
LEFT JOIN agents a ON a.id = iu.agent_id
LEFT JOIN emergency_tokens et ON et.user_id = u.id
AND et.issued_at >= NOW() - INTERVAL '90 days'
WHERE u.tenant_id = $1::UUID
AND r.role = 'admin'
GROUP BY u.email
ORDER BY eats_last_90d DESC NULLS LAST;

Wat je hieruit ziet:

  • Admins die nooit EAT hebben uitgevoerd → kandidaat voor downgrade
  • Admins op meer hosts dan strikt nodig → minimal-privilege check
  • Admins zonder lokale-user-link → enkel dashboard, geen shell

7. Backup-evidence per host laatste 90 dagen

In het dashboard

  1. Sidebar → Inventaris → tab Backups → filter tag ‘production’
  2. Per host: successful_runs_90d + failed_runs_90d
  3. Sorteer ascending op successful — 0 op prod = audit finding
  4. Klik ‘Export evidence’ voor je ISO 27001 A.8.13 rapport

Of via API (geavanceerd — voor automatisering)

SELECT a.hostname,
b.tool,
b.destination,
b.last_successful_run,
(SELECT COUNT(*) FROM backup_inventory bi
WHERE bi.agent_id = b.agent_id
AND bi.run_at >= NOW() - INTERVAL '90 days'
AND bi.success = true) AS successful_runs_90d,
(SELECT COUNT(*) FROM backup_inventory bi
WHERE bi.agent_id = b.agent_id
AND bi.run_at >= NOW() - INTERVAL '90 days'
AND bi.success = false) AS failed_runs_90d
FROM backup_configs b
JOIN agents a ON a.id = b.agent_id
WHERE b.tenant_id = $1::UUID
AND 'production' = ANY(a.tags)
ORDER BY successful_runs_90d ASC;

successful_runs_90d = 0 op een prod-host is een audit-finding (ISO 27001 A.8.13 / NIS2 §2(c) business continuity).


8. Retention check — hoe lang houden we evidence

In het dashboard

  1. Sidebar → Trust Score → component ‘Evidence continuity’
  2. Tabel toont per evidence-tabel oudste rij + nieuwste
  3. Direct visueel: groen >12m, rood <12m (NIS2 minimum)
  4. Klik rode rij → details + remediation suggesties

Of via API (geavanceerd — voor automatisering)

SELECT 'audit_log' AS table_name,
MIN(created_at) AS oldest, MAX(created_at) AS newest,
COUNT(*) AS rows
FROM audit_log WHERE tenant_id=$1::UUID
UNION ALL
SELECT 'emergency_tokens',
MIN(issued_at), MAX(issued_at), COUNT(*)
FROM emergency_tokens WHERE tenant_id=$1::UUID
UNION ALL
SELECT 'transparency_log',
MIN(appended_at), MAX(appended_at), COUNT(*)
FROM transparency_log WHERE tenant_id=$1::UUID
UNION ALL
SELECT 'audit_packs',
MIN(month_start), MAX(month_start), COUNT(*)
FROM audit_packs WHERE tenant_id=$1::UUID;

NIS2 vereist (interpretatie van de Belgische omzetting): minimum 12 maanden voor audit-evidence. Trust Score evidence_continuity-component straft tenants af die <12 maanden continuum hebben — die zie je terug in /trust-score/v12/tenant.