How to Set Up HashiCorp Vault for Secrets Management from Scratch (2026)
HashiCorp Vault is the industry standard for secrets management. This step-by-step guide shows you how to install Vault, configure it, and integrate it with Kubernetes.
Hardcoded secrets in code, plain-text passwords in ConfigMaps, API keys in environment variables baked into Docker images — this is how breaches happen.
HashiCorp Vault solves this. It's the industry-standard secrets management platform that lets you:
- Store secrets centrally and access them over an API
- Rotate credentials automatically
- Control exactly who and what can read which secret
- Audit every single access to every secret
This guide walks you through setting up Vault from scratch — locally first, then in Kubernetes.
What Is HashiCorp Vault?
Vault is a secrets management tool that acts as a single source of truth for sensitive data: API keys, database passwords, TLS certificates, SSH keys, and more.
The core model is simple:
- You store a secret in Vault (e.g.,
secret/myapp/db-password) - Vault authenticates any client that wants to read it (Kubernetes pod, CI runner, developer)
- Vault authorizes the access based on policies
- Vault returns the secret and logs the access
Everything is encrypted at rest, audited, and controlled.
Prerequisites
Before starting, you need:
- Docker installed (for local setup)
kubectl+ a Kubernetes cluster (for the K8s integration section)- Helm installed
- The
vaultCLI installed
Install the Vault CLI on Linux/Mac:
# Mac
brew tap hashicorp/tap
brew install hashicorp/tap/vault
# Ubuntu/Debian
wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install vaultPart 1: Run Vault Locally (Dev Mode)
Start Vault in development mode to explore without full setup:
vault server -dev -dev-root-token-id="root"In a second terminal, configure your environment:
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='root'
# Verify Vault is running
vault statusYou'll see:
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
Total Shares 1
Threshold 1
Version 1.17.0
HA Enabled false
Dev mode is not for production — secrets are in-memory and lost on restart. Use it to learn the API.
Part 2: Store and Read Your First Secret
Vault uses a filesystem-like path model. Secrets go under secret/ (KV v2 by default in dev mode).
Write a secret
vault kv put secret/myapp/database \
username="admin" \
password="super-secret-password" \
host="postgres.internal:5432"Read it back
vault kv get secret/myapp/databaseOutput:
======== Secret Path ========
secret/data/myapp/database
======= Metadata =======
Key Value
--- -----
created_time 2026-03-14T10:00:00Z
current_version 1
====== Data ======
Key Value
--- -----
host postgres.internal:5432
password super-secret-password
username admin
Get a specific field
vault kv get -field=password secret/myapp/databaseUpdate a secret (creates a new version)
vault kv put secret/myapp/database \
username="admin" \
password="new-rotated-password" \
host="postgres.internal:5432"View version history
vault kv metadata get secret/myapp/database
# Read a specific version
vault kv get -version=1 secret/myapp/databasePart 3: Policies — Controlling Access
Vault uses policies to control who can read or write which paths.
Create a read-only policy for your app
cat > myapp-policy.hcl << 'EOF'
path "secret/data/myapp/*" {
capabilities = ["read"]
}
path "secret/metadata/myapp/*" {
capabilities = ["list"]
}
EOF
vault policy write myapp-readonly myapp-policy.hclVerify the policy
vault policy read myapp-readonlyAn admin policy that can manage secrets:
# admin-policy.hcl
path "secret/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "auth/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
path "sys/policies/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}Part 4: Production Setup with TLS and Persistent Storage
For production, you need Vault backed by real storage and TLS.
Production config file
# config.hcl
ui = true
storage "raft" {
path = "/vault/data"
node_id = "node1"
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert_file = "/vault/tls/tls.crt"
tls_key_file = "/vault/tls/tls.key"
}
api_addr = "https://vault.yourdomain.com:8200"
cluster_addr = "https://vault.yourdomain.com:8201"Start Vault with this config
vault server -config=config.hclInitialize Vault (first time only)
# Initialize with 5 key shares, 3 required to unseal
vault operator init -key-shares=5 -key-threshold=3This outputs 5 unseal keys and a root token. Save these securely — you cannot recover them.
Unseal Vault
After every restart, Vault is sealed and needs 3 of 5 keys:
vault operator unseal <key1>
vault operator unseal <key2>
vault operator unseal <key3>Part 5: Deploy Vault in Kubernetes
For Kubernetes, use the official Helm chart:
helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo updateCreate a production-ready values file
# vault-values.yaml
server:
ha:
enabled: true
replicas: 3
raft:
enabled: true
setNodeId: true
resources:
requests:
memory: 256Mi
cpu: 250m
limits:
memory: 512Mi
cpu: 500m
dataStorage:
enabled: true
size: 10Gi
storageClass: "gp2"
auditStorage:
enabled: true
size: 10Gi
ingress:
enabled: true
hosts:
- host: vault.yourdomain.com
paths: ["/"]
tls:
- secretName: vault-tls
hosts:
- vault.yourdomain.com
ui:
enabled: true
injector:
enabled: true # enables the Agent Injector for sidecar injectionhelm install vault hashicorp/vault \
--namespace vault \
--create-namespace \
-f vault-values.yamlPart 6: Kubernetes Authentication
The Vault Agent Injector lets Kubernetes pods get secrets injected automatically — no code changes required.
Enable Kubernetes auth in Vault
# Enable the Kubernetes auth method
vault auth enable kubernetes
# Configure it with your cluster info
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/tokenCreate a role that maps K8s service accounts to Vault policies
vault write auth/kubernetes/role/myapp \
bound_service_account_names="myapp-sa" \
bound_service_account_namespaces="production" \
policies="myapp-readonly" \
ttl="1h"Annotate your Pod to get secrets injected
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: production
spec:
template:
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "myapp"
vault.hashicorp.com/agent-inject-secret-database.txt: "secret/data/myapp/database"
vault.hashicorp.com/agent-inject-template-database.txt: |
{{- with secret "secret/data/myapp/database" -}}
DB_USERNAME={{ .Data.data.username }}
DB_PASSWORD={{ .Data.data.password }}
DB_HOST={{ .Data.data.host }}
{{- end -}}
spec:
serviceAccountName: myapp-sa
containers:
- name: myapp
image: myapp:latest
env:
- name: DB_CREDENTIALS_FILE
value: /vault/secrets/database.txtThe Vault Agent sidecar will inject the file /vault/secrets/database.txt with the rendered template. Your app reads the file — no secrets in env vars, no Kubernetes Secrets, no plaintext anywhere.
Part 7: Dynamic Database Credentials (Advanced)
Vault can generate temporary database credentials that auto-expire:
# Enable the database secrets engine
vault secrets enable database
# Configure a PostgreSQL connection
vault write database/config/mydb \
plugin_name=postgresql-database-plugin \
allowed_roles="myapp-role" \
connection_url="postgresql://{{username}}:{{password}}@postgres:5432/mydb" \
username="vault-admin" \
password="vault-admin-password"
# Create a role that generates credentials
vault write database/roles/myapp-role \
db_name=mydb \
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"Now every time an app requests credentials, it gets a unique, time-limited username/password:
vault read database/creds/myapp-roleKey Value
--- -----
username v-myapp-abc123
password A1b2-C3d4-E5f6-G7h8
lease_duration 1h
After 1 hour, those credentials automatically expire and are deleted from PostgreSQL. Even if leaked, they're useless within an hour.
Vault CLI Quick Reference
# Check status
vault status
# List secrets at a path
vault kv list secret/
# Write a secret
vault kv put secret/myapp key=value
# Read a secret
vault kv get secret/myapp
# Delete a secret
vault kv delete secret/myapp
# List auth methods
vault auth list
# List secrets engines
vault secrets list
# Check token info
vault token lookupLearn More
Want hands-on Vault labs in a real Kubernetes environment? KodeKloud's DevOps courses include dedicated Vault content with real cluster exercises. You'll go from zero to production-ready Vault in a structured path.
If you need a cloud environment to practice, DigitalOcean's managed Kubernetes is one of the most affordable ways to run a real cluster without the complexity of EKS or GKE.
Summary
HashiCorp Vault is the right answer to secrets management at any scale:
- Dev mode — learn locally in minutes
- KV store — simple key-value secrets with versioning
- Policies — fine-grained control over who reads what
- Kubernetes integration — Agent Injector for zero-code-change secret injection
- Dynamic credentials — auto-expiring database credentials for maximum security
Start by moving your database passwords out of Kubernetes Secrets and into Vault. That single change dramatically reduces your blast radius if any service is ever compromised.
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
What is a Service Mesh? Explained Simply (No Jargon)
Service mesh sounds complicated but the concept is simple. Here's what it actually does, why teams use it, and whether you need one — explained without the buzzwords.
Build a DevSecOps Pipeline with Trivy, SonarQube, and OPA from Scratch (2026)
Step-by-step project walkthrough: add security scanning, code quality gates, and policy enforcement to a GitHub Actions pipeline. Real configs, production-ready.
Build a Kubernetes Cluster with kubeadm from Scratch (2026)
Step-by-step guide to building a real multi-node Kubernetes cluster using kubeadm — no managed services, no shortcuts.