Keys and operations
Rotate, version, and revoke keys
Attach key and format versions to protected data, support controlled migration, and prepare immediate revocation for suspected compromise.
Keys and algorithms have lifecycles. Keys leak. Employees leave. Algorithms age out of the guidance. Design your data format so old records stay readable while new writes use the current key.
Do this on day one. One day you will rotate under pressure, and that is the wrong day to invent a migration.
Version everything you protect
Store a non-secret key identifier and a format version next to every ciphertext or signature:
{
"v": 2,
"kid": "field-key-2026-08",
"nonce": "9mPqL2Xb8kQz",
"tag": "4sR7...",
"ciphertext": "..."
}
Now a read is a lookup, not a guessing game. You keep a keyring of known keys and pick the right one by ID:
const keyring = {
'field-key-2026-02': oldKey, // decrypt only
'field-key-2026-08': currentKey,
}
const key = keyring[record.kid]
if (!key) throw new Error(`unknown key id: ${record.kid}`)
Compare that with records that carry no key identifier. After a rotation, the application has to try every historical key until one works. Reads get slow, failures get confusing, and retirement becomes impossible. You can never prove a key is unused, so you can never delete it.
Rotate in phases
With a versioned format, rotation becomes a routine with four steps:
phase 1: add key v2 to the keyring (reads: v1+v2, writes: v1)
phase 2: switch writes to v2 (reads: v1+v2, writes: v2)
phase 3: re-encrypt or expire v1 records
phase 4: retire v1 to decrypt-only, then delete per retention policy
Keep the old key in decrypt-only mode during the migration. Then retire it according to your retention needs. I like to watch a metric of reads per key version. Phase 4 starts when v1 reads hit zero and stay there.
Revocation is not rotation
Rotation is planned. Revocation is what you do when a key may be compromised. It has to be fast: stop trusting the key now, not after a migration.
For signing keys, revocation means removing trust in the key and issuing a clean replacement. You also have to decide whether things signed before the compromise are still acceptable. Often you cannot tell when the leak happened, so the honest answer is no.
For encryption keys, immediate revocation has a cost. Records encrypted under the revoked key stop being readable. So compromise response and data recovery need an explicit tradeoff, written down before the incident: which data you would give up, and who makes that call at 3am.
Write that decision down now, while nobody is panicking. The 3am version of you will thank the calm version.
Try this on your own project: write a migration plan from key version 1 to version 2 using the new-write and old-read phases. Encrypt records under both versions and confirm the key identifier selects the correct key without trial decryption. Then revoke version 1 in a test environment, record which reads fail, and note how the recovery decision gets made.
Lesson completed