Encryption keys are long-lived security dependencies. A key may need replacement because its access policy changed, an operator left, a cryptographic policy changed, or there is reason to suspect exposure. The difficult part is not generating a new key. It is changing keys without making existing ciphertext unreadable or quietly continuing to depend on the old key forever.

This process is called key rotation: introducing a new key for a defined cryptographic role and moving the system away from the old one in a controlled way.

The useful mental model is: rotation changes which key protects future data first; migration changes which key protects existing data later. Treating those as separate steps makes failures easier to contain and recover from.

Understand what rotation is defending against

Suppose an application encrypts records with key version 1. If that key is exposed, an attacker who can also obtain ciphertext protected by it may be able to decrypt that data. Replacing the key used for new encryption limits how much additional data becomes dependent on the exposed key.

Rotation therefore reduces the future impact of a key that should no longer be trusted. It can also reduce dependence on very old keys and make planned key retirement possible.

Rotation does not undo past exposure. If an attacker already copied plaintext, rotating a key cannot make that copy secret again. If the attacker copied both an old key and ciphertext encrypted under it, simply switching new writes to another key does not protect those old copies. Rotation must be combined with access control, key-use logging, incident response, and appropriate migration when the threat model requires it.

Give ciphertext a key identity

A system with more than one active key version must know which key is required for each ciphertext. Do not make decryption guess.

A simplified encrypted record might contain:

key_version: 3
ciphertext: <encrypted bytes>

The version is metadata, not a secret. Its purpose is to let the application select the correct key before attempting decryption.

The decryption path then becomes conceptually:

read key_version
load the authorized key for that version
decrypt ciphertext

In a real design, authenticated-encryption metadata, nonces, algorithm identifiers, and storage formats must follow the requirements of the cryptographic library or protocol in use. The important design point here is narrower: ciphertext must remain unambiguously associated with the key material needed to process it.

Without that association, teams often compensate by trying several keys until one appears to work. That makes behavior harder to reason about, complicates retirement, and can hide data that was never migrated.

Rotate new writes before migrating old data

Assume the application currently encrypts every new record with key version 1. A controlled rotation can proceed in stages.

First, create key version 2 inside the system that owns or protects encryption keys. Give it only the permissions required for its role. Do not delete version 1.

Next, change the encryption path so new records use version 2:

new plaintext -> key v2 -> new ciphertext

Keep the decryption path able to use both versions while old ciphertext still exists:

ciphertext tagged v1 -> decrypt with key v1
ciphertext tagged v2 -> decrypt with key v2

This is the smallest useful rotation. New data no longer increases the amount protected by version 1, while existing data remains readable.

Verify this boundary before doing anything destructive. New writes should consistently reference version 2. Old records should still decrypt through version 1. Errors selecting or accessing either key should be visible in monitoring.

Decide whether old ciphertext must move

Not every rotation requires immediate re-encryption of every stored object.

If version 1 is being replaced as routine key hygiene and remains protected, a system may keep old ciphertext under version 1 until the data expires naturally. This avoids a large migration and can be reasonable when retention is short and the threat model permits continued use of the old key for decryption.

If version 1 may have been exposed, continuing to leave valuable data encrypted only with that key preserves the risk. Under that threat model, existing ciphertext should normally be migrated to protection that does not depend on the suspected key, subject to incident-response evidence and recovery requirements.

The decision is therefore driven by why the key is rotating, not by rotation as a calendar event.

Migrate without turning rotation into an outage

For data encrypted directly with the retiring key, migration generally requires decrypting the data with the old key and encrypting it with the new key. That operation temporarily handles plaintext inside the trusted application or cryptographic boundary, so the migration worker needs carefully limited access.

A safe migration process should be restartable. Process bounded batches, record successful completion, and make repeated execution harmless where practical. If a batch fails halfway through, the system should still know the key version for every record rather than relying on a global assumption that the migration is complete.

For each object, the conceptual transition is:

