Aller au contenu

mTLS — certificats client hub ↔ agent

Chaque agent reçoit un certificat client X.509 signé par le hub dès le premier boot. À partir de ce moment, chaque handshake TLS vers api.monsys.ai prouve deux choses : que la connexion possède un bearer token valide (comme avant), et que le côté client détient la clé privée correspondante dans /var/lib/monsys/mtls/client.key. Un token volé seul ne suffit plus à usurper un agent — l’attaquant doit aussi exfiltrer la clé locale, qui ne quitte jamais l’hôte.

Modèle de menace

Avant mTLS (bearer uniquement) :

  • Vol de token via dump d’inventaire, ligne de log ou scrape mémoire → un attaquant peut appeler tout endpoint agent jusqu’à ce que l’opérateur fasse une rotation.

Après mTLS :

  • Le vol de token requiert également /var/lib/monsys/mtls/client.key (root-owned, mode 600) à exfiltrer séparément.
  • Un proxy mal configuré qui stripperait le cert est rejeté — Caddy positionne l’en-tête X-Monsys-Client-Verified à partir du fingerprint cert, et le middleware hub avorte si le CN ne matche pas l’agent_id du bearer.

Fonctionnement

  1. Bootstrap CA (une fois). Au premier démarrage, le hub génère une CA RSA-4096, chiffre la clé privée avec CLOUD_ENCRYPTION_KEY (AES-256-GCM), et stocke les deux dans la ligne singleton hub_settings. Le cert CA public est aussi exposé sans authentification via GET /api/v1/agents/ca-cert pour que les agents puissent l’épingler.
  2. Émission cert par agent. L’agent appelle POST /api/v1/agents/issue-client-cert avec son bearer token. Le hub signe un cert RSA-2048 (CN = agent_id UUID, OU = tenant_id UUID), valide 365 jours, stocke le cert public dans agent_certificates, retourne cert + key + CA PEM une seule fois.
  3. Persistence. L’agent écrit trois fichiers mode 600 sous /var/lib/monsys/mtls/ : client.crt, client.key, hub-ca.crt.
  4. Toute requête suivante utilise le cert. Caddy est configuré avec client_auth.mode = verify_if_given contre la CA hub, donc les anciens agents bearer-only continuent de fonctionner pendant le déploiement.
  5. Propagation Caddy. Après vérification, Caddy injecte X-Monsys-Client-Subject (DN complet) et X-Monsys-Client-Verified (fingerprint cert) dans la requête upstream. Les copies entrantes de ces en-têtes sont d’abord supprimées pour qu’un client non-mTLS ne puisse pas les falsifier.
  6. Cross-check hub. Le middleware AgentAuth extrait le CN du DN sujet et le compare à l’agent_id résolu par le bearer. Match : succès + last_seen_at mis à jour sur la ligne cert. Mismatch : HTTP 401 + integrity_anomaly enregistré — signal fort de vol de token ou de mauvaise configuration proxy.

Déploiement — ce qui change pour les agents existants

Rien d’immédiat. Le mode verify_if_given de Caddy permet aux connexions non-mTLS de continuer. À la prochaine auto-update (ou restart manuel), le nouveau binaire appelle issue-client-cert une fois et tout le trafic suivant est mTLS-authentifié. Pas de downtime, pas de re-enrôlement, pas de changement de token.

La composante Trust Score agent_health applique une pénalité douce (-5 points) aux agents n’ayant pas encore bootstrappé de cert. Ça nudge les opérateurs à déployer le nouveau binaire sans forcer une coupure dure.

Notes opérationnelles

SujetDétail
Expiration CA10 ans depuis le premier boot. Alerte câblée sur ca_not_after pour automatisation future.
Expiration cert client365 jours. L’agent re-fetch automatiquement dans les 30 jours avant expiration.
Clé privée CAChiffrée AES-256-GCM dans hub_settings.ca_key_enc. La restauration nécessite la même CLOUD_ENCRYPTION_KEY — backup hors-bande.
RotationPOST /api/v1/agents/issue-client-cert effectue la rotation : ancienne ligne marquée revoked_at = NOW(), revoke_reason = 'rotated', nouvelle ligne insérée en une tx.
RévocationL’opérateur positionne revoked_at en DB. Le middleware hub rejette les certs révoqués même si Caddy les accepte (jusqu’à un futur endpoint CRL).
StorageClés client RSA-2048, CA RSA-4096. Ed25519 réservé aux Emergency Action Tokens où nous contrôlons les deux côtés.

Endpoints

MéthodePathAuthQuoi
GET/api/v1/agents/ca-certaucuneCertificat public de la CA hub (pour trust pinning)
POST/api/v1/agents/issue-client-certbearerÉmission ou rotation du cert client + clé privée de l’agent appelant

Fichiers sur l’hôte agent

/var/lib/monsys/mtls/
├── client.crt # certificat client rsa-2048 (PEM)
├── client.key # clé privée rsa-2048 (PEM, mode 600)
└── hub-ca.crt # racine CA hub (PEM)

Mapping de conformité : ISO 27001 A.8.20 (Sécurité du réseau) + CRA Annexe I §3 (communication sécurisée par défaut). Les deux contrôles sont automatiquement évalués via un comptage des lignes actives, non-révoquées, dans agent_certificates.