Deep-dive technique · 2026-05-25

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 :

É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 :

À 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 :

Ne peut pas l'attaquant :

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 :

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.

Retour au blog