Chapter 39 / 40
Key rotation
A credential that never changes is a credential that leaks. Not all at once, not dramatically — but over years, laptops are lost, contractors come and go, screenshots end up in the wrong chat. The defence is not “never leak” (impossible) but “rotate often enough that a leak has a short half-life”. This chapter is the Sodimo rotation playbook: what gets rotated, when, and how.
Status: Planned — the rotation schedule activates when the vault goes live. The procedures below are the shape the team adopts from day one.
Everything in this chapter assumes the Vaultwarden vault (chapter Account vault basics, full spec in chapter The vault) exists and is reachable at vault.sodimo.eu. Some rotations are Vaultwarden-UI-only (entering a new password for a SaaS), some are Claude-Code-driven (rotating an API token end-to-end — generating, writing to the vault, updating the consumer service, verifying, revoking). The walk-throughs below show each flow in the shape it actually takes.
Every rotation lands a row in run_ledger with surface=vault_rotation — so the dashboard (chapter The launchpad) can answer “when did we last rotate X?” without asking anyone.
The rotation calendar
This schedule is canonical — the same cadence appears in chapter The vault. Do not drift. If a cadence feels wrong for a specific credential, update both chapters together.
| What | Cadence | Trigger events (in addition to the schedule) |
|---|---|---|
| SSH keys (personal laptop → harness) | 90 days | Laptop lost/stolen/retired; teammate leaves. |
| Admin passwords (Cloudflare, Google Workspace, GitHub org) | 180 days, TOTP-bound | Teammate with admin role leaves; suspected breach upstream. |
| Service tokens (Cloudflare API, GitHub deploy keys, Anthropic API, D1 tokens, third-party SaaS) | 365 days, and on any employee offboarding | Any suspicion of leak; token visible in a screenshot or a commit; service retired. |
| Vaultwarden admin token | 365 days | Any suspicion of compromise. |
| Break-glass items (paper recovery envelope, safe combo, LUKS recovery keys, backup-encryption keys) | Never rotated automatically | Only on a specific incident — physical security is what protects these. |
Two framings help hold the cadence in your head:
- SSH is the short fuse (90 days). SSH keys protect the harness itself — the box that holds everything else — so the blast radius of a leaked SSH key is the entire system. The 90-day cadence is not paranoia; it is proportionate to what the key unlocks.
- The 365-day service-token rotation is the forcing-function audit. Once a year, every automation service gets its credential re-issued. The point is not just “the old token is burnt”; it is the annual excuse to verify that each service still exists, still needs the token it has, and still has a sensible scope.
Offboarding is a universal trigger. When anyone leaves the team, every secret they had access to is rotated in the same session — not selectively. The calendar is the floor, not the ceiling.
How a service-token rotation goes (Claude Code-driven)
Service tokens — Cloudflare API, Anthropic API, D1, GitHub deploy keys — rotate end-to-end through Claude Code, because the rotation touches three systems in sequence (the issuer, the vault, the consuming service). Open Claude Code:
Rotate the Cloudflare API token used by the ETL service.
Claude Code does the following, showing each step:
- Reads the current token’s metadata from Vaultwarden (when it was created, who uses it, what its scope is).
- Generates a new token in Cloudflare with the same scope (via the Cloudflare API, not a human logging in).
- Writes the new token into Vaultwarden, with today’s date and your initials stamped into the entry’s custom fields.
- Updates the service that consumes the token — in this case, the
sodimo-etlsystemd service — to reference the new entry. - Restarts the service.
- Verifies the next scheduled run of the ETL succeeds against the new token.
- Revokes the old token in Cloudflare.
- Marks the old Vaultwarden entry as “revoked YYYY-MM-DD” in a note field rather than deleting it, so the audit trail survives.
- Writes a row to
run_ledgerwithsurface=vault_rotationand the rotated credential’s short name.
The entire sequence takes five minutes for a well-scoped credential. You watch it happen; Claude Code talks you through each step; you approve each irreversible action (writing to the vault, revoking the old token) before it happens.
How an admin-password rotation goes (Vaultwarden UI)
Admin passwords for the SaaS consoles — Cloudflare, Google Workspace, GitHub org, the registrar — rotate directly in the vendor’s UI and in Vaultwarden. No Claude Code needed; the browser is the whole tool.
- Open
vault.sodimo.eu, log in, find the entry (e.g. “Cloudflare — admin”). - Open the vendor’s console in another tab, go to the password-change flow, generate a new password (Vaultwarden’s built-in generator is fine; 20+ characters, mixed classes).
- Complete the vendor’s change flow. Re-authenticate with TOTP if asked.
- Paste the new password into the Vaultwarden entry, save.
- Sign out and sign back in at the vendor to confirm the new password works.
- The Vaultwarden entry records the password-change event automatically in its history.
Five minutes in the browser, no terminal involved. This is the shape Paul or Rani can do without Thomas on the call.
SSH key rotation (90 days)
SSH keys rotate every 90 days because they protect the harness. See the companion chapter (SSH basics) for the from-scratch setup — this section assumes you already have a key in Vaultwarden and you are rotating it.
Open Claude Code:
Rotate my SSH key for the Framework Desktop.
The sequence:
- Claude Code generates a new Ed25519 keypair on your laptop (not on the server, never on the server).
- The new public key is added to the harness’s
authorized_keys— added, not replaced, so you are not locked out if anything goes wrong. - You test SSH with the new key:
ssh harness.sodimo.eu— it should succeed without a password prompt. - Once the new key works, the old public key is removed from
authorized_keys. - The new private key is uploaded to Vaultwarden (collection: SSH private keys); the old entry is marked revoked rather than deleted.
- A
run_ledgerrow withsurface=vault_rotationrecords the rotation.
If step 3 fails — the new key did not get in — the old key is still on the server, so you are not locked out. Fix the problem (usually: public key not copied correctly) and try again. Nothing is destructive until the old key is removed.
Calendar the next rotation 90 days out. Vaultwarden will also surface the entry’s age in the UI, so a glance at the SSH collection tells you which keys are due.
When to rotate now, off schedule
Four situations overrule the calendar and demand rotation today:
- Credential is visible somewhere public. A token in a screenshot shared on WhatsApp, in a git commit, in a support ticket. Even if the viewer is trusted, the credential is burnt.
- A laptop is lost or stolen. Every key on that laptop is compromised as of now.
- A teammate leaves the company. Every credential they had access to is rotated in the same working day.
- Unusual activity. A billing spike on the Anthropic account, an unexpected deploy, a service hitting Cloudflare from an IP nobody recognises. Rotate first, investigate second.
None of these are rare. Budget a rotation every couple of months, on top of the calendar, from operational reality alone.
What rotation does not fix
Rotation limits the half-life of a leak — it does not undo the leak. If a token was leaked and used maliciously before you noticed, rotating does not unwrite the malicious calls. The response to a confirmed leak is:
- Rotate, immediately. (This chapter.)
- Audit the logs of the system the token reached. Cloudflare has an audit log; D1 has query logs; Anthropic has request logs. Look for activity you do not recognise.
- Message Thomas (during the engagement) or the on-call owner (after handoff). They will decide whether the audit warrants further response.
Rotation is the first step of the response, not the whole response.
The exit procedure (Thomas’s handoff)
At the end of the engagement, a full-rotation session takes place in one sitting. Every credential Thomas has ever held is either rotated to a Sodimo-owned one or revoked. The procedure is in chapter The vault — this chapter points to it so no employee thinks it is optional.
The rule: the day Thomas hands over the harness, no Thomas-issued or Thomas-known credential has live access to anything Sodimo. The vault is the same shape, the tooling is the same, only the keys have changed.