Offloading Encryption Logic with Vault Transit
Stop managing encryption keys in your app code. Learn how to use Vault's Transit Secrets Engine to implement encryption-as-a-service for PII and sensitive data.
20 Aug 2025, 22:28 UTC

The Burden of Local Key Management
When an application needs to protect Personally Identifiable Information (PII) at rest, the immediate instinct is to implement a library for AES-256 encryption. However, the actual encryption algorithm is rarely the hard part. The operational failure points are key rotation, secure key storage, and access auditing. If a developer hardcodes a key in an environment variable or stores it in a config file, the encryption becomes a formality rather than a security boundary.
The goal is to separate the data from the key. By treating encryption as a service rather than a local function, you can rotate keys and audit every single decryption event without modifying your application code or redeploying services.
Encryption-as-a-Service via Transit
The Vault Transit Secrets Engine provides a way to encrypt and decrypt data without ever exposing the raw encryption keys to the application. Instead of the application asking Vault for a key to perform the work locally, the application sends the plaintext to Vault, and Vault returns the ciphertext.
This pattern, known as Encryption-as-a-Service, ensures that the keys never leave Vault's secure memory. The application only needs the permission to call the /encrypt and /decrypt endpoints for a specific named key. This simplifies compliance (such as GDPR or PCI-DSS) because you can prove exactly who accessed the decryption endpoint and when.
Implementation Walkthrough
To implement this, you first need a running Vault instance. For testing, a development server is sufficient. The following steps assume you are using the Vault CLI with administrative permissions.
1. Enable the Engine and Create a Key
Run these commands on your local terminal or the machine where the Vault CLI is configured to communicate with the server:
# Enable the transit secrets engine
vault secrets enable transit
# Create a named key called 'customer-data'
vault write -f transit/keys/customer-data
2. Encrypting Data
To encrypt a value, you send it to the encrypt endpoint. Note that Vault expects the plaintext to be base64 encoded when using the CLI.
# Encrypt the string '[contact removed]'
# The echo -n prevents trailing newlines from being encrypted
vault write transit/encrypt/customer-data plaintext=$(echo -n "[contact removed]" | base64)
Expected Result: Vault returns a ciphertext string starting with vault:v1:. The v1 indicates the version of the key used, which is critical for seamless key rotation.
3. Decrypting Data
To retrieve the original value, send the ciphertext back to the decrypt endpoint:
# Replace <CIPHERTEXT> with the value received from the previous step
vault write transit/decrypt/customer-data ciphertext=<CIPHERTEXT>
Vault will return the base64 encoded plaintext, which you can then decode to verify it matches the original input.
Performance and Reliability Trade-offs
Moving encryption to a network service introduces a critical dependency: latency. Every time your application needs to read or write a sensitive field, it must perform a network round-trip to Vault. For high-throughput applications (thousands of requests per second), this can become a bottleneck.
| Approach | Key Security | Latency | Operational Overhead |
|---|---|---|---|
| Local Library | Low (Key exposure risk) | Negligible | High (Manual rotation) |
| Vault Transit | High (Keys stay in Vault) | Moderate (Network call) | Low (Automated rotation) |
To mitigate latency, consider batching requests using Vault's batch endpoints or evaluating if only a small subset of fields truly requires this level of isolation. Additionally, because Transit does not provide data integrity checks (like an HMAC) by default, you must ensure your database access controls prevent unauthorized modification of the ciphertext.
Verification and Safety
Before moving to production, verify your setup by measuring the round-trip time of 1,000 encrypt/decrypt cycles to ensure it fits within your application's SLA.
Warning: Transit keys are not recoverable if the Vault cluster is destroyed or the key is deleted. Ensure your Vault cluster is deployed in a High Availability (HA) configuration and that your backup strategy includes the Vault storage backend. If you lose the key, the ciphertext stored in your database becomes permanent noise.
Rollback
If you need to disable the Transit engine, be aware that this will make all data encrypted by that engine unreadable. Only run the following if you have decrypted your data or no longer need it:
vault secrets disable transit0 replies
A thoughtful contribution can make all the difference. Be the first to share one.