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-Verifiedheader op de cert-fingerprint, en hub middleware breekt af als de CN niet overeenkomt met het bearer agent_id.
Hoe het werkt
- 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 singletonhub_settingsrij. Het publieke CA-cert is ook ongeauthenticeerd beschikbaar viaGET /api/v1/agents/ca-certzodat agents het kunnen pinnen. - Per-agent cert uitgifte. De agent roept
POST /api/v1/agents/issue-client-certaan 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 inagent_certificates, geeft cert + key + CA PEM éénmalig terug. - Persistentie. De agent schrijft drie bestanden mode 600 onder
/var/lib/monsys/mtls/:client.crt,client.key,hub-ca.crt. - Elke vervolg-request gebruikt het cert. Caddy draait met
client_auth.mode = verify_if_giventegen de hub CA, dus oudere bearer-only agents blijven werken tijdens de uitrol. - Caddy propagatie. Na verificatie injecteert Caddy
X-Monsys-Client-Subject(volledige DN) enX-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. - Hub cross-check. De
AgentAuthmiddleware haalt CN uit de subject DN en vergelijkt met het bearer-gerelateerde agent_id. Match: succes +last_seen_atop de cert-rij bijgewerkt. Mismatch: HTTP 401integrity_anomalygelogd — 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
| Onderwerp | Detail |
|---|---|
| CA expiry | 10 jaar vanaf eerste boot. Alert via ca_not_after voor toekomstige automatisering. |
| Client cert expiry | 365 dagen. Agent re-fetcht automatisch binnen 30 dagen vóór expiry. |
| CA private key | AES-256-GCM versleuteld in hub_settings.ca_key_enc. Restore vereist dezelfde CLOUD_ENCRYPTION_KEY — backup out-of-band. |
| Rotatie | POST /api/v1/agents/issue-client-cert roteert: oude rij krijgt revoked_at = NOW(), revoke_reason = 'rotated', nieuwe rij ingevoegd in één tx. |
| Revocatie | Operator zet revoked_at in de DB. Hub middleware weigert geroteerde certs ook al accepteert Caddy ze (tot toekomstige CRL endpoint). |
| Storage | RSA-2048 client keys, RSA-4096 CA. Ed25519 gereserveerd voor Emergency Action Tokens waar we beide kanten controleren. |
Endpoints
| Methode | Pad | Auth | Wat |
|---|---|---|---|
| GET | /api/v1/agents/ca-cert | geen | Hub CA publiek certificaat (voor trust pinning) |
| POST | /api/v1/agents/issue-client-cert | bearer | Uitgifte 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.