A Complete Beginner’s Guide to Secrets Management (Using HashiCorp Vault)
HashiCorp Vault is a security tool used to securely store, manage, and control access to secrets such as passwords, API keys, database credentials, certificates, encryption keys, and tokens. It acts as a centralized “vault” for sensitive information instead of hardcoding secrets into applications or storing them in configuration files.
Why do organizations use Vault?
Imagine you have an application that needs to connect to:
- A PostgreSQL database.
- AWS.
- A third-party API (e.g., Stripe).
Without Vault, you might store credentials in:
- Environment variables.
- Configuration files.
- Source code (which is a bad practice).
With Vault:
- Applications authenticate to Vault.
- Vault verifies their identity.
- Vault provides the required secret securely.
- Secrets can expire automatically and be rotated without changing application code.
Key Features
- Secrets management
- Store API keys, passwords, SSH keys, certificates, and other sensitive data securely. - Dynamic secrets
- Generate temporary credentials on demand.
- Example: Instead of using a permanent database password, Vault creates a database user that’s valid for only one hour. - Encryption as a Service
- Encrypt and decrypt application data without exposing encryption keys to the application. - Authentication
- Supports many authentication methods, including LDAP, Active Directory, Kubernetes, AWS IAM, Azure, GitHub, and OIDC. - Access control
- Uses policies to define exactly who or what can access specific secrets. - Audit logging
- Records every request to help with security monitoring and compliance.
Vault Workflow
The following image illustrates a complete flow to manage secrets in an applicationF.
Use Case
Suppose a web application needs a MySQL password.
Without Vault
config.yaml
------------
db_user=admin
db_password=MySecretPassword123If someone gains access to the file, they have the database password.
With Vault
Even if the credentials are stolen, they become unusable after they expire.
Common Integrations
Vault integrates well with:
a) Kubernetes.
b) Docker.
c) AWS, Azure, and Google Cloud.
d) Jenkins and GitHub Actions.
e) Terraform.
f) Databases such as MySQL, PostgreSQL, Oracle, and MongoDB.
Vault Deployment Using Terraform
Kubernetes, Terraform, Helm, and microservices, the Kubernetes + Helm approach would be -
The overall steps can be described as below -
Step 1: Configure Providers:
terraform {
required_version = ">=1.6"
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.35"
}
helm = {
source = "hashicorp/helm"
version = "~> 2.15"
}
}
}
provider "kubernetes" {
config_path = "~/.kube/config"
}
provider "helm" {
kubernetes {
config_path = "~/.kube/config"
}
}Step 2: Create Namespace
resource "kubernetes_namespace" "vault" {
metadata {
name = "vault"
}
}Step 3: Deploy Vault
resource "helm_release" "vault" {
name = "vault"
namespace = kubernetes_namespace.vault.metadata[0].name
repository = "https://helm.releases.hashicorp.com"
chart = "vault"
version = "0.30.1"
values = [
file("${path.module}/values.yaml")
]
}Step 4: values.yaml
server:
ha:
enabled: true
raft:
enabled: true
dataStorage:
enabled: true
size: 10Gi
auditStorage:
enabled: true
size: 10Gi
ui:
enabled: true
injector:
enabled: trueThis creates:
a) 3 Vault pods.
b) Integrated Raft storage.
c) Persistent Volumes.
d) Web UI.
e) Vault Agent Injector.
Step 5: Initialize Vault
kubectl exec -it vault-0 -n vault -- vault operator initThe output could be -
Unseal Key 1:
Unseal Key 2:
Unseal Key 3:
Unseal Key 4:
Unseal Key 5:
Get Kumaresh Chandra Baruri’s stories in your inbox
Join Medium for free to get updates from this writer.
Initial Root Token: xxxx-YYYY-zzzz
Step 6: Unseal Vault
vault operator unsealProvide three different keys and repeat on each pod.
Step 7: Login
vault loginStep 8: Enable Kubernetes Authentication
vault auth enable kubernetesStep 9: Configure Kubernetes
vault write auth/kubernetes/config \
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
kubernetes_host=https://kubernetes.default.svcStep 10: Enable KV Secrets
vault secrets enable -path=secret kv-v2Store a Secret
vault kv put secret/db \
username=admin \
password=Secret123Read Secret
vault kv get secret/dbConfigure the PostGreSQL -
vault write database/config/postgres \
plugin_name=postgresql-database-plugin \
allowed_roles="readonly"Vault can now generate temporary database users with configurable time-to-live (TTL).
Terraform Deployment
terraform init
terraform plan
terraform applyVerify
kubectl get pods -n vault
kubectl get pvc -n vault
kubectl get svc -n vaultHow Java Service Access?
Add Dependencies
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-vault-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>Store Secrets in Vault
Enable the KV secrets engine:
vault secrets enable -path=secret kv-v2Store a secret:
vault kv put secret/myapp \
db.username=postgres \
db.password=MySecret123Configure Spring Boot
Application.yml-
spring:
application:
name: myapp
cloud:
vault:
uri: http://localhost:8200
token: hvs.xxxxxxxxxxxxxxxxx
kv:
enabled: true
backend: secret
application-name: myappSpring Cloud Vault will automatically read:
secret/myapp
Access Secrets
@RestController
public class SecretController {
@Value("${db.username}")
private String username;
@Value("${db.password}")
private String password;
@GetMapping("/secret")
public String secret() {
return username + " : " + password;
}
}No database password is stored in application.yml.
Reading Secrets Programmatically
@Service
public class VaultService {
private final VaultTemplate vaultTemplate;
public VaultService(VaultTemplate vaultTemplate) {
this.vaultTemplate = vaultTemplate;
}
public Map<String, Object> getSecrets() {
VaultResponse response =
vaultTemplate.read("secret/data/myapp");
return (Map<String, Object>)
response.getData().get("data");
}
}Controller:
@RestController
@RequestMapping("/vault")
public class VaultController {
private final VaultService vaultService;
public VaultController(VaultService vaultService) {
this.vaultService = vaultService;
}
@GetMapping("/secrets")
public Map<String, Object> secrets() {
return vaultService.getSecrets();
}
}Dynamic PostgreSQL Credentials
Enable the database secrets engine:
vault secrets enable databaseConfigure PostgreSQL:
vault write database/config/postgres \
plugin_name=postgresql-database-plugin \
connection_url="postgresql://{{username}}:{{password}}@postgres:5432/postgres?sslmode=disable" \
allowed_roles="readonly" \
username="postgres" \
password="postgres"Create a role:
vault write database/roles/readonly \
db_name=postgres \
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
default_ttl="30m" \
max_ttl="24h"Request for temporary credentials-
@Service
public class DatabaseCredentialService {
private final VaultTemplate vaultTemplate;
public DatabaseCredentialService(VaultTemplate vaultTemplate) {
this.vaultTemplate = vaultTemplate;
}
public Map<String, Object> generateCredentials() {
VaultResponse response =
vaultTemplate.read("database/creds/readonly");
return response.getData();
}
}The response could be -
{
"username": "v-token-abc123",
"password": "P7x9LmK82",
"lease_duration": 1800,
"renewable": true
}Production Best Practices
a) Use Integrated Raft storage instead of the legacy Consul backend for new deployments.
b) Deploy at least 3 Vault pods across different nodes or availability zones.
c) Enable TLS for all client and cluster communication.
d) Store unseal keys securely (or use Auto Unseal with AWS KMS, Azure Key Vault, or Google Cloud KMS).
e) Enable audit logging.
f) Use Kubernetes authentication instead of static tokens.
g) Apply least-privilege Vault policies.
h) Enable regular Raft snapshots for backup and disaster recovery.
i) Monitor Vault with Prometheus and visualize metrics in Grafana.
References:
a) https://developer.hashicorp.com/vault/docs/about-vault/what-is-vault?utm_source=chatgpt.com