ciphertext v1
    |
decrypt with v1
    |
encrypt with v2
    |
ciphertext v2

Do not remove version 1 merely because the migration job reported success. Independently verify that no required ciphertext still references it.

Envelope-encryption systems can make this operation cheaper. When data is encrypted with a data encryption key and only that data key is wrapped by a key-encryption key, some rotations can rewrap the data key under a new key-encryption key instead of decrypting and re-encrypting the entire payload. Whether that is valid depends on which key is being replaced and on the guarantees of the key-management system. It does not remove the need to track key versions and verify migration.

Treat retirement as a separate security decision

A key is not retired when new encryption stops using it. It is retired when the system no longer needs it for legitimate operations and the organization has deliberately removed or disabled its use according to the key-management design.

Before retirement, verify at least three facts in the system’s own terms: no new writes use the old version, no retained ciphertext requires it, and required recovery paths do not depend on it.

The last point is easy to miss. Backups can contain ciphertext that is older than the live database. Deleting an old key can make an otherwise healthy backup impossible to restore. If backups must remain recoverable, their key dependencies need to be included in the retirement decision.

A useful recovery test is stronger than checking that a backup file exists. Restore representative encrypted data in an isolated recovery environment and prove that the required keys and authorization paths are available there.

Avoid the common shortcuts

One dangerous shortcut is to replace a key value in configuration while leaving ciphertext unchanged. Encryption is not a password lookup: ciphertext created with one key does not become decryptable with another merely because the application’s current configuration changed.

Another mistake is keeping an unversioned current_key and assuming all data uses it. That assumption is fragile during deployments, rollback, migrations, and restores. Explicit key identity lets the data state describe reality.

Do not delete an old key immediately after switching new writes. Deployment rollback, delayed jobs, replicas, backups, or unmigrated records may still require it. Instead, reduce its permissions where the platform permits, monitor remaining use, verify dependencies, and retire it only after those dependencies are gone.

Finally, rotation should not grant broad key access to make migration convenient. A migration worker that can use every key against every dataset creates a powerful new trust boundary. Restrict its data scope, key permissions, runtime lifetime, and operator access according to the sensitivity of the system.

Verify rotation as a security control

A rotation process should produce evidence that its intended state actually exists.

After switching writes, sample or query newly encrypted objects and confirm that they reference the new key version. During migration, measure how many required objects still reference the retiring version. Investigate unexpected uses of an old key rather than treating them as harmless noise.

Before retirement, test the normal read path and the recovery path. If the key-management platform supports disabling a key reversibly, a controlled disable-and-observe stage can reveal hidden dependencies before irreversible destruction. Whether that step is appropriate depends on platform behavior and application availability requirements.

Key-use logs are especially valuable here. They can show that a supposedly retired version is still being requested by a forgotten service or background job. Logs do not prove that every ciphertext has migrated, but they complement inventory checks by showing actual runtime dependence.

Choose the amount of rotation your threat model needs

A small application with short-lived encrypted data may need only explicit key versions, a controlled switch for new writes, and retirement after the old data expires. Building a complex migration service would add operational risk without much benefit.

A system holding long-lived or high-impact data may justify automated migration, detailed key-use monitoring, tested recovery procedures, and separate permissions for key creation, activation, migration, and retirement. Suspected key compromise usually demands faster containment and more careful treatment of existing ciphertext than routine rotation.

The key decision is not how frequently a key can be changed. It is whether the system can change it without losing track of which data depends on which key.

Conclusion

Safe key rotation is a state transition, not a key-generation event. Give ciphertext an explicit key identity, switch new encryption to the replacement key, preserve old decryption only while it is needed, migrate existing data when the threat model requires it, and verify recovery before retiring anything.

That approach does not eliminate the consequences of key compromise. It does make those consequences easier to contain, gives developers a reliable way to move away from old key material, and turns retirement into a decision supported by evidence rather than hope.