← News
/PLAYBOOK · 2026-08-14

HashiCorp Vault Secrets Management in Practice: Dynamic Secrets and Access Control

Hands-on Vault secrets management: install, KV read/write, database dynamic secrets, policies, and AppRole. Full config steps and verification so ops and security teams can centralize server, database, and cloud credentials.

When to Use

Vault secrets management fits teams that must centralize database passwords, API tokens, SSH keys, and other credentials. The usual pattern writes passwords in plaintext configs; a compromised host leaks everything. Vault stores credentials in an encrypted backend, gates who can read and when via policy, and can mint short-lived dynamic secrets. Fits SMB multi-server, database, and CI/CD setups.

Prerequisites

How It Works

Vault's model is centralized storage + policy isolation + dynamic issuance. Secrets are written to backend storage (memory in dev; Consul or Raft in prod) and encrypted with the master key under Seal. Reads require Unseal. Policies in HCL declare path capabilities; auth methods (Token, AppRole, Kubernetes, etc.) enforce least privilege. The database engine mints temporary read-only accounts for MySQL and PostgreSQL and revokes them at expiry, eliminating long-lived static passwords.

Procedure

1. Install and start Vault

# Download Vault 1.15 and extract to /usr/local/bin
wget https://releases.hashicorp.com/vault/1.15.6/vault_1.15.6_linux_amd64.zip
unzip vault_1.15.6_linux_amd64.zip -d /usr/local/bin/
vault version

# Create data directory and write a minimal config
mkdir -p /etc/vault /opt/vault/data
cat > /etc/vault/config.hcl <<'EOF'
storage "raft" {
  path = "/opt/vault/data"
  node_id = "node1"
}
listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_disable = 1
}
api_addr = "http://127.0.0.1:8200"
cluster_addr = "https://127.0.0.1:8201"
ui = true
EOF

# Start Vault
nohup vault server -config=/etc/vault/config.hcl > /var/log/vault.log 2>&1 &
export VAULT_ADDR='http://127.0.0.1:8200'
vault status

First start showing Sealed is expected. Init generates the root token and 5 unseal key shares.

2. Init and unseal

vault operator init -key-shares=5 -key-threshold=3
# Outputs Unseal Key 1-5 and Initial Root Token; store them securely

# Unseal 3 times (threshold); enter one Unseal Key each time
vault operator unseal
vault operator unseal
vault operator unseal
vault status   # Seal Type: shamir, Sealed: false

# Log in with the root token
vault login <Initial Root Token>

3. Enable KV and write secrets

vault secrets enable -path=secret kv-v2
vault kv put secret/webapp db_password='S3cure!Pass'
vault kv get secret/webapp
vault kv metadata get secret/webapp

4. Configure MySQL dynamic secrets (optional)

vault secrets enable database
vault write database/config/mysql \
  plugin_name=mysql-database-plugin \
  connection_url="{{username}}:{{password}}@tcp(10.0.0.5:3306)/" \
  allowed_roles="readonly"
vault write database/roles/readonly \
  db_name=mysql \
  creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';GRANT SELECT ON *.* TO '{{name}}'@'%';" \
  default_ttl="1h" max_ttl="24h"

# Fetch dynamic credentials (auto-revoked after 1 hour)
vault read database/creds/readonly

5. Write a policy and create an AppRole

cat > webapp.hcl <<'EOF'
path "secret/data/webapp" {
  capabilities = ["read"]
}
EOF
vault policy write webapp webapp.hcl

vault auth enable approle
vault write auth/approle/role/webapp \
  token_policies="webapp" \
  token_ttl="30m" \
  secret_id_ttl="24h"

# Fetch RoleID and SecretID to distribute to the app
vault read -format=json auth/approle/role/webapp/role-id
vault write -f auth/approle/role/webapp/secret-id

Verification

# Log in with AppRole and read the secret; policy should allow it
vault write auth/approle/login role_id=<RoleID> secret_id=<SecretID>
export VAULT_TOKEN=<returned client_token>
vault kv get secret/webapp   # should succeed

# Verify dynamic secret lease and revocation
vault read database/creds/readonly
vault list sys/leases/lookup/database/creds/readonly

FAQ

FAQ 1: Vault is Sealed after restart. What now?

By design. Data on disk is encrypted. Re-enter 3 Unseal Keys (threshold) after restart. In production, use Auto Unseal (cloud KMS or HSM) so operators do not unseal by hand.

FAQ 2: Can you recover a lost root token?

Yes. Run `vault operator generate-root` with unseal key shares to mint a new root token. If all unseal keys are also gone, recovery is impossible—wipe the storage directory and re-init. Keep Unseal Keys and the root token in offline encrypted backups.

FAQ 3: How do apps avoid hardcoding RoleID/SecretID?

SecretID is a secret; RoleID is a semi-public identifier. Inject SecretID via environment variables, or use Vault Agent auto-auth to fetch and cache a token at startup so the app never sees plaintext credentials.

Summary

These steps stand up a usable Vault secrets environment in about 30 minutes: Raft storage + Shamir unseal for data at rest, KV for static secrets, the database engine for short-lived credentials, Policy + AppRole for least-privilege auth. Credentials move from scattered configs to a single control plane, shrinking the leak surface. Next: Kubernetes auth, Terraform integration, and Consul HA for a full secrets-governance stack.