docs/cert-rotation.md
Ref: Size: 2.6 KiB History
# Server certificate rotation The server's QUIC identity is a self-signed ECDSA cert generated on first start (`transport.GenerateServerCert`, 2-year validity) and persisted next to the database (`server.crt` / `server.key`). Agents trust it by **fingerprint pin** carried in the join blob—not by CA path and **not by expiry**: an expired cert keeps working for already-enrolled agents. Rotation is therefore never an emergency at `NotAfter`; it is hygiene that bounds how long a stolen `server.key` stays useful. The server logs its cert fingerprint at every startup. It warns, at startup and daily thereafter, when the cert is within 90 days of expiry (`transport.CertRenewalDue`). ## Why rotate - `server.key` compromise: anyone holding it can impersonate the server to every agent pinning that cert's fingerprint, until every agent re-pins. - The validity period (2 years) is the *scheduled* cadence; rotate immediately on suspected key exposure. ## Ceremony Rotating the cert changes its fingerprint, which invalidates every agent's pin. Each agent must re-enroll to pick up the new fingerprint. 1. Stop the server. 2. Move the old cert+key aside: `mv server.crt server.crt.old && mv server.key server.key.old` (in the DB directory). 3. Start the server—it generates and persists a fresh 2-year cert and logs the new fingerprint. 4. For each host: mint a join token (`POST /api/v1/enroll-tokens`), copy the `join` blob, run `eitri-agent join <blob>` on the host, **then restart the agent daemon** (e.g. `systemctl restart eitri-agent`). `join` only rewrites the on-disk identity; the running daemon holds its identity in memory and keeps pinning the old fingerprint until restarted. Running VMs are untouched—they survive agent restarts by design, and the agent's reconcile state is independent of its server identity. 5. Delete `server.crt.old` / `server.key.old` once every host has reconnected (watch `GET /api/v1/hosts` for `online: true`). Until a host re-enrolls, its agent logs `server cert pin mismatch` and backs off—VMs keep running, but the host is dark to the control plane. Rotate during a window where that is acceptable, host by host. ## Out of scope (future) - Overlap rotation (serving old+new certs simultaneously)—needs dual-cert listener support. - Pushing new pins over the existing authenticated channel (would remove the re-enroll requirement). ## Related - [credential-revocation.md](credential-revocation.md)—revoking a leaked host credential (generation bump), the complementary emergency lever - [connecting](connecting.md)—the SSH CAs, which are separate from the QUIC identity rotated here