HashiCorp Vault — Transit Exercises
Practice encryption, key rotation, envelope encryption, and signing.
Exercise 1 — Basic Encrypt/Decrypt
Task: Encrypt sensitive data and decrypt it.
- Enable the Transit engine
- Create an encryption key called
app-key - Encrypt the string “SSN:123-45-6789”
- Decrypt it back to plaintext
- Verify you get the original string
Show Answer
# 1. Enable Transit
vault secrets enable transit
# 2. Create key
vault write -f transit/keys/app-key
# 3. Encrypt
CIPHERTEXT=$(vault write -field=ciphertext transit/encrypt/app-key \
plaintext=$(echo -n "SSN:123-45-6789" | base64))
echo "Ciphertext: $CIPHERTEXT"
# 4. Decrypt
PLAINTEXT_B64=$(vault write -field=plaintext transit/decrypt/app-key \
ciphertext="$CIPHERTEXT")
# 5. Verify
echo "$PLAINTEXT_B64" | base64 --decode
# SSN:123-45-6789
Exercise 2 — Key Rotation and Rewrap
Task: Rotate an encryption key and rewrap existing data.
- Encrypt “my-secret” with key version 1
- Rotate the key
- Encrypt “another-secret” — verify it uses version 2
- Rewrap the first ciphertext to version 2
- Verify the old v1 ciphertext still decrypts
- Set min_decryption_version to 2 and try to decrypt the old v1 ciphertext
Show Answer
# 1. Encrypt with v1
CT_V1=$(vault write -field=ciphertext transit/encrypt/app-key \
plaintext=$(echo -n "my-secret" | base64))
echo "V1 ciphertext: $CT_V1"
# vault:v1:...
# 2. Rotate
vault write -f transit/keys/app-key/rotate
# 3. Encrypt with v2
CT_V2=$(vault write -field=ciphertext transit/encrypt/app-key \
plaintext=$(echo -n "another-secret" | base64))
echo "V2 ciphertext: $CT_V2"
# vault:v2:...
# 4. Rewrap v1 ciphertext
CT_REWRAPPED=$(vault write -field=ciphertext transit/rewrap/app-key \
ciphertext="$CT_V1")
echo "Rewrapped: $CT_REWRAPPED"
# vault:v2:... (new ciphertext, same plaintext)
# 5. Old v1 still decrypts
vault write -field=plaintext transit/decrypt/app-key \
ciphertext="$CT_V1" | base64 --decode
# my-secret ✅
# 6. Set min_decryption_version
vault write transit/keys/app-key/config min_decryption_version=2
vault write transit/decrypt/app-key ciphertext="$CT_V1"
# Error! Cannot decrypt — below minimum decryption version
# But rewrapped ciphertext works
vault write -field=plaintext transit/decrypt/app-key \
ciphertext="$CT_REWRAPPED" | base64 --decode
# my-secret ✅
Exercise 3 — Envelope Encryption
Task: Use envelope encryption to encrypt a file.
- Generate a datakey
- Use the plaintext key to encrypt a file with OpenSSL
- Store the encrypted key alongside the encrypted file
- Discard the plaintext key
- Later: decrypt the datakey via Vault, then decrypt the file
Show Answer
# Create a test file
echo "This is sensitive data that needs encryption" > /tmp/sensitive.txt
# 1. Generate datakey
RESPONSE=$(vault write -format=json transit/datakey/plaintext/app-key)
PLAINTEXT_KEY=$(echo "$RESPONSE" | jq -r .data.plaintext)
ENCRYPTED_KEY=$(echo "$RESPONSE" | jq -r .data.ciphertext)
# 2. Encrypt the file
echo "$PLAINTEXT_KEY" | base64 --decode > /tmp/datakey.bin
openssl enc -aes-256-cbc -pbkdf2 \
-in /tmp/sensitive.txt \
-out /tmp/sensitive.txt.enc \
-pass file:/tmp/datakey.bin
# 3. Store encrypted key
echo "$ENCRYPTED_KEY" > /tmp/sensitive.txt.key
# 4. Discard plaintext key
rm /tmp/datakey.bin
unset PLAINTEXT_KEY
# 5. Decrypt: recover the datakey
RECOVERED_KEY=$(vault write -field=plaintext transit/decrypt/app-key \
ciphertext="$(cat /tmp/sensitive.txt.key)")
echo "$RECOVERED_KEY" | base64 --decode > /tmp/datakey.bin
# Decrypt the file
openssl enc -aes-256-cbc -pbkdf2 -d \
-in /tmp/sensitive.txt.enc \
-out /tmp/sensitive-recovered.txt \
-pass file:/tmp/datakey.bin
cat /tmp/sensitive-recovered.txt
# This is sensitive data that needs encryption
# Cleanup
rm /tmp/datakey.bin /tmp/sensitive.txt.enc /tmp/sensitive.txt.key
Exercise 4 — Digital Signatures
Task: Sign and verify data.
- Create an ed25519 signing key
- Sign the message “deploy-v2.3.1”
- Verify the signature
- Tamper with the message and verify again — should fail
Show Answer
# 1. Create signing key
vault write transit/keys/deploy-signer type=ed25519
# 2. Sign
SIGNATURE=$(vault write -field=signature transit/sign/deploy-signer \
input=$(echo -n "deploy-v2.3.1" | base64))
echo "Signature: $SIGNATURE"
# 3. Verify (should be valid=true)
vault write transit/verify/deploy-signer \
input=$(echo -n "deploy-v2.3.1" | base64) \
signature="$SIGNATURE"
# valid: true ✅
# 4. Tamper with message
vault write transit/verify/deploy-signer \
input=$(echo -n "deploy-v2.3.1-TAMPERED" | base64) \
signature="$SIGNATURE"
# valid: false ❌
Exercise 5 — Transit Policy
Task: Write a policy that allows an application to encrypt and decrypt with a specific key, but NOT rotate or delete the key.
Show Answer
# app-transit-policy.hcl
# Encrypt and decrypt
path "transit/encrypt/app-key" {
capabilities = ["update"]
}
path "transit/decrypt/app-key" {
capabilities = ["update"]
}
# Generate data keys (for envelope encryption)
path "transit/datakey/plaintext/app-key" {
capabilities = ["update"]
}
# Read key info (but not the key material)
path "transit/keys/app-key" {
capabilities = ["read"]
}
# Explicitly deny key management
path "transit/keys/app-key/rotate" {
capabilities = ["deny"]
}
path "transit/keys/app-key/config" {
capabilities = ["deny"]
}
vault policy write app-transit app-transit-policy.hcl
TOKEN=$(vault token create -policy=app-transit -ttl=1h -field=token)
# Can encrypt
VAULT_TOKEN=$TOKEN vault write transit/encrypt/app-key \
plaintext=$(echo -n "test" | base64)
# Success ✅
# Cannot rotate
VAULT_TOKEN=$TOKEN vault write -f transit/keys/app-key/rotate
# Error: permission denied ❌
What’s Next?
With Transit mastered, let’s move to Vault as a Certificate Authority with the PKI secrets engine.
Next Chapter: PKI Secrets Engine