Ed25519, épinglage TOFU et vérification offline : comment fonctionnent les evidence packs monsys
Les dashboards sont pour les opérateurs. Les auditeurs veulent un artifact qu'ils peuvent vérifier offline, sans faire confiance à votre système. Comment fonctionne la chaîne de signature monsys.
Un auditeur demande une preuve que votre serveur n'a eu aucune modification non autorisée le 14 mars. Vous envoyez une capture d'écran d'un dashboard. L'auditeur demande : comment je sais que ça n'a pas été modifié ?
C'est le problème central de tout outil de monitoring qui veut fournir de la preuve de conformité. Les dashboards sont bien pour les opérateurs. Les auditeurs veulent autre chose : un artifact qu'ils peuvent vérifier offline, sans devoir faire confiance à votre système.
Voici comment fonctionne la chaîne de signature monsys.
L'architecture en un schéma
Chaque payload que l'agent envoie au hub est signée avec une paire de clés Ed25519. La paire est unique par agent — la clé privée est générée sur l'hôte à l'installation et ne quitte jamais l'hôte. Le hub ne connaît que la clé publique.
Agent (host) Hub (monsys.ai BE)
───────────────── ──────────────────────────────
Ed25519 private key Ed25519 public key (TOFU pinned)
│ │
▼ ▼
payload → sign(payload, privkey) → verify(sig, pubkey) → store
Le hub épingle la clé publique à la première connexion (TOFU). Chaque payload est ensuite vérifié. Un attaquant qui vole le token du hub ne peut pas injecter de fausse télémétrie — il lui faut la clé privée sur l'hôte pour produire une signature valide.
Comment un evidence pack est construit
Quand vous cliquez sur « Générer evidence pack » pour une période (ex : avril 2026) :
Étape 1 : Query Le hub récupère tous les événements pertinents pour votre tenant sur la période :
- Snapshots d'inventaire agent
- Événements d'alerte (open, fermés, acquittés)
- Événements de détection
- Évaluations de contrôles de conformité
- Entrées audit log (qui a fait quoi, quand)
- Traces AI observability (si actif)
Étape 2 : Normalisation Chaque ligne d'événement est sérialisée en JSON canonique (clés triées, pas de variations d'espaces). C'est important : deux datasets identiques doivent produire des bytes identiques, sinon la signature ne correspond pas.
Étape 3 : Manifest Le manifest est un fichier JSON qui liste tous les fichiers de la tarball avec leur hash SHA256 :
{
"tenant_id": "acme-bv",
"period_start": "2026-04-01T00:00:00Z",
"period_end": "2026-04-30T23:59:59Z",
"generated_at": "2026-05-01T08:03:14Z",
"signing_key_id": "sk_2024_q1",
"files": [
{
"path": "agents/web-edge-01/inventory_snapshots.ndjson",
"sha256": "b4c2f1a3...",
"record_count": 2880
},
{
"path": "alerts/april_2026.ndjson",
"sha256": "e7d9c2b1...",
"record_count": 47
}
],
"inputs_hash": "sha256:a1b2c3d4..."
}
L'inputs_hash est le SHA256 de toutes les valeurs sha256 concaténées — une empreinte du bundle entier.
Étape 4 : Signature Le hub signe le manifest avec sa clé Ed25519 de signature tenant :
signature = Ed25519.sign(manifest_bytes, tenant_signing_privkey)
La signature et la clé publique sont incluses dans la tarball.
Étape 5 : Packaging
evidence_acme-bv_april-2026.tar.gz
├── manifest.json
├── manifest.sig ← signature Ed25519 (hex)
├── signing_key.pub ← clé publique (PEM)
├── verify.py ← script de vérification standalone
└── data/
├── agents/
├── alerts/
├── detections/
├── compliance/
└── audit_log/
Vérification offline : verify.py
Le script verify.py qui se trouve dans la tarball n'a aucune dépendance externe à part la stdlib Python (3.8+) et cryptography (installable via pip). Un auditeur qui ne connaît pas monsys peut l'exécuter :
pip install cryptography
python verify.py evidence_acme-bv_april-2026.tar.gz
Sortie en cas de succès :
✓ Signature valid (Ed25519)
✓ Signing key matches expected fingerprint: 4a:b3:c2:...
✓ All 12 files intact (SHA256 match)
✓ inputs_hash consistent
✓ Period: 2026-04-01 → 2026-04-30
✓ Tenant: acme-bv
exit 0
Sortie en cas de manipulation :
✗ File tampered: data/alerts/april_2026.ndjson
Expected SHA256: e7d9c2b1...
Actual SHA256: f8e0d3c2...
exit 1
L'auditeur n'a pas besoin de compte monsys. Le script ne télécharge rien depuis Internet. La vérification est entièrement offline.
Rotation de clés : la lineage de la clé de signature
Les clés de signature sont rotées périodiquement (recommandé : annuellement, ou en cas de soupçon de compromission). Mais qu'arrive-t-il aux evidence packs signés avec une vieille clé ?
monsys maintient une key lineage. Chaque clé a :
key_id: identifiant unique (ex :sk_2024_q1)public_key: format PEMactive_from/active_untilsuperseded_by: référence vers la clé qui lui succède
À la vérification, verify.py vérifie non seulement la validité de la signature, mais aussi si la clé utilisée était active au moment de la génération (generated_at dans le manifest). Une clé rotée le 1er janvier 2025 reste valide pour les evidence packs générés avant cette date.
# Simplifié depuis verify.py
def verify_key_was_active(key_id: str, generated_at: datetime, lineage: list) -> bool:
for key in lineage:
if key["key_id"] == key_id:
active_from = datetime.fromisoformat(key["active_from"])
active_until = datetime.fromisoformat(key["active_until"]) if key.get("active_until") else datetime.max
return active_from <= generated_at <= active_until
return False
Le snapshot de la lineage est aussi dans la tarball, pour que la vérification fonctionne sans accès réseau.
Vol de bearer token : ce que ça peut et ne peut pas faire
Une question fréquente : si un attaquant vole le token agent (le token que l'agent utilise pour pousser de la télémétrie au hub), que peut-il faire ?
Peut l'attaquant :
- Envoyer de la fausse télémétrie comme cet agent → le hub accepte la requête
- Mais : cette télémétrie n'a pas la signature Ed25519 de la clé privée de l'agent
- Le hub stocke la télémétrie non signée avec un flag
signature_missing - Les evidence packs pour cette période sont marqués
integrity_warning
Ne peut pas l'attaquant :
- Envoyer un payload signé valide sans la clé privée sur l'hôte
- Modifier rétroactivement des evidence packs existants (la signature ne correspondra plus)
- Roter la clé de signature au niveau du hub (cela exige TOTP + droits admin)
C'est pourquoi la rotation périodique de token reste recommandée — mais la chaîne de signature garantit qu'un token volé ne peut pas empoisonner la preuve historique.
mTLS : la deuxième couche de sécurité
Par-dessus la signature Ed25519, la connexion hub-agent utilise mTLS. L'agent reçoit un certificat client à la première connexion qui est ensuite épinglé. Cela signifie :
- Le hub sait avec certitude que la connexion vient de l'agent enregistré (pas de quelqu'un avec uniquement le token)
- Un man-in-the-middle ne peut pas simuler un faux agent
La combinaison : mTLS authentifie qui établit la connexion ; Ed25519 authentifie le contenu de chaque payload.
NIS2 et AI Act : ce que ça signifie concrètement
L'article 21 de NIS2 exige des « appropriate technical measures » pour la journalisation et la réponse aux incidents. « Appropriate » est vague, mais un audit trail signé et vérifiable offline marque nettement mieux auprès d'un régulateur que des captures d'écran ou exports CSV.
Pour l'AI Act article 12 (journalisation des événements du système IA) : le module AI observability utilise la même chaîne de signature que le reste de monsys. Chaque trace — prompt, completion, tokens, hits PII — est dans la tarball, signée, vérifiable par un inspecteur DPA sans compte monsys.
Inspecteur DPA : « Prouvez que votre système IA n'a transmis aucun
numéro IBAN à OpenAI le 3 avril. »
Opérateur : python verify.py evidence_april-2026.tar.gz
✓ Signature valid
grep -r "pii_hits_count" data/ai_traces/ | grep "2026-04-03"
→ 0 résultats pour hits IBAN à cette date
Vérifiable. Reproductible. Sans demander votre confiance.
La chaîne de signature est documentée dans docs.monsys.ai/fr/security/agent-signing et docs.monsys.ai/fr/security/signing-keys-rotation. Les cinq premiers serveurs gratuits : monsys.ai/fr/signup.