Ga naar inhoud

mTLS — hub ↔ agent client certificaten

Elke agent krijgt bij eerste boot een door de hub ondertekend X.509 client certificaat. Vanaf dat moment bewijst elke TLS handshake naar api.monsys.ai twee dingen: dat de connectie een geldig bearer token heeft (zoals voorheen), én dat de client kant de bijbehorende private key bezit in /var/lib/monsys/mtls/client.key. Een gelekt token alleen is niet meer voldoende — de aanvaller heeft ook de on-disk key nodig, die nooit de host verlaat.

Threat-model

Voor mTLS (bearer-only):

  • Token diefstal uit een inventory dump, log line of memory scrape → aanvaller kan elke agent-endpoint aanroepen als die agent tot operator het token roteert.

Na mTLS:

  • Token diefstal vereist nog steeds /var/lib/monsys/mtls/client.key (root-owned, mode 600) om apart geëxfiltreerd te worden.
  • Een fout-geconfigureerde proxy die het cert stript wordt geweigerd — Caddy zet de X-Monsys-Client-Verified header op de cert-fingerprint, en hub middleware breekt af als de CN niet overeenkomt met het bearer agent_id.

Hoe het werkt

  1. CA bootstrap (eenmalig). Bij eerste start genereert de hub een RSA-4096 CA, encrypt de private key met CLOUD_ENCRYPTION_KEY (AES-256-GCM), en bewaart beide in de singleton hub_settings rij. Het publieke CA-cert is ook ongeauthenticeerd beschikbaar via GET /api/v1/agents/ca-cert zodat agents het kunnen pinnen.
  2. Per-agent cert uitgifte. De agent roept POST /api/v1/agents/issue-client-cert aan met zijn bearer token. De hub ondertekent een RSA-2048 cert (CN = agent_id UUID, OU = tenant_id UUID), 365-dagen geldig, bewaart het publieke deel in agent_certificates, geeft cert + key + CA PEM éénmalig terug.
  3. Persistentie. De agent schrijft drie bestanden mode 600 onder /var/lib/monsys/mtls/: client.crt, client.key, hub-ca.crt.
  4. Elke vervolg-request gebruikt het cert. Caddy draait met client_auth.mode = verify_if_given tegen de hub CA, dus oudere bearer-only agents blijven werken tijdens de uitrol.
  5. Caddy propagatie. Na verificatie injecteert Caddy X-Monsys-Client-Subject (volledige DN) en X-Monsys-Client-Verified (cert fingerprint) in de upstream-request. Inbound kopieën van deze headers worden eerst gestript, zodat een niet-mTLS client ze niet kan vervalsen.
  6. Hub cross-check. De AgentAuth middleware haalt CN uit de subject DN en vergelijkt met het bearer-gerelateerde agent_id. Match: succes + last_seen_at op de cert-rij bijgewerkt. Mismatch: HTTP 401
    • integrity_anomaly gelogd — sterk signaal van token diefstal of proxy misconfiguratie.

Uitrol — wat verandert voor bestaande agents

Niets onmiddellijk. Caddy’s verify_if_given modus laat niet-mTLS verbindingen blijven werken. Bij de volgende agent auto-update (of handmatige restart) roept het nieuwe binary één keer issue-client-cert aan, en alle vervolg-traffic is mTLS-geauthenticeerd. Geen downtime, geen re-enrolment, geen token verandering.

De Trust Score agent_health component geeft een zachte penalty (-5 punten) aan agents die nog geen cert hebben opgehaald. Dat nudge operators om de nieuwe binary uit te rollen zonder harde breuk te forceren.

Operationele notities

OnderwerpDetail
CA expiry10 jaar vanaf eerste boot. Alert via ca_not_after voor toekomstige automatisering.
Client cert expiry365 dagen. Agent re-fetcht automatisch binnen 30 dagen vóór expiry.
CA private keyAES-256-GCM versleuteld in hub_settings.ca_key_enc. Restore vereist dezelfde CLOUD_ENCRYPTION_KEY — backup out-of-band.
RotatiePOST /api/v1/agents/issue-client-cert roteert: oude rij krijgt revoked_at = NOW(), revoke_reason = 'rotated', nieuwe rij ingevoegd in één tx.
RevocatieOperator zet revoked_at in de DB. Hub middleware weigert geroteerde certs ook al accepteert Caddy ze (tot toekomstige CRL endpoint).
StorageRSA-2048 client keys, RSA-4096 CA. Ed25519 gereserveerd voor Emergency Action Tokens waar we beide kanten controleren.

Endpoints

MethodePadAuthWat
GET/api/v1/agents/ca-certgeenHub CA publiek certificaat (voor trust pinning)
POST/api/v1/agents/issue-client-certbearerUitgifte of rotatie van het bellende agent’s client cert + private key

Bestanden op de agent-host

/var/lib/monsys/mtls/
├── client.crt # rsa-2048 client certificaat (PEM)
├── client.key # rsa-2048 private key (PEM, mode 600)
└── hub-ca.crt # hub CA root (PEM)

Compliance mapping: ISO 27001 A.8.20 (Netwerkbeveiliging) + CRA Annex I §3 (secure-by-default communicatie). Beide controls worden automatisch geëvalueerd via een count van actieve, niet-geroteerde rijen in agent_certificates.