HashiCorp Vault
A secrets management tool for securely storing, accessing, and managing sensitive data like tokens, passwords, certificates, and encryption keys.
HashiCorp Vault Cheatsheet
A secrets management tool for securely storing, accessing, and managing sensitive data like tokens, passwords, certificates, and encryption keys.
Overview
HashiCorp Vault provides a unified interface for managing secrets while providing tight access control and recording a detailed audit log. It handles leasing, key revocation, key rolling, and auditing, making it essential for modern infrastructure security.
graph TB
subgraph "Vault Architecture"
Client[Client Applications]
API[Vault API]
Auth[Authentication]
Policy[Policies]
subgraph "Secret Engines"
KV[KV Store]
DB[Database]
PKI[PKI Certificates]
Transit[Transit Encryption]
end
subgraph "Storage Backend"
Consul[Consul]
Raft[Integrated Raft]
S3[S3/Cloud Storage]
end
end
Client --> API
API --> Auth
Auth --> Policy
Policy --> KV
Policy --> DB
Policy --> PKI
Policy --> Transit
KV --> Consul
DB --> Raft
PKI --> S3
Secret Engines
Key Concepts
- Secret Engine: A component that stores, generates, or encrypts data
- Mount Path: The location where a secret engine is enabled (e.g.,
secret/,database/) - Versioning: KV v2 supports versioned secrets with history
- Lease: Time-bound access to secrets with automatic revocation
Common Commands
# List enabled secret engines
vault secrets list
# Enable a secret engine
vault secrets enable -path=secret kv-v2
vault secrets enable database
vault secrets enable pki
# Disable a secret engine
vault secrets disable secret/
# Tune secret engine settings
vault secrets tune -max-lease-ttl=87600h pki/
KV (Key-Value) Engine
# KV Version 2 (recommended)
vault secrets enable -version=2 -path=secret kv
# Write a secret
vault kv put secret/myapp/config username="admin" password="s3cr3t"
# Read a secret
vault kv get secret/myapp/config
vault kv get -field=password secret/myapp/config
# Read specific version
vault kv get -version=2 secret/myapp/config
# List secrets
vault kv list secret/myapp
# Delete secret (soft delete in v2)
vault kv delete secret/myapp/config
# Permanently destroy specific version
vault kv destroy -versions=1,2 secret/myapp/config
# Undelete a secret
vault kv undelete -versions=1 secret/myapp/config
# View metadata
vault kv metadata get secret/myapp/config
Database Secret Engine
# Enable database engine
vault secrets enable database
# Configure PostgreSQL connection
vault write database/config/my-postgresql-database \
plugin_name=postgresql-database-plugin \
allowed_roles="my-role" \
connection_url="postgresql://{{username}}:{{password}}@localhost:5432/mydb" \
username="vault-admin" \
password="vault-password"
# Create a role for dynamic credentials
vault write database/roles/my-role \
db_name=my-postgresql-database \
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/my-role
# Rotate root credentials
vault write -force database/rotate-root/my-postgresql-database
PKI Secret Engine
# Enable PKI engine
vault secrets enable pki
# Configure max lease TTL
vault secrets tune -max-lease-ttl=87600h pki/
# Generate root CA
vault write -field=certificate pki/root/generate/internal \
common_name="example.com" \
ttl=87600h > CA_cert.crt
# Configure CA and CRL URLs
vault write pki/config/urls \
issuing_certificates="http://vault.example.com:8200/v1/pki/ca" \
crl_distribution_points="http://vault.example.com:8200/v1/pki/crl"
# Create a role for issuing certificates
vault write pki/roles/example-dot-com \
allowed_domains="example.com" \
allow_subdomains=true \
max_ttl="720h"
# Issue a certificate
vault write pki/issue/example-dot-com \
common_name="app.example.com" \
ttl="24h"
# Revoke a certificate
vault write pki/revoke serial_number="<serial>"
Authentication Methods
Key Concepts
- Auth Method: A way to authenticate users or machines to Vault
- Token: The core authentication mechanism; all auth methods produce tokens
- Entity: A representation of a user or machine across auth methods
- Alias: Maps an auth method identity to an entity
flowchart LR
subgraph "Authentication Flow"
User[User/Application]
Auth[Auth Method]
Token[Vault Token]
Policy[Attached Policies]
Secret[Access Secrets]
end
User -->|Credentials| Auth
Auth -->|Validates| Token
Token -->|Authorises| Policy
Policy -->|Grants Access| Secret
Token Authentication
# Login with token
vault login <token>
# Create a new token
vault token create
# Create token with specific policy
vault token create -policy="my-policy" -ttl=1h
# Create orphan token (no parent)
vault token create -orphan
# Create periodic token
vault token create -period=24h
# Lookup current token
vault token lookup
# Lookup specific token
vault token lookup -accessor <accessor>
# Renew token
vault token renew
vault token renew -increment=1h
# Revoke token
vault token revoke <token>
vault token revoke -accessor <accessor>
# Revoke a token but orphan its children (leave them valid)
vault token revoke -mode=orphan <token>
Kubernetes Authentication
# Enable Kubernetes auth
vault auth enable kubernetes
# Configure Kubernetes auth
vault write auth/kubernetes/config \
kubernetes_host="https://kubernetes.default.svc:443" \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
token_reviewer_jwt=@/var/run/secrets/kubernetes.io/serviceaccount/token
# Create a role
vault write auth/kubernetes/role/myapp \
bound_service_account_names=myapp-sa \
bound_service_account_namespaces=default \
policies=myapp-policy \
ttl=1h
# Login from Kubernetes pod
vault write auth/kubernetes/login \
role=myapp \
jwt=@/var/run/secrets/kubernetes.io/serviceaccount/token
AppRole Authentication
# Enable AppRole auth
vault auth enable approle
# Create an AppRole
vault write auth/approle/role/my-app \
secret_id_ttl=10m \
token_num_uses=10 \
token_ttl=20m \
token_max_ttl=30m \
secret_id_num_uses=40 \
policies="my-policy"
# Get RoleID
vault read auth/approle/role/my-app/role-id
# Generate SecretID
vault write -f auth/approle/role/my-app/secret-id
# Login with AppRole
vault write auth/approle/login \
role_id="<role-id>" \
secret_id="<secret-id>"
# Destroy specific SecretID
vault write auth/approle/role/my-app/secret-id/destroy \
secret_id="<secret-id>"
Other Auth Methods
# LDAP Authentication
vault auth enable ldap
vault write auth/ldap/config \
url="ldaps://ldap.example.com" \
userdn="ou=Users,dc=example,dc=com" \
groupdn="ou=Groups,dc=example,dc=com" \
groupfilter="(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={{.UserDN}}))"
vault login -method=ldap username=mitchellh
# GitHub Authentication
vault auth enable github
vault write auth/github/config organization=myorg
vault write auth/github/map/teams/engineering value=eng-policy
vault login -method=github token="<github-token>"
# OIDC Authentication
vault auth enable oidc
vault write auth/oidc/config \
oidc_discovery_url="https://accounts.google.com" \
oidc_client_id="<client-id>" \
oidc_client_secret="<client-secret>" \
default_role="demo"
Policies and Access Control
Key Concepts
- Policy: A named set of permissions written in HCL or JSON
- Capabilities: The operations allowed (create, read, update, delete, list, sudo, deny)
- Path: The secret path the policy applies to
- Templating: Dynamic policy paths using identity information
Policy Syntax
# Example policy: my-policy.hcl
# Allow full access to app secrets
path "secret/data/myapp/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
# Read-only access to shared secrets
path "secret/data/shared/*" {
capabilities = ["read", "list"]
}
# Deny access to admin secrets
path "secret/data/admin/*" {
capabilities = ["deny"]
}
# Allow managing own tokens
path "auth/token/renew-self" {
capabilities = ["update"]
}
path "auth/token/revoke-self" {
capabilities = ["update"]
}
# Use templating for user-specific paths
path "secret/data/users/{{identity.entity.name}}/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
# Require specific parameters
path "secret/data/restricted" {
capabilities = ["create", "update"]
required_parameters = ["reason"]
allowed_parameters = {
"reason" = []
"data" = []
}
}
# Control response wrapping
path "secret/data/wrapped" {
capabilities = ["read"]
min_wrapping_ttl = "1m"
max_wrapping_ttl = "90m"
}
Policy Management Commands
# Write a policy
vault policy write my-policy my-policy.hcl
# Read a policy
vault policy read my-policy
# List all policies
vault policy list
# Delete a policy
vault policy delete my-policy
# Format policy file
vault policy fmt my-policy.hcl
# Test a policy (requires sudo)
vault token capabilities secret/myapp/config
Built-in Policies
# Default policy - attached to all tokens
vault policy read default
# Root policy - superuser access (cannot be modified)
vault policy read root
# Create admin policy
cat > admin-policy.hcl << 'EOF'
# Manage secrets engines
path "sys/mounts/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
# Manage auth methods
path "sys/auth/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
# Manage policies
path "sys/policies/acl/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
# List policies
path "sys/policies/acl" {
capabilities = ["list"]
}
# Read system health
path "sys/health" {
capabilities = ["read", "sudo"]
}
EOF
vault policy write admin admin-policy.hcl
Dynamic Secrets
Key Concepts
- Dynamic Secrets: Credentials generated on-demand with automatic expiration
- Lease: Time-bound validity period for dynamic secrets
- Revocation: Automatic or manual invalidation of credentials
- Rotation: Automatic renewal of credentials
Database Dynamic Secrets
# MySQL dynamic credentials
vault write database/config/mysql-db \
plugin_name=mysql-database-plugin \
connection_url="{{username}}:{{password}}@tcp(127.0.0.1:3306)/" \
allowed_roles="readonly,readwrite" \
username="vault" \
password="vaultpassword"
vault write database/roles/readonly \
db_name=mysql-db \
creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; \
GRANT SELECT ON *.* TO '{{name}}'@'%';" \
default_ttl="1h" \
max_ttl="24h"
# Generate credentials
vault read database/creds/readonly
# Output:
# Key Value
# --- -----
# lease_id database/creds/readonly/abcd1234
# lease_duration 1h
# lease_renewable true
# password A1a-xxxxxxxxxxxxxx
# username v-token-readonly-xxxxxxxxxx
AWS Dynamic Secrets
# 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=eu-west-1
# Create IAM user role
vault write aws/roles/my-role \
credential_type=iam_user \
policy_document=-<<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
]
}
EOF
# Create assumed role
vault write aws/roles/assumed-role \
credential_type=assumed_role \
role_arns=arn:aws:iam::123456789012:role/MyRole
# Generate credentials
vault read aws/creds/my-role
Lease Management
# List all leases
vault list sys/leases/lookup/database/creds/my-role
# Lookup lease information
vault lease lookup database/creds/my-role/abcd1234
# Renew a lease
vault lease renew database/creds/my-role/abcd1234
vault lease renew -increment=1h database/creds/my-role/abcd1234
# Revoke a specific lease
vault lease revoke database/creds/my-role/abcd1234
# Revoke all leases for a path
vault lease revoke -prefix database/creds/my-role
# Force revoke (skip backend cleanup)
vault lease revoke -force database/creds/my-role/abcd1234
Secret Rotation
Key Concepts
- Static Rotation: Manual or scheduled rotation of existing credentials
- Automatic Rotation: Vault automatically rotates credentials on a schedule
- Root Rotation: Rotating the credentials Vault uses to connect to backends
Database Root Credential Rotation
# Rotate root credentials (Vault manages new password)
vault write -force database/rotate-root/my-postgresql-database
# Configure static role with rotation
vault write database/static-roles/my-static-role \
db_name=my-postgresql-database \
rotation_statements="ALTER USER \"{{name}}\" WITH PASSWORD '{{password}}';" \
username="existing-db-user" \
rotation_period=86400
# Get static credentials
vault read database/static-creds/my-static-role
# Force rotation
vault write -force database/rotate-role/my-static-role
PKI Certificate Rotation
# Rotate intermediate CA
vault write pki_int/intermediate/generate/internal \
common_name="example.com Intermediate Authority" \
| vault write pki/root/sign-intermediate \
csr=- \
format=pem_bundle \
ttl=43800h
# Set signed certificate
vault write pki_int/intermediate/set-signed \
certificate=@signed_certificate.pem
# Tidy up expired certificates
vault write pki/tidy \
tidy_cert_store=true \
tidy_revoked_certs=true \
safety_buffer=72h
Token Rotation
# Rotate accessor (invalidates old token)
vault token create -policy="my-policy" -renewable=true
# Auto-renew tokens in applications
while true; do
vault token renew -increment=1h
sleep 3000 # Renew before expiry
done
CLI Essentials
Basic Operations
# Set Vault address
export VAULT_ADDR='https://vault.example.com:8200'
# Set token (not recommended for production)
# Service tokens are prefixed hvs. (s. on Vault < 1.10)
export VAULT_TOKEN='hvs.xxxxxxxxxx'
# Login interactively
vault login
# Check Vault status
vault status
# View help
vault path-help secret/
vault path-help sys/mounts
Read Operations
# Read a secret
vault read secret/myapp/config
# Read specific field
vault read -field=password secret/myapp/config
# Output as JSON
vault read -format=json secret/myapp/config
# Output as YAML
vault read -format=yaml secret/myapp/config
# Read with jq processing
vault read -format=json secret/myapp/config | jq -r '.data.data.password'
Write Operations
# Write key-value pairs
vault write secret/myapp/config username="admin" password="secret"
# Write from file
vault write secret/myapp/config @data.json
# Write from stdin
echo '{"username": "admin", "password": "secret"}' | vault write secret/myapp/config -
# Force write (no input)
vault write -force sys/leases/revoke-prefix/database/
# Write with output
vault write -format=json auth/approle/login role_id="xxx" secret_id="yyy"
Delete and List Operations
# Delete a secret
vault delete secret/myapp/config
# List secrets
vault list secret/
vault list -format=json secret/
# List with detailed output
vault list -detailed auth/token/accessors
Advanced CLI Usage
# Wrap response
vault read -wrap-ttl=10m secret/myapp/config
# Unwrap response
vault unwrap <wrapping_token>
# Use namespaces (Enterprise)
vault read -namespace=team1 secret/myapp/config
export VAULT_NAMESPACE=team1
# Enable audit logging
vault audit enable file file_path=/var/log/vault/audit.log
# Seal Vault (emergency)
vault operator seal
# Unseal Vault
vault operator unseal <key>
# Generate new unseal keys
vault operator rekey -init -key-shares=5 -key-threshold=3
Integration Patterns
Kubernetes Integration
flowchart TB
subgraph "Kubernetes Cluster"
Pod[Application Pod]
SA[Service Account]
Init[Vault Init Container]
Sidecar[Vault Agent Sidecar]
end
subgraph "HashiCorp Vault"
VaultAPI[Vault API]
K8sAuth[Kubernetes Auth]
Secrets[Secret Engine]
end
Pod --> SA
SA --> Init
Init --> VaultAPI
VaultAPI --> K8sAuth
K8sAuth --> Secrets
Sidecar --> VaultAPI
Vault Agent Injector
# Deployment with Vault Agent annotations
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "myapp"
vault.hashicorp.com/agent-inject-secret-config: "secret/data/myapp/config"
vault.hashicorp.com/agent-inject-template-config: |
{{- with secret "secret/data/myapp/config" -}}
export DB_USER="{{ .Data.data.username }}"
export DB_PASS="{{ .Data.data.password }}"
{{- end }}
spec:
serviceAccountName: myapp-sa
containers:
- name: myapp
image: myapp:latest
command: ["/bin/sh", "-c", "source /vault/secrets/config && ./start.sh"]
External Secrets Operator
# SecretStore for Vault
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
spec:
provider:
vault:
server: "https://vault.example.com:8200"
path: "secret"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "external-secrets"
serviceAccountRef:
name: "external-secrets-sa"
---
# ExternalSecret
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: myapp-secrets
spec:
refreshInterval: "1h"
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: myapp-secrets
data:
- secretKey: username
remoteRef:
key: secret/myapp/config
property: username
- secretKey: password
remoteRef:
key: secret/myapp/config
property: password
CI/CD Integration
GitHub Actions
name: Deploy with Vault Secrets
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Import Secrets
uses: hashicorp/vault-action@v2
with:
url: https://vault.example.com:8200
method: jwt
role: github-actions
secrets: |
secret/data/myapp/config username | DB_USER ;
secret/data/myapp/config password | DB_PASS ;
secret/data/myapp/config api_key | API_KEY
- name: Deploy Application
run: |
echo "Deploying with secrets..."
./deploy.sh
env:
DB_USER: ${{ env.DB_USER }}
DB_PASS: ${{ env.DB_PASS }}
GitLab CI
# .gitlab-ci.yml
variables:
VAULT_ADDR: https://vault.example.com:8200
deploy:
image: hashicorp/vault:latest
script:
- export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=gitlab-ci jwt=$CI_JOB_JWT)"
- export DB_PASS=$(vault kv get -field=password secret/myapp/config)
- ./deploy.sh
id_tokens:
VAULT_ID_TOKEN:
aud: https://vault.example.com
Jenkins Pipeline
pipeline {
agent any
environment {
VAULT_ADDR = 'https://vault.example.com:8200'
}
stages {
stage('Retrieve Secrets') {
steps {
withVault(
configuration: [
vaultUrl: "${VAULT_ADDR}",
vaultCredentialId: 'vault-approle'
],
vaultSecrets: [
[
path: 'secret/myapp/config',
secretValues: [
[envVar: 'DB_USER', vaultKey: 'username'],
[envVar: 'DB_PASS', vaultKey: 'password']
]
]
]
) {
sh './deploy.sh'
}
}
}
}
}
Application Integration
Python (hvac)
import hvac
# Token authentication
client = hvac.Client(
url='https://vault.example.com:8200',
token='hvs.xxxxxxxxxx'
)
# AppRole authentication
client = hvac.Client(url='https://vault.example.com:8200')
client.auth.approle.login(
role_id='role-id',
secret_id='secret-id'
)
# Read secret
secret = client.secrets.kv.v2.read_secret_version(
path='myapp/config',
mount_point='secret'
)
username = secret['data']['data']['username']
password = secret['data']['data']['password']
# Write secret
client.secrets.kv.v2.create_or_update_secret(
path='myapp/config',
secret={'username': 'admin', 'password': 'newpass'},
mount_point='secret'
)
# Generate dynamic database credentials
creds = client.secrets.database.generate_credentials(
name='my-role',
mount_point='database'
)
db_user = creds['data']['username']
db_pass = creds['data']['password']
Go
package main
import (
"context"
"fmt"
"log"
vault "github.com/hashicorp/vault/api"
)
func main() {
config := vault.DefaultConfig()
config.Address = "https://vault.example.com:8200"
client, err := vault.NewClient(config)
if err != nil {
log.Fatal(err)
}
// Set token
client.SetToken("hvs.xxxxxxxxxx")
// Read secret
secret, err := client.KVv2("secret").Get(
context.Background(),
"myapp/config",
)
if err != nil {
log.Fatal(err)
}
username := secret.Data["username"].(string)
password := secret.Data["password"].(string)
fmt.Printf("Username: %s\n", username)
}
Node.js
const vault = require('node-vault')({
apiVersion: 'v1',
endpoint: 'https://vault.example.com:8200',
token: 'hvs.xxxxxxxxxx'
});
// Read secret (KV v2)
async function getSecret() {
const result = await vault.read('secret/data/myapp/config');
const { username, password } = result.data.data;
return { username, password };
}
// AppRole login
async function loginAppRole(roleId, secretId) {
const result = await vault.approleLogin({
role_id: roleId,
secret_id: secretId
});
vault.token = result.auth.client_token;
}
// Write secret
async function writeSecret(path, data) {
await vault.write(`secret/data/${path}`, {
data: data
});
}
Quick Reference
| Command | Description |
|---|---|
vault status |
Check Vault server status and seal state |
vault login |
Authenticate to Vault |
vault token lookup |
Display information about current token |
vault kv get secret/path |
Read a secret from KV store |
vault kv put secret/path key=value |
Write a secret to KV store |
vault kv list secret/ |
List secrets at a path |
vault kv delete secret/path |
Delete a secret |
vault secrets list |
List all enabled secret engines |
vault secrets enable -path=name type |
Enable a secret engine |
vault auth list |
List all enabled auth methods |
vault auth enable type |
Enable an auth method |
vault policy list |
List all policies |
vault policy write name file.hcl |
Create or update a policy |
vault policy read name |
Read a policy |
vault lease revoke lease_id |
Revoke a lease |
vault lease renew lease_id |
Renew a lease |
vault operator seal |
Seal the Vault |
vault operator unseal |
Unseal the Vault |
vault audit enable type |
Enable an audit device |
vault read -format=json path |
Read with JSON output |
vault write -force path |
Write without input data |
Environment Variables
| Variable | Description |
|---|---|
VAULT_ADDR |
Vault server address |
VAULT_TOKEN |
Authentication token |
VAULT_NAMESPACE |
Namespace (Enterprise) |
VAULT_CACERT |
Path to CA certificate |
VAULT_CLIENT_CERT |
Path to client certificate |
VAULT_CLIENT_KEY |
Path to client private key |
VAULT_SKIP_VERIFY |
Skip TLS verification (not recommended) |
VAULT_FORMAT |
Output format (json, yaml, table) |
Common Issues and Solutions
Issue: "permission denied" Error
Symptoms: Unable to read or write secrets despite being authenticated.
Solutions:
# Check your current token capabilities
vault token capabilities secret/myapp/config
# Verify token policies
vault token lookup
# Check policy content
vault policy read my-policy
# Ensure path matches exactly (including trailing slash for list)
vault kv list secret/myapp/ # Note trailing slash
Issue: Token Expired or Invalid
Symptoms: "token expired" or "missing client token" errors.
Solutions:
# Check token TTL
vault token lookup
# Renew token before expiry
vault token renew
# Re-authenticate
vault login -method=approle role_id=$ROLE_ID secret_id=$SECRET_ID
# Use renewable tokens
vault token create -policy="my-policy" -renewable=true -ttl=1h
Issue: Secret Not Found
Symptoms: "no value found at path" error.
Solutions:
# Check if using KV v1 or v2 (paths differ)
# KV v1: secret/myapp/config
# KV v2: secret/data/myapp/config (data prefix)
vault kv get secret/myapp/config # CLI handles versioning
# List to verify path exists
vault kv list secret/myapp/
# Check for soft-deleted secrets (KV v2)
vault kv metadata get secret/myapp/config
vault kv undelete -versions=1 secret/myapp/config
Issue: Vault Sealed
Symptoms: "Vault is sealed" error after restart.
Solutions:
# Check seal status
vault status
# Unseal with threshold keys
vault operator unseal <key-1>
vault operator unseal <key-2>
vault operator unseal <key-3>
# Configure auto-unseal (recommended for production)
# In vault.hcl:
seal "awskms" {
region = "eu-west-1"
kms_key_id = "alias/vault-unseal"
}
Issue: Certificate Errors
Symptoms: TLS handshake or certificate verification failures.
Solutions:
# Specify CA certificate
export VAULT_CACERT=/path/to/ca.crt
# Or use environment variables
vault read -ca-cert=/path/to/ca.crt secret/myapp/config
# Skip verification (development only!)
export VAULT_SKIP_VERIFY=true
# Check certificate
openssl s_client -connect vault.example.com:8200 -CAfile ca.crt
Issue: Lease Not Renewable
Symptoms: "lease is not renewable" error.
Solutions:
# Check lease details
vault lease lookup <lease_id>
# Some dynamic secrets have max TTL limits
# Check role configuration
vault read database/roles/my-role
# Request new credentials instead of renewing
vault read database/creds/my-role
# Increase max_ttl in role if needed
vault write database/roles/my-role max_ttl=48h
Issue: High Availability Redirect
Symptoms: Requests redirected to standby node.
Solutions:
# Use the active node address
vault status # Check if standby
# Configure client to follow redirects
export VAULT_MAX_RETRIES=5
# Use load balancer that routes to active node
# Or configure DNS with health checks
Issue: Audit Log Full
Symptoms: Vault stops responding when audit device is blocked.
Solutions:
# Vault blocks all operations if audit fails (security feature)
# Ensure audit log destination is available
# Rotate logs
logrotate /etc/logrotate.d/vault
# Add multiple audit devices for redundancy
vault audit enable file file_path=/var/log/vault/audit.log
vault audit enable syslog tag="vault"
# Check audit device status
vault audit list -detailed
Related Topics
The following topics would complement this HashiCorp Vault cheatsheet:
-
Consul - Service discovery and configuration often used alongside Vault as a storage backend and for service mesh integration
-
Kubernetes Secrets Management - Native Kubernetes secrets handling and comparison with external secret management solutions
-
PKI and TLS Certificates - Deeper understanding of certificate authorities, certificate chains, and TLS configuration
-
OAuth2 and OIDC - Authentication protocols used by Vault's OIDC auth method and JWT validation
-
Terraform Vault Provider - Infrastructure as Code approach to managing Vault configuration, policies, and secret engines
-
Security Compliance Frameworks - Understanding SOC2, PCI-DSS, and other compliance requirements that Vault helps address