-
-
Notifications
You must be signed in to change notification settings - Fork 0
Vault Security
- Overview
- Critical Security Warning
- Development vs Production
- AppRole Authentication
- Secure Token Storage
- Backup and Recovery
- Token Rotation
- Network Security
- Monitoring and Auditing
This document outlines security best practices for HashiCorp Vault in the devstack-core environment. The default configuration is optimized for local development only and should never be used in production environments.
The current setup uses the Vault root token for simplicity in local development. This is EXTREMELY DANGEROUS in production because:
- Root tokens have unlimited privileges across all Vault operations
- Root tokens never expire by default
- Compromise of a root token = complete system compromise
- No audit trail for individual operations
- Cannot be revoked without re-initializing Vault
Current Development Configuration:
# .env file (DEVELOPMENT ONLY)
VAULT_TOKEN=$(cat ~/.config/vault/root-token).env with real tokens to version control
The devstack-core environment is configured for local development with:
- Root token stored in
~/.config/vault/root-token - Auto-unseal on container start
- File backend for storage
- Unencrypted network communication (HTTP)
- Single-node deployment
This is acceptable ONLY for:
- Local development on your personal machine
- Testing and experimentation
- Learning Vault features
- Rapid prototyping
A production Vault deployment must have:
- No root token usage - use AppRole, Kubernetes auth, or other auth methods
- Auto-unseal with cloud KMS (AWS KMS, Azure Key Vault, GCP KMS)
- TLS/HTTPS everywhere with valid certificates
- High availability (3+ node cluster with Raft or Consul storage)
- Audit logging enabled and monitored
- Network isolation (private networks, firewalls)
- Regular backups with encrypted snapshots
- Access control policies with least privilege
- MFA required for sensitive operations
- Secrets rotation policies enforced
AppRole is the recommended authentication method for applications accessing Vault.
Create a policy file reference-api-policy.hcl:
# Allow reading database credentials
path "secret/data/postgres" {
capabilities = ["read"]
}
path "secret/data/mysql" {
capabilities = ["read"]
}
path "secret/data/mongodb" {
capabilities = ["read"]
}
path "secret/data/redis-1" {
capabilities = ["read"]
}
path "secret/data/rabbitmq" {
capabilities = ["read"]
}
# Allow reading PKI certificates
path "pki/cert/ca" {
capabilities = ["read"]
}
path "pki/issue/reference-api" {
capabilities = ["create", "update"]
}
# Deny access to other secrets
path "secret/data/*" {
capabilities = ["deny"]
}# Set Vault environment
export VAULT_ADDR="http://localhost:8200"
export VAULT_TOKEN=$(cat ~/.config/vault/root-token)
# Write the policy
vault policy write reference-api reference-api-policy.hcl# Enable AppRole authentication method
vault auth enable approle
# Create a role for the reference API
vault write auth/approle/role/reference-api \
token_policies="reference-api" \
token_ttl=1h \
token_max_ttl=4h \
bind_secret_id=true \
secret_id_ttl=0# Get Role ID (can be public)
vault read auth/approle/role/reference-api/role-id
# Example output:
# Key Value
# --- -----
# role_id a1b2c3d4-e5f6-7g8h-9i0j-k1l2m3n4o5p6
# Generate Secret ID (must be kept secret)
vault write -f auth/approle/role/reference-api/secret-id
# Example output:
# Key Value
# --- -----
# secret_id z9y8x7w6-v5u4-t3s2-r1q0-p9o8n7m6l5k4
# secret_id_accessor a1b2c3d4-e5f6-7g8h-9i0j-k1l2m3n4o5p6
# secret_id_ttl 0sPython Example (FastAPI):
import os
import hvac
def get_vault_client():
"""Get authenticated Vault client using AppRole"""
role_id = os.environ["VAULT_ROLE_ID"]
secret_id = os.environ["VAULT_SECRET_ID"]
vault_addr = os.environ.get("VAULT_ADDR", "http://vault:8200")
client = hvac.Client(url=vault_addr)
# Authenticate with AppRole
response = client.auth.approle.login(
role_id=role_id,
secret_id=secret_id,
)
# Token is automatically set in client
return client
def get_postgres_credentials():
"""Fetch PostgreSQL credentials from Vault"""
client = get_vault_client()
secret = client.secrets.kv.v2.read_secret_version(
path="postgres",
mount_point="secret"
)
return {
"user": secret["data"]["data"]["username"],
"password": secret["data"]["data"]["password"],
"database": secret["data"]["data"]["database"],
}Instead of using VAULT_TOKEN, use AppRole credentials:
# .env (DO NOT commit to git)
VAULT_ROLE_ID=a1b2c3d4-e5f6-7g8h-9i0j-k1l2m3n4o5p6
VAULT_SECRET_ID=z9y8x7w6-v5u4-t3s2-r1q0-p9o8n7m6l5k4- Limited permissions - only access to specified secrets
- Time-limited tokens - automatic expiration
- Renewable tokens - applications can refresh before expiry
- Revocable - can be disabled without affecting other apps
- Auditable - track which application accessed what
- No root token exposure - applications never see root token
Bad (Current Development Setup):
# .env - NEVER use this in production
VAULT_TOKEN=hvs.CAESIJ1wv8...Better - Use Environment Variables at Runtime:
# Fetch from secure storage at container start
VAULT_TOKEN=$(security find-generic-password -s vault-token -w)Best - Use AppRole (No Token Storage):
# Only store role_id and secret_id
VAULT_ROLE_ID=a1b2c3d4-...
VAULT_SECRET_ID=z9y8x7w6-...Store Vault tokens securely in macOS Keychain:
# Store token in keychain
security add-generic-password \
-a "${USER}" \
-s "vault-root-token" \
-w "$(cat ~/.config/vault/root-token)"
# Retrieve token
VAULT_TOKEN=$(security find-generic-password \
-a "${USER}" \
-s "vault-root-token" \
-w)For Kubernetes deployments:
apiVersion: v1
kind: Secret
metadata:
name: vault-approle
namespace: production
type: Opaque
data:
role-id: <base64-encoded-role-id>
secret-id: <base64-encoded-secret-id>-
Unseal Keys - stored in
~/.config/vault/keys.json -
Root Token - stored in
~/.config/vault/root-token -
Vault Data - Docker volume
vault_data - Policies - export all custom policies
-
Configuration -
configs/vault/directory
# Create backup directory with timestamp
BACKUP_DIR="backups/vault-$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
# Backup unseal keys (CRITICAL)
cp ~/.config/vault/keys.json "$BACKUP_DIR/"
chmod 600 "$BACKUP_DIR/keys.json"
# Backup root token (CRITICAL)
cp ~/.config/vault/root-token "$BACKUP_DIR/"
chmod 600 "$BACKUP_DIR/root-token"
# Backup CA certificates
cp -r ~/.config/vault/ca "$BACKUP_DIR/"
# Backup Vault data volume
docker run --rm \
-v vault_data:/data \
-v "$PWD/$BACKUP_DIR":/backup \
alpine tar czf /backup/vault-data.tar.gz -C /data .
# Encrypt the backup
tar czf - "$BACKUP_DIR" | \
gpg --symmetric --cipher-algo AES256 \
-o "$BACKUP_DIR.tar.gz.gpg"
# Securely delete unencrypted backup
rm -rf "$BACKUP_DIR"
echo "Encrypted backup created: $BACKUP_DIR.tar.gz.gpg"Create scripts/backup-vault.sh:
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="backups/vault-$(date +%Y%m%d_%H%M%S)"
BACKUP_RETENTION_DAYS=30
# Create encrypted backup (see manual backup above)
# ...
# Clean up old backups
find backups/ -name "vault-*.tar.gz.gpg" \
-mtime +${BACKUP_RETENTION_DAYS} \
-delete
echo "Backup completed and old backups cleaned"Recommended backup frequency:
- Unseal keys: Immediately after initialization, store in multiple secure locations
- Vault data: Daily for development, hourly for production
- Policies: After every change
- Off-site backup: Weekly encrypted backups to cloud storage
# Decrypt backup
gpg --decrypt backups/vault-20250123_143022.tar.gz.gpg | \
tar xzf -
# Restore unseal keys
cp backups/vault-20250123_143022/keys.json ~/.config/vault/
# Restore root token
cp backups/vault-20250123_143022/root-token ~/.config/vault/
# Stop Vault container
docker compose stop vault
# Restore data volume
docker run --rm \
-v vault_data:/data \
-v "$PWD/backups/vault-20250123_143022":/backup \
alpine sh -c "cd /data && tar xzf /backup/vault-data.tar.gz"
# Start Vault
docker compose start vaultWhy rotate?
- Limit exposure window if token is compromised
- Compliance requirements
- Best security practice
How to rotate root token:
export VAULT_ADDR="http://localhost:8200"
export VAULT_TOKEN=$(cat ~/.config/vault/root-token)
# Generate new root token
vault token create -policy=root -period=768h
# Output:
# Key Value
# --- -----
# token hvs.CAESIJ...
# token_accessor aBcDeFgH...
# token_duration 768h
# token_renewable true
# token_policies ["root"]
# Update stored token
echo "hvs.CAESIJ..." > ~/.config/vault/root-token
chmod 600 ~/.config/vault/root-token
# Revoke old token
vault token revoke $(cat ~/.config/vault/root-token.old)With AppRole, tokens automatically rotate:
def renew_vault_token(client):
"""Renew Vault token before expiration"""
try:
client.auth.token.renew_self()
except hvac.exceptions.InvalidRequest:
# Token expired, re-authenticate
client = get_vault_client()
return client- Vault accessible on
http://localhost:8200 - No TLS encryption
- No network isolation
Acceptable ONLY for local development
# vault-config.hcl
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert_file = "/vault/certs/vault.crt"
tls_key_file = "/vault/certs/vault.key"
}# docker-compose-production.yml
services:
vault:
networks:
- vault-network # Isolated network
ports:
- "127.0.0.1:8200:8200" # Only localhost access# Allow only from application network
iptables -A INPUT -p tcp --dport 8200 -s 172.20.0.0/16 -j ACCEPT
iptables -A INPUT -p tcp --dport 8200 -j DROP# Enable file audit backend
vault audit enable file file_path=/vault/logs/audit.log
# Enable syslog audit backend (production)
vault audit enable syslog tag="vault" facility="AUTH"Prometheus metrics are exposed at http://localhost:8200/v1/sys/metrics:
-
vault_core_unsealed- Vault seal status -
vault_runtime_alloc_bytes- Memory usage -
vault_runtime_num_goroutines- Concurrent operations -
vault_token_creation- Token creation rate -
vault_token_revocation- Token revocation rate
# Prometheus alert rules
groups:
- name: vault
rules:
- alert: VaultSealed
expr: vault_core_unsealed == 0
for: 1m
annotations:
summary: "Vault is sealed"
- alert: VaultHighTokenCreation
expr: rate(vault_token_creation[5m]) > 100
annotations:
summary: "Unusual token creation rate"- Root token stored in
~/.config/vault/root-token - Auto-unseal configured
- Backup script created
- Test AppRole authentication
- Document token rotation procedure
- Set up audit logging
- Remove all root token references
- Implement AppRole for all applications
- Enable TLS with valid certificates
- Configure high availability (3+ nodes)
- Enable audit logging
- Set up automated encrypted backups
- Configure network isolation
- Implement monitoring and alerting
- Test disaster recovery procedures
- Document access control policies
- Train team on security procedures
- HashiCorp Vault Production Hardening
- AppRole Auth Method
- Vault Security Best Practices
- Disaster Recovery
For questions or security concerns:
- Open an issue in the GitHub repository
- Review the official HashiCorp Vault documentation
- Consult with your security team before production deployment