Secrets Engines¶
π Secrets Engines - Secrets engines overview
Overview¶
This document covers Vault secrets engines including KV (v1 and v2), Transit, PKI, Database, and AWS. Secrets engines represent 20% of the exam - the highest-weighted domain - and require understanding both configuration and use case selection.
KV Secrets Engine¶
KV v1 vs v2¶
| Feature | KV v1 | KV v2 |
|---|---|---|
| Versioning | No | Yes (configurable max versions) |
| Soft delete | No | Yes (undelete possible) |
| Destroy | No | Yes (permanent delete) |
| Metadata | No | Yes (custom metadata per secret) |
| Check-and-set | No | Yes (CAS parameter) |
| API path | <mount>/key | <mount>/data/key |
| Metadata path | N/A | <mount>/metadata/key |
π KV v2 - KV version 2 π KV v1 - KV version 1
KV v2 Operations¶
# Enable KV v2
vault secrets enable -path=secret kv-v2
# Write a secret
vault kv put secret/my-app/config username="admin" password="s3cret"
# Read a secret
vault kv get secret/my-app/config
# Read specific field
vault kv get -field=password secret/my-app/config
# Read specific version
vault kv get -version=2 secret/my-app/config
# List secrets
vault kv list secret/my-app/
# Delete (soft delete - can undelete)
vault kv delete secret/my-app/config
# Undelete version
vault kv undelete -versions=1 secret/my-app/config
# Permanently destroy version
vault kv destroy -versions=1 secret/my-app/config
# Delete all versions and metadata
vault kv metadata delete secret/my-app/config
# Read metadata
vault kv metadata get secret/my-app/config
# Set custom metadata
vault kv metadata put -custom-metadata=team="platform" secret/my-app/config
KV v2 Path Differences (Exam Trap)¶
CLI command: vault kv get secret/my-app
API path: /v1/secret/data/my-app (note /data/ in API)
Metadata API: /v1/secret/metadata/my-app
Delete API: /v1/secret/data/my-app (HTTP DELETE)
Destroy API: /v1/secret/destroy/my-app (HTTP POST)
- CLI
vault kvcommands do NOT include/data/in the path - API calls MUST include
/data/in the path for KV v2 - Policy paths MUST include
/data/for read/write operations - This is one of the most commonly tested exam traps
Check-and-Set (CAS)¶
# Write with check-and-set (prevent accidental overwrites)
vault kv put -cas=0 secret/my-app/config key=value # Only if key doesn't exist
vault kv put -cas=3 secret/my-app/config key=newvalue # Only if current version is 3
Transit Secrets Engine¶
Overview¶
- Encryption as a Service - encrypts/decrypts data without storing it
- Vault manages encryption keys internally
- Application sends plaintext, receives ciphertext (and vice versa)
- Supports key rotation without re-encrypting data
- Data never stored in Vault - only encrypted/decrypted
π Transit Engine - Encryption as a service
Operations¶
# Enable Transit
vault secrets enable transit
# Create encryption key
vault write -f transit/keys/my-key
# Encrypt data (base64-encoded plaintext required)
vault write transit/encrypt/my-key \
plaintext=$(echo -n "secret data" | base64)
# Returns: ciphertext = vault:v1:xxxxxxxxxxxxx
# Decrypt data
vault write transit/decrypt/my-key \
ciphertext="vault:v1:xxxxxxxxxxxxx"
# Returns: plaintext = c2VjcmV0IGRhdGE= (base64)
# Decode: echo "c2VjcmV0IGRhdGE=" | base64 -d
# Rotate key
vault write -f transit/keys/my-key/rotate
# New data uses v2, existing v1 ciphertext still decryptable
# Rewrap (re-encrypt with latest key version)
vault write transit/rewrap/my-key \
ciphertext="vault:v1:xxxxxxxxxxxxx"
# Returns: vault:v2:yyyyyyyyyyyyy
Key Types¶
| Type | Algorithm | Use Case |
|---|---|---|
| aes256-gcm96 | AES-256-GCM | General encryption (default) |
| chacha20-poly1305 | ChaCha20 | Performance on non-AES hardware |
| rsa-2048 | RSA-2048 | Asymmetric encryption/signing |
| rsa-4096 | RSA-4096 | Stronger asymmetric |
| ecdsa-p256 | ECDSA P-256 | Digital signatures |
| ed25519 | EdDSA | Digital signatures |
Key Rotation¶
- New key version created, old versions retained
- Existing ciphertext still decryptable with old key version
- New encryptions use latest key version
vault:v1:xxx= encrypted with key version 1vault:v2:xxx= encrypted with key version 2- Rewrap operation re-encrypts with latest version
PKI Secrets Engine¶
Overview¶
- Certificate authority (CA) that generates X.509 certificates
- Dynamic certificate issuance with configurable TTL
- Short-lived certificates reduce compromise risk
- Supports root and intermediate CA hierarchy
π PKI Engine - PKI documentation
# Enable PKI
vault secrets enable pki
# Set max lease TTL
vault secrets tune -max-lease-ttl=87600h pki
# Generate root CA
vault write pki/root/generate/internal \
common_name="Example Root CA" \
ttl=87600h
# Create role for issuing certificates
vault write pki/roles/web-server \
allowed_domains="example.com" \
allow_subdomains=true \
max_ttl=72h
# Issue a certificate
vault write pki/issue/web-server \
common_name="web.example.com" \
ttl=24h
Best Practices¶
- Use intermediate CA for issuing certificates (not root)
- Keep root CA offline or with very restricted access
- Set short TTLs (hours to days) for issued certificates
- Use separate PKI mounts for root and intermediate CAs
Database Secrets Engine¶
Overview¶
- Generates dynamic database credentials on demand
- Credentials unique per request and automatically revoked
- Supports MySQL, PostgreSQL, MongoDB, MSSQL, Oracle, and more
- Credential lifecycle managed via Vault leases
π Database Engine - Dynamic database credentials
# Enable database engine
vault secrets enable database
# Configure database connection
vault write database/config/my-postgres \
plugin_name=postgresql-database-plugin \
allowed_roles="app-role" \
connection_url="postgresql://{{username}}:{{password}}@db:5432/mydb?sslmode=disable" \
username="vault-admin" \
password="admin-password"
# Rotate root credentials (Vault manages the password)
vault write -f database/rotate-root/my-postgres
# Create role with creation statements
vault write database/roles/app-role \
db_name=my-postgres \
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
default_ttl=1h \
max_ttl=24h
# Generate dynamic credentials
vault read database/creds/app-role
# username: v-token-app-role-xxxxx
# password: A1a-yyyyyyyyy
# lease_id: database/creds/app-role/zzzzz
# lease_duration: 1h
Credential Lifecycle¶
- Application requests credentials from Vault
- Vault creates unique database user with configured permissions
- Vault returns credentials with a lease ID and TTL
- Application uses credentials to connect to database
- When lease expires, Vault revokes the database user
- Application must request new credentials before lease expiry
AWS Secrets Engine¶
Overview¶
- Generates dynamic AWS IAM credentials
- Three credential types: IAM user, STS AssumeRole, STS Federation
- Credentials automatically revoked when lease expires
π AWS Engine - Dynamic AWS credentials
# Enable AWS secrets engine
vault secrets enable aws
# Configure root credentials
vault write aws/config/root \
access_key="AKIAIOSFODNN7EXAMPLE" \
secret_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
region=us-east-1
# Create role for STS AssumeRole
vault write aws/roles/deploy \
credential_type=assumed_role \
role_arns="arn:aws:iam::123456789:role/deploy-role"
# Generate credentials
vault read aws/creds/deploy
Secrets Engine Management¶
# Enable at custom path
vault secrets enable -path=team-kv kv-v2
# List enabled engines
vault secrets list
# Tune engine (change default TTL)
vault secrets tune -default-lease-ttl=2h database/
# Disable engine (removes all data!)
vault secrets disable team-kv/
# Move engine to new path
vault secrets move secret/ kv/
Engine Selection Guide¶
| Need | Engine | Why |
|---|---|---|
| Store application config | KV (v2) | Static key-value storage |
| Encrypt data without storing | Transit | Encryption as a service |
| Generate TLS certificates | PKI | Dynamic certificate issuance |
| Database access | Database | Dynamic, short-lived credentials |
| AWS access | AWS | Dynamic IAM credentials |
| SSH access | SSH | Dynamic SSH credentials/signing |