Migrating ciphertext between Vault Transit key versions without re-encryption
Vault Transit's rewrap endpoint lets you migrate existing ciphertext to a new key version without decrypting and re-encrypting your data. Here's how it works, with a concrete example and trade-offs.
04 Nov 2025, 14:07 UTC

Rotating encryption keys without re-encrypting your data
Applications that store encrypted secrets often face a dreaded choice: rotate the key and re-encrypt everything, or keep an aging key and risk non-compliance. HashiCorp Vault's Transit secrets engine provides a third path.
The problem with naive key rotation
Traditional encryption requires decrypting data with the old key, then re-encrypting with the new one. At scale, this means moving terabytes of ciphertext, saturating I/O, and introducing windows where data is temporarily unprotected. Transit avoids this by keeping keys inside Vault and never exposing them to the application layer.
How Transit's rewrap endpoint works
Transit uses encryption as a service. The same plaintext always produces the same ciphertext for a given key version (convergent encryption), and each key can have multiple versions. The rewrap endpoint migrates existing ciphertext from an old key version to a new one without ever revealing the plaintext. The process is idempotent: running it twice yields the same result, and no downtime is required for the underlying data.
Concrete example: rewrap in practice
Assume you have a Vault CLI configured with a token that grants transit and keys capabilities. Replace placeholders with your actual key name and ciphertext values.
# Enable the Transit engine (once, if not already enabled)
vault secrets enable transit
# Create (or reuse) a key; the -f flag forces overwrite if needed
vault write -f transit/keys/my-key
# Encrypt a value and keep the ciphertext output
vault transit encrypt -key=my-key my-secret-value
# Later, rotate the key version (creates a new version without deleting old ones)
vault write transit/keys/my-key rotate
# Rewrap existing ciphertext to the new key version
# Replace old-ciphertext with the value returned from the encrypt step
vault transit rewrap -key=my-key -ciphertext=old-ciphertext
After rewrap, the returned ciphertext can be decrypted with the same key name using vault transit decrypt -key=my-key. If decryption returns the original plaintext, the migration was successful.
Where to run: Any machine with the Vault CLI installed and VAULT_ADDR/VAULT_TOKEN set.
Required permissions: A token with sudo-equivalent policies or a policy that allows transit/keys/* and transit/rewrap/*.
Meaningful placeholders: old-ciphertext — the ciphertext produced by the encrypt step; my-key — the named key in Transit.
Expected check: Decryption of the rewrapped ciphertext yields the original plaintext. If it fails, verify that the key version is enabled and the ciphertext was not corrupted.
Relevant risks: If Vault is unreachable, the command fails and the original ciphertext remains unchanged. Rewrap is idempotent, but if the target key version is disabled, the operation will error.
Trade-offs and limitations
- Payload size: Transit is not designed for very large files. Payloads exceeding 4 MB typically require external chunking logic before encryption.
- Performance: High-frequency encryption or rewrap calls can create a bottleneck at the Vault server. Consider local caching of encrypted values for read-heavy workloads.
- Availability: Decryption depends on Vault being reachable. If the Vault cluster is unavailable, your application cannot decrypt its data.
If you're new to Transit, start by enabling the engine and creating a key in a development or staging environment. Test encrypt, decrypt, and rewrap on non-critical data before rolling the pattern into production. The vault transit rewrap command is the core tool for key migration without data movement.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.