Choosing Between Vault Transit and KV v2 for Field-Level Encryption
Decide whether to protect application fields with Vault Transit envelope encryption or KV v2 secret storage, including CLI validation and rollback.
28 Nov 2025, 23:14 UTC

Decision: Where should field encryption happen?
Your application must persist sensitive fields—email addresses, national identifiers, or payment tokens—in its own database. You want HashiCorp Vault to manage the cryptographic keys so application code does not handle them directly. The decision is between two supported patterns:
- Vault Transit secrets engine: the application sends plaintext to Vault, receives ciphertext, and stores that ciphertext in its database. Vault never stores the plaintext.
- KV version 2 secrets engine: Vault stores the plaintext value at a secret path, and the application reads it back when needed.
Constraints to evaluate first
- Plaintext exposure. Can plaintext exist in application memory, logs, or database backups?
- Key rotation. Must you rotate keys without rewriting every stored row?
- Availability coupling. Can the application tolerate Vault latency or downtime during field reads and writes?
- Audit granularity. Do you need to know which cryptographic key was used, or only who read a secret path?
Supported options compared
| Factor | Transit envelope encryption | KV v2 secret storage |
|---|---|---|
| Plaintext inside Vault | No; Vault performs cryptography only and never stores plaintext | Yes; Vault stores and returns the plaintext value |
| Application database | Stores ciphertext produced by Vault | Stores a reference, or reads plaintext from Vault at runtime |
| Key rotation | New key version; existing ciphertexts can be re-encrypted or left for older key versions | New secret version; older values remain unless explicitly destroyed |
| Runtime dependency | Vault needed for encrypt and decrypt operations | Vault needed on every secret read |
| Audit events | Key usage and encrypt/decrypt operations | Read and write access to secret paths |
| Typical latency | Per cryptographic request | Single read per secret |
Trade-offs
Transit: ciphertext stays with the application
Transit is appropriate when the application database must not contain plaintext. Because Vault returns only ciphertext, a database leak does not expose readable fields without also compromising the Transit key. Key rotation does not require changing the ciphertext format; you can create a new key version and re-encrypt existing values at your own pace.
The trade-off is operational complexity. The application must base64-encode plaintext before sending it to Transit, store the resulting ciphertext string, and call Vault again to decrypt. Each field read or write adds a network round trip to Vault. Transit also does not store plaintext, so loss of the key or prolonged Vault unavailability makes stored ciphertext permanently undecryptable.
Convergent encryption is optional in Transit and must be explicitly enabled. By default, identical plaintexts produce different ciphertexts because Vault uses a random nonce. Do not enable convergent encryption unless you understand that it can reveal equality patterns in stored data.
KV v2: Vault becomes the plaintext repository
KV v2 simplifies application code: write a value once, read it back when needed, and rely on built-in versioning. This pattern fits configuration values, API tokens, or other secrets that the application needs in plaintext at runtime.
The trade-off is that Vault stores plaintext for those fields. A compromise of Vault, or an over-permissive policy, exposes the values directly. The application is also coupled to Vault availability for every read, and plaintext exists in application memory and potentially in application logs if developers log the response.
Implementation and validation
Run these commands from a machine with the Vault CLI installed and authenticated to a non-production Vault server. The token must have capabilities for sys/mounts/*, transit/*, and kv/*, or be a root/sudo token. Replace placeholders in angle brackets with your own values.
1. Enable Transit and create a key
vault secrets enable transit
vault write -f transit/keys/field-key
Required permissions. A token with sudo or policies allowing sys/mounts and transit/keys/create.
Expected check. Both commands return success without errors. Enabling a secrets engine persists in Vault storage; disabling it later removes the mount and its keys.
2. Encrypt a field value
Transit expects plaintext as base64. Encode the value outside Vault, then send it to the encrypt endpoint.
echo -n '[contact removed]' | base64
vault write transit/encrypt/field-key plaintext=
Expected check. The response includes a ciphertext value. Store that string in the application database column for the sensitive field. Do not store the original plaintext.
Risk. If the application loses the ciphertext or the Transit key is destroyed, the field cannot be recovered.
3. Decrypt and confirm round-trip
vault write transit/decrypt/field-key ciphertext=
Expected check. The response plaintext field decodes to the original value. If decryption fails, the ciphertext may have been created under a different key version or key name.
4. Contrast with KV v2
vault secrets enable -version=2 kv
vault write kv/field/email value='[contact removed]'
vault read kv/field/email
Expected check. The read command returns the plaintext value. To verify least privilege, test with a separate token:
vault token capabilities kv/field/email
A token without read permission on that path should return deny.
5. Verify audit logging
vault audit enable file file_path=/var/log/vault_audit.log
After enabling Transit encrypt/decrypt and KV read operations, inspect the audit log for events containing the requesting identity and the relevant path. This confirms that key usage and secret access are recorded separately.
Limitations and practical checks
- Transit has rate limits. Benchmark encrypt/decrypt throughput before using it for per-request field encryption at high volume.
- KV v2 responses include plaintext in memory. Avoid logging Vault responses or writing secret values to application logs.
- Production Vault deployments require TLS, authenticated tokens, and least-privilege policies. These CLI examples assume authentication is already configured.
- Key type and convergent encryption behavior can differ across Vault versions. Test rotation and re-encryption in a non-production cluster before changing production keys.
Practical check. Insert a test row containing Transit ciphertext, decrypt it through Vault, and compare the decoded output to the original plaintext. For KV v2, attempt a read with a token that lacks permission on the secret path and confirm the response is deny.
Rollback
Enabling secrets engines and creating keys changes Vault state. Rollback is destructive and should only be performed in a test cluster:
vault secrets disable transit
vault secrets disable kv
Disabling Transit removes the key and makes any stored ciphertext undecryptable. Disable KV v2 only after confirming no application or process depends on those secret paths.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.