Auditeur — récupérer et vérifier les preuves
Cette page suppose que l’auditeur a son propre compte dans /auditor
avec scope lecture seule. Le client ne donne aucun accès shell et
aucun admin tableau de bord — toute preuve est signée et
vérifiable hors-ligne.
1. Audit trimestriel NIS2 — qu’est-ce que j’ai
Dans le tableau de bord
- Login en auditeur dans /auditor → Sidebar → Audit Packs
- Télécharger .jsonl.gz + .pdf + .sig pour le mois
- Cliquer ‘Download verify-CLI’ pour obtenir le vérifieur offline
- Lancer CLI contre pubkey — quatre checkmarks vertes
Ouvrez /audit-packs. Une ligne par mois pour le tenant choisi.
Téléchargez :
2026-04.jsonl.gz— tous les events bruts (lisible machine)2026-04.pdf— rapport lisible humain, 12-15 pages2026-04.sig— signature Ed25519 surmanifest_hash
Vérifier localement (aucun aller-retour réseau vers monsys) :
Ou via API (avancé — pour automatisation)
wget https://get.monsys.ai/monsys-verify-eat-linux-x64chmod +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.pubCe que la CLI vérifie :
- Calcule
manifest_hash = sha256(manifest)— doit matcher le contenu de.sig - Parcourt chaque ligne dans JSONL.gz, chaîne sha256 → doit terminer
sur
hash_chain_rootdu manifest - Vérifie la signature Ed25519 contre la pubkey publiée du hub
Sortie en cas de succès :
✓ manifest_hash matches signature✓ hash chain root matches manifest✓ Ed25519 signature valid against pubkey 7c34a9e2b1f0…✓ 1247 entries in pack, 0 tampered2. Prouver que CVE-2026-XXXX a été patchée en 7 jours
Dans le tableau de bord
- Sidebar → CVE noyau → rechercher CVE-2026-XXXX
- Onglet ‘Timeline’ montre par host : detected, patched, operator
- Filtre ‘Time to patch > 7 jours’ isole les SLA breaches
- Bouton ‘Export for audit’ → CSV avec toutes les colonnes
Trois questions d’auditeur :
- Quand la CVE a-t-elle été détectée la première fois ?
- Quand a-t-elle été patchée par hôte ?
- Qui a exécuté l’action ?
En un seul rapport SQL :
Ou via API (avancé — pour automatisation)
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;Une ligne avec time_to_patch IS NULL = hôte non encore patché. Une
ligne avec operator IS NULL = redémarrage non déclenché par EAT
(manuel) — preuve plus faible, mais toujours une ligne dans
kernel_reboot_history avec expected=false.
3. Montrez-moi chaque action privilégiée du dernier trimestre
Dans le tableau de bord
- Sidebar → Audit log (sous MANAGE)
- Filtre : event_type = emergency_token_issued + plage Q1
- Par ligne : operator, target, actions JSON, exit_code
- Bouton ‘Verify in transparency log’ ouvre vérifieur externe par nonce
Ou via API (avancé — pour automatisation)
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;Pour vérification hors-ligne : chaque nonce est dans le journal de
transparence. L’auditeur peut valider indépendamment :
./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→ Confirme que l’EAT a été émis par la clé légitime du hub ET que l’entrée du journal n’a pas été manipulée rétroactivement (vérification de la chaîne de hash).
4. Quels contrôles NIS2/CRA sont insuffisants
Dans le tableau de bord
- Sidebar → Compliance → choisir framework NIS2
- Matrice par contrôle : coverage + evidence count + reviewed status
- Filtre reviewed_status=‘draft’ pour voir le travail de review restant
- Bouton ‘Export as CSV’ pour rapport trimestriel
/compliance/NIS2 affiche une matrice :
| Contrôle | Couverture | Preuves | Reviewé |
|---|---|---|---|
| NIS2-Art21-2-a | automatic | 247 | ✓ |
| NIS2-Art21-2-b | partial | 12 | draft |
| NIS2-Art21-2-c | manual | 0 | draft |
| … |
coverage_level=automatic = monsys exécute la requête de preuves
chaque nuit et stocke les résultats dans compliance_evidence.
partial = mix d’automatique + attestation manuelle. manual = champ
texte pour déclaration humaine uniquement.
reviewed_status='draft' signifie : pas encore validé légalement.
Tant que ce flag n’est pas reviewed ET COMPLIANCE_PRODUCTION=1 sur
le hub, le PDF affiche une bannière d’avertissement “draft mapping —
not suitable for legal claims”.
Pour le rapport trimestriel, exportez la matrice en CSV via :
Ou via API (avancé — pour automatisation)
curl 'https://app.monsys.ai/api/v1/compliance/coverage?framework=NIS2&format=csv' \ -H "Authorization: Bearer $TOKEN" > nis2-coverage-2026-Q1.csv5. Vérifier l’intégrité cryptographique d’une ligne de preuve spécifique
Dans le tableau de bord
- Sidebar → Audit Packs → choisir le mois
- Cliquer ‘Tamper check’ dans la vue download
- Coller la ligne JSONL suspecte + numéro de ligne
- UI montre expected vs computed hash + verdict
Soit l’auditeur doute que la ligne #847 de 2026-04.jsonl.gz ait
réellement été enregistrée telle quelle, ou si l’opérateur l’a modifiée
après coup.
Ou via API (avancé — pour automatisation)
zcat 2026-04.jsonl.gz | sed -n '847p' > suspicious-line.jsonsha256sum suspicious-line.json# 7c34a9e2b1f0…Comparez avec le hash_chain du manifest — chaque ligne JSONL ajoute
son sha256 à la chaîne :
zcat 2026-04.jsonl.gz | ./monsys-verify-eat-linux-x64 chain-position --line 847# expected_position: 7c34a9e2b1f0…# computed_position: 7c34a9e2b1f0…# ✓ line 847 matches the chainMismatch = preuve de manipulation rétroactive. Match = la ligne est
identique à ce qu’elle était à l’écriture à signed_at.
6. Quels utilisateurs ont des droits admin transversaux
Dans le tableau de bord
- Sidebar → RBAC → onglet ‘Admin overview’
- Par user : tous hosts + EATs exécutés 90 derniers jours
- Trier eats_last_90d ascending — admins jamais utilisés
- Cliquer ‘Downgrade to editor’ pour least-privilege
Ou via API (avancé — pour automatisation)
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;Ce que vous repérez :
- Admins qui n’ont jamais exécuté un EAT → candidat à downgrade
- Admins sur plus d’hôtes que strictement nécessaire → check moindre privilège
- Admins sans lien utilisateur local → tableau de bord uniquement, pas de shell
7. Preuves de backup par hôte sur les 90 derniers jours
Dans le tableau de bord
- Sidebar → Inventaire → onglet Backups → filtre tag ‘production’
- Par host : successful_runs_90d + failed_runs_90d
- Trier ascending sur successful — 0 en prod = audit finding
- Cliquer ‘Export evidence’ pour rapport ISO 27001 A.8.13
Ou via API (avancé — pour automatisation)
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 sur un hôte de prod est un audit finding
(ISO 27001 A.8.13 / NIS2 §2(c) continuité d’activité).
8. Check de rétention — combien de temps gardons-nous les preuves
Dans le tableau de bord
- Sidebar → Trust Score → composant ‘Evidence continuity’
- Table montre par table de preuves : ligne la plus ancienne + récente
- À l’œil : vert >12m, rouge <12m (NIS2 minimum)
- Cliquer ligne rouge → détails + suggestions remediation
Ou via API (avancé — pour automatisation)
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::UUIDUNION ALLSELECT 'emergency_tokens', MIN(issued_at), MAX(issued_at), COUNT(*) FROM emergency_tokens WHERE tenant_id=$1::UUIDUNION ALLSELECT 'transparency_log', MIN(appended_at), MAX(appended_at), COUNT(*) FROM transparency_log WHERE tenant_id=$1::UUIDUNION ALLSELECT 'audit_packs', MIN(month_start), MAX(month_start), COUNT(*) FROM audit_packs WHERE tenant_id=$1::UUID;NIS2 exige (selon la transposition belge) : minimum 12 mois pour les
preuves d’audit. Le composant evidence_continuity du Trust Score
pénalise les tenants avec moins de 12 mois de continuum — visible dans
/trust-score/v12/tenant.