Skip to content
6 min read·Lesson 6 of 8

Encryption as a Service (Transit Engine)

Use Vault's Transit engine to encrypt and decrypt application data without applications ever seeing the key material.

Application encryption is a recurring source of bugs: developers pick weak algorithms, hardcode IVs, forget to authenticate, store keys next to data. Vault's Transit secrets engine solves this by making Vault itself the cryptographic operation provider. Apps never see keys; they call Vault to encrypt and decrypt.

The Core Model

App → "encrypt this plaintext with key 'orders-pii'" → Vault
Vault → ciphertext
App → stores ciphertext in DB
…
App → "decrypt this ciphertext with key 'orders-pii'" → Vault
Vault → plaintext

The encryption key lives inside Vault, protected by Vault's barrier. The app holds only ciphertext.

Setting Up Transit

vault secrets enable transit

# Create a named key
vault write -f transit/keys/orders-pii

# Inspect
vault read transit/keys/orders-pii

The key has a type (default: aes256-gcm96), a list of versions, and configuration: deletion_allowed, exportable, allow_plaintext_backup, etc.

Encrypt and Decrypt

vault write transit/encrypt/orders-pii \
  plaintext=$(echo -n "Alice's SSN: 123-45-6789" | base64)
# Returns: ciphertext=vault:v1:abc...

vault write transit/decrypt/orders-pii \
  ciphertext=vault:v1:abc...
# Returns: plaintext (base64-encoded)

The vault:v1: prefix encodes the key version. When you rotate the key, new encrypts use v2:; existing v1: ciphertexts continue to decrypt because Vault retains old versions.

Key Rotation

vault write -f transit/keys/orders-pii/rotate
vault read transit/keys/orders-pii
# Now shows latest_version=2

All new encrypts use v2. Old v1 ciphertexts still decrypt. To force migration of stored ciphertexts to the new key version, use rewrap:

vault write transit/rewrap/orders-pii ciphertext=vault:v1:abc...
# Returns: ciphertext=vault:v2:xyz... (same plaintext, new key version)

Rewrap doesn't expose the plaintext to the caller — Vault rewraps internally. You can run a one-off job that scans your DB, calls rewrap on every ciphertext, and migrates the column.

Min Decryption Version

Once you've rewrapped all data to the new version, you can retire the old version by setting min_decryption_version:

vault write transit/keys/orders-pii/config min_decryption_version=2

Vault will refuse to decrypt v1 ciphertexts. Combined with min_encryption_version, this enforces a key-rotation lifecycle.

Convergent Encryption

By default, Transit uses a random nonce, so encrypting the same plaintext twice produces different ciphertexts (secure, but not searchable). Convergent encryption derives the nonce from the plaintext and a context, producing deterministic ciphertext for the same input:

vault write -f transit/keys/email-pii \
  type=aes256-gcm96 \
  convergent_encryption=true \
  derived=true

Use case: encrypting an email address column where you need to look up by encrypted value. The cost: leaking equality patterns. Use sparingly and with awareness of the tradeoff.

Data Keys

For very large data (multi-megabyte files), it's inefficient to ship every byte to Vault. The datakey pattern:

  1. App asks Vault: "Generate a data key under 'orders-pii'"
  2. Vault returns: plaintext AES key + ciphertext (the plaintext key encrypted by the master)
  3. App encrypts the large data locally with the plaintext key, in memory
  4. App stores the ciphertext data + ciphertext key alongside
  5. App discards the plaintext key
  6. To decrypt: app sends ciphertext key to Vault, gets plaintext key, decrypts the data locally

This is exactly how AWS KMS envelope encryption works. Vault Transit can serve the same role.

Sign, Verify, HMAC

Transit isn't just symmetric encryption. You can also:

  • Generate signing keys (RSA, ECDSA, Ed25519) and sign payloads
  • Verify signatures
  • Generate HMAC of an input (useful for tokenisation, deterministic hashing)
  • Encrypt with asymmetric keys (RSA-OAEP)
vault write -f transit/keys/jwt-signer type=rsa-2048
vault write transit/sign/jwt-signer input=$(echo -n '{"sub":"alice"}' | base64)

This is how some teams implement JWT signing without ever giving the app the private key.

Performance and Caching

Transit operations are CPU-bound on the Vault server. Benchmarks: a 4-vCPU Vault instance handles thousands of encrypts/decrypts per second. For higher throughput, scale Vault horizontally and use a load balancer.

Apps should cache decrypted plaintexts in memory (with care) when the same value is read repeatedly — never bypass Vault to "save calls", but don't decrypt the same row twice per request either.

Policies for Transit

path "transit/encrypt/orders-pii" { capabilities = ["update"] }
path "transit/decrypt/orders-pii" { capabilities = ["update"] }

Note: encrypt/decrypt are update in Vault's model (the request body changes), not read. You can grant a service the right to encrypt only (write-only data flow) by omitting the decrypt path — useful for log shippers that need to encrypt PII but should never read it back.

When to Use Transit

Use caseUse Transit?
Encrypt a few sensitive DB columns (PII, payment data)Yes — perfect fit
File-level disk encryptionUse OS LUKS/dm-crypt; Transit is overkill
Sign JWTs without storing private keys in appsYes
Replace AWS KMS for envelope encryptionYes — and you become multi-cloud
Encrypt very small request payloadsYes — minimal overhead
Bulk encryption of TBs of dataUse datakey pattern — don't ship the bytes

Transit lets you treat encryption as a service, not as a per-app implementation problem — and centralised key management is the single biggest improvement most apps can make to their encryption story.

Key Takeaways

  • Transit makes Vault an encryption oracle: send plaintext, get ciphertext; never expose the key.
  • Apps can encrypt at-rest data (database fields, files) with a per-named-key policy.
  • Key rotation is centralised — rotate once, decrypt continues to work via key versioning.
  • Convergent encryption produces deterministic ciphertext for searchability (with security tradeoffs).
  • Datakey, sign/verify, HMAC, and rewrap operations cover most cryptographic needs.

Test your knowledge

Try exam-style practice questions to reinforce what you've learned.

Practice Questions →