Getting Started with HashiCorp Vault: A Practical Guide
Secrets management is one of those problems that seems simple until you’re dealing with hundreds of services, multiple environments, and compliance requirements. That’s where HashiCorp Vault comes in.
After working with Vault at enterprise scale at Dell Technologies, I’ve learned what works (and what doesn’t). This guide covers the fundamentals to get you started.
What is HashiCorp Vault?
Vault is a tool for securely accessing secrets. A secret is anything you want to control access to: API keys, passwords, certificates, encryption keys. Vault provides a unified interface to any secret while providing tight access control and recording a detailed audit log.
Core Concepts
Before diving into code, let’s understand the key concepts:
Secrets Engines
These are components that store, generate, or encrypt data. Common types include:
- KV (Key-Value): Simple key-value storage for static secrets
- Database: Dynamic database credentials
- PKI: Certificate authority for TLS certificates
- Transit: Encryption as a service
Authentication Methods
How clients prove their identity to Vault:
- Token: The fundamental auth method
- AppRole: For machines and applications
- LDAP/OIDC: For human users
- Kubernetes: For pods running in K8s
Policies
Define what secrets a client can access:
# Example policy for an application
path "secret/data/myapp/*" {
capabilities = ["read", "list"]
}
path "database/creds/myapp-db" {
capabilities = ["read"]
}
Setting Up Vault Locally
Let’s get Vault running for development:
# Install Vault (macOS)
brew install vault
# Start in dev mode (NOT for production!)
vault server -dev
# In another terminal, set the address
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='root' # Dev mode root token
Your First Secrets
Storing a Secret
# Enable the KV secrets engine (v2)
vault secrets enable -path=secret kv-v2
# Store a secret
vault kv put secret/myapp/config \
api_key="sk-abc123" \
db_password="supersecret"
# Read it back
vault kv get secret/myapp/config
Using the API
# Store via API
curl -X POST \
-H "X-Vault-Token: root" \
-d '{"data": {"api_key": "sk-abc123"}}' \
http://127.0.0.1:8200/v1/secret/data/myapp/config
# Read via API
curl -H "X-Vault-Token: root" \
http://127.0.0.1:8200/v1/secret/data/myapp/config
AppRole Authentication
For applications, AppRole is the recommended auth method:
# Enable AppRole
vault auth enable approle
# Create a policy
vault policy write myapp-policy - <<EOF
path "secret/data/myapp/*" {
capabilities = ["read"]
}
EOF
# Create a role
vault write auth/approle/role/myapp \
token_policies="myapp-policy" \
token_ttl=1h \
token_max_ttl=4h
# Get the role ID (safe to distribute)
vault read auth/approle/role/myapp/role-id
# Generate a secret ID (keep this secure!)
vault write -f auth/approle/role/myapp/secret-id
Authenticating with AppRole
# Login and get a token
vault write auth/approle/login \
role_id="<role-id>" \
secret_id="<secret-id>"
# Use the returned token
export VAULT_TOKEN="<client-token>"
vault kv get secret/myapp/config
Best Practices
From my experience managing Vault at scale:
1. Never Use Root Tokens in Production
Create specific tokens with limited permissions. Root tokens should only be used for initial setup.
2. Enable Audit Logging
vault audit enable file file_path=/var/log/vault_audit.log
Every secret access is logged—essential for compliance.
3. Use Short TTLs
Shorter token lifetimes reduce the blast radius if credentials are compromised.
4. Namespace Your Secrets
Organize by application and environment:
secret/
├── prod/
│ ├── app1/
│ └── app2/
└── dev/
├── app1/
└── app2/
5. Rotate Secrets Regularly
Vault can automate this with dynamic secrets for databases and cloud providers.
Common Pitfalls
Storing secrets in code: Even with Vault, I’ve seen teams commit Vault tokens to Git. Use environment variables or secret injection.
Overly permissive policies: Start restrictive and expand as needed. capabilities = ["create", "read", "update", "delete", "list"] is almost never correct.
Ignoring high availability: Dev mode stores everything in memory. Production needs proper storage backend (Consul, Raft, etc.).
Next Steps
This guide covers the basics. In future posts, I’ll dive into:
- Dynamic database credentials
- PKI certificate management
- Kubernetes integration
- Vault Agent for secret injection
Resources
Have questions about Vault? Connect with me on LinkedIn—I’m always happy to discuss secrets management strategies.