HashiCorp Vault
Centrally manage secrets, encryption, and access with HashiCorp Vault.
When to Use This Skill
Use this skill when:
- •Centralizing secrets management
- •Implementing dynamic credentials
- •Managing PKI and certificates
- •Encrypting sensitive data
- •Meeting compliance requirements
Prerequisites
- •Vault server (dev or production)
- •Vault CLI installed
- •Network access to Vault
Quick Start
Development Server
bash
# Start dev server vault server -dev # Set environment export VAULT_ADDR='http://127.0.0.1:8200' export VAULT_TOKEN='root' # Verify connection vault status
Production Deployment
hcl
# config.hcl
storage "raft" {
path = "/opt/vault/data"
node_id = "vault-1"
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert_file = "/opt/vault/tls/vault.crt"
tls_key_file = "/opt/vault/tls/vault.key"
}
api_addr = "https://vault.example.com:8200"
cluster_addr = "https://vault.example.com:8201"
ui = true
bash
# Initialize Vault vault operator init -key-shares=5 -key-threshold=3 # Unseal (run 3 times with different keys) vault operator unseal <key-1> vault operator unseal <key-2> vault operator unseal <key-3> # Login vault login <root-token>
Secret Engines
KV Secrets
bash
# Enable KV v2 vault secrets enable -path=secret kv-v2 # Write secret vault kv put secret/myapp/config \ username="admin" \ password="s3cr3t" # Read secret vault kv get secret/myapp/config vault kv get -field=password secret/myapp/config # Update secret vault kv put secret/myapp/config \ username="admin" \ password="new-password" # List secrets vault kv list secret/ # Delete secret vault kv delete secret/myapp/config # Version history vault kv metadata get secret/myapp/config
Database Secrets
bash
# Enable database engine
vault secrets enable database
# Configure PostgreSQL connection
vault write database/config/postgresql \
plugin_name=postgresql-database-plugin \
connection_url="postgresql://{{username}}:{{password}}@localhost:5432/mydb" \
allowed_roles="readonly,readwrite" \
username="vault" \
password="vault-password"
# Create role
vault write database/roles/readonly \
db_name=postgresql \
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"
# Get credentials
vault read database/creds/readonly
AWS Secrets
bash
# Enable AWS engine
vault secrets enable aws
# Configure root credentials
vault write aws/config/root \
access_key=AKIA... \
secret_key=secret... \
region=us-east-1
# Create role
vault write aws/roles/deploy \
credential_type=iam_user \
policy_document=-<<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:*"],
"Resource": ["arn:aws:s3:::my-bucket/*"]
}
]
}
EOF
# Get credentials
vault read aws/creds/deploy
PKI Secrets
bash
# Enable PKI engine vault secrets enable pki 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 URLs vault write pki/config/urls \ issuing_certificates="https://vault.example.com:8200/v1/pki/ca" \ crl_distribution_points="https://vault.example.com:8200/v1/pki/crl" # Create role vault write pki/roles/web-server \ allowed_domains="example.com" \ allow_subdomains=true \ max_ttl="720h" # Issue certificate vault write pki/issue/web-server \ common_name="web.example.com" \ ttl="24h"
Authentication Methods
AppRole
bash
# Enable AppRole vault auth enable approle # Create role vault write auth/approle/role/myapp \ token_policies="myapp-policy" \ token_ttl=1h \ token_max_ttl=4h \ secret_id_ttl=10m # Get role ID vault read auth/approle/role/myapp/role-id # Generate secret ID vault write -f auth/approle/role/myapp/secret-id # Login vault write auth/approle/login \ role_id=<role-id> \ secret_id=<secret-id>
Kubernetes
bash
# Enable Kubernetes auth vault auth enable kubernetes # Configure vault write auth/kubernetes/config \ kubernetes_host="https://kubernetes.default.svc" \ kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt # Create role vault write auth/kubernetes/role/myapp \ bound_service_account_names=myapp \ bound_service_account_namespaces=default \ policies=myapp-policy \ ttl=1h
OIDC
bash
# Enable OIDC auth vault auth enable oidc # Configure vault write auth/oidc/config \ oidc_discovery_url="https://accounts.google.com" \ oidc_client_id="your-client-id" \ oidc_client_secret="your-client-secret" \ default_role="default" # Create role vault write auth/oidc/role/default \ bound_audiences="your-client-id" \ allowed_redirect_uris="http://localhost:8250/oidc/callback" \ user_claim="sub" \ policies="default"
Policies
Policy Definition
hcl
# myapp-policy.hcl
# Read secrets
path "secret/data/myapp/*" {
capabilities = ["read", "list"]
}
# Database credentials
path "database/creds/myapp-db" {
capabilities = ["read"]
}
# PKI certificates
path "pki/issue/web-server" {
capabilities = ["create", "update"]
}
# Deny access to other secrets
path "secret/data/other/*" {
capabilities = ["deny"]
}
bash
# Create policy vault policy write myapp myapp-policy.hcl # List policies vault policy list # Read policy vault policy read myapp
Application Integration
Python
python
import hvac
# Initialize client
client = hvac.Client(url='http://localhost:8200')
# AppRole authentication
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'
)
password = secret['data']['data']['password']
# Get database credentials
db_creds = client.secrets.database.generate_credentials(
name='myapp-db'
)
Kubernetes Sidecar
yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp
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_PASSWORD="{{ .Data.data.password }}"
{{- end }}
spec:
serviceAccountName: myapp
containers:
- name: myapp
image: myapp:latest
command: ["/bin/sh", "-c", "source /vault/secrets/config && ./start.sh"]
Common Issues
Issue: Sealed Vault
Problem: Vault is sealed after restart Solution: Implement auto-unseal with cloud KMS or HSM
Issue: Token Expired
Problem: Application token has expired Solution: Implement token renewal, use shorter-lived tokens
Issue: Permission Denied
Problem: Cannot access secrets Solution: Review policies, check token capabilities
Best Practices
- •Use short-lived tokens
- •Implement auto-unseal
- •Enable audit logging
- •Use namespaces for isolation
- •Rotate root tokens regularly
- •Implement least-privilege policies
- •Use dynamic secrets where possible
- •Regular backup and DR testing
Related Skills
- •aws-secrets-manager - AWS native secrets
- •sops-encryption - File encryption
- •kubernetes-hardening - K8s security