Home/Engineer/Security Hardening/HashiCorp Vault Basics — Sec…
Security HardeningAdvancedlinuxvaultsecretshashicorp

HashiCorp Vault Basics — Secret Management and Dynamic Credentials

Covers HashiCorp Vault core concepts (seal/unseal, tokens, policies, secrets engines) and walks through KV v2 static secrets, database dynamic credentials, and AppRole authentication.

Contents
  1. What is HashiCorp Vault?
  2. Core Concepts
  3. Starting the Server and Unsealing
  4. CLI Login
  5. KV v2 — Static Secrets
  6. Policies
  7. Dynamic Credentials — Database Secrets Engine
  8. AppRole — Application Authentication
  9. Audit Logs
  10. Recap

What is HashiCorp Vault?

Vault is a tool that centrally stores, issues, and audits secrets—API keys, database passwords, certificates, and the like—in a secure way. It addresses the fundamental risk of hardcoding passwords in source code or scattering environment-variable files across systems.

Vault’s strongest differentiator is dynamic secrets. Rather than merely storing static passwords, it creates short-lived database accounts on the fly whenever an application requests them, then automatically revokes those accounts when the TTL expires. Even if a password leaks, the blast radius is limited by the short lifetime, and every issuance is recorded in the audit log—who received credentials, and when.

This guide covers Vault’s core concepts and the main workflows (KV secrets, database dynamic credentials, and AppRole) in a single-node development/staging setup.

The vault server -dev used in this document is for learning only. Data lives in memory, the server auto-unseals, and there is no TLS. Never use it in production. Production requires persistent storage (Integrated Storage/Raft), TLS, and a distributed unseal-key configuration.

Core Concepts

ConceptDescription
Seal / UnsealVault starts in an encrypted sealed state. You must unseal it with master-key shards before data can be accessed
Unseal Key (Shamir)The master key is split into N shards; K of them are required to decrypt (e.g., 3 of 5)
Root TokenThe initial token with all privileges. Revoke it after setup
TokenEvery request is authenticated with a token. Tokens carry a TTL and attached policies
PolicyPath-level permissions (capabilities) written in HCL
Secrets EnginePlugins that handle secrets (kv, database, pki, and others)
Auth MethodHow users/apps authenticate (token, approle, userpass, kubernetes)

Starting the Server and Unsealing

Dev server for learning:

Bash
vault server -dev -dev-root-token-id="root"
# VAULT_ADDR, Root Token

A production-style start (Raft storage) uses a config file.

HCL
# /etc/vault.d/vault.hcl
storage "raft" {
  path    = "/opt/vault/data"
  node_id = "node1"
}
listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_cert_file = "/etc/vault.d/tls/vault.crt"
  tls_key_file  = "/etc/vault.d/tls/vault.key"
}
api_addr = "https://vault.example.com:8200"
ui = true
Bash
export VAULT_ADDR='https://vault.example.com:8200'
vault operator init # unseal 5 + root ( !)
vault operator unseal # 3
vault status # Sealed: false check

The vault operator init output (unseal keys and root token) is shown only once. Lose it and the data is gone forever. Store key shards with different people / in different safes.

CLI Login

Bash
export VAULT_ADDR='http://127.0.0.1:8200'
vault login # (dev root)
vault token lookup # ·TTL· check

KV v2 — Static Secrets

The most basic secrets store. v2 supports versioning and soft delete.

Bash
# KV v2
vault secrets enable -path=secret kv-v2

# when save
vault kv put secret/myapp/db username="appuser" password="s3cr3t"

#
vault kv get secret/myapp/db
vault kv get -field=password secret/myapp/db #

#
vault kv get -version=1 secret/myapp/db
vault kv metadata get secret/myapp/db #

# / /
vault kv delete secret/myapp/db
vault kv undelete -versions=2 secret/myapp/db
vault kv destroy -versions=1 secret/myapp/db

Note that KV v2 inserts /data/ into the API path (important when writing policies).

Policies

Permissions are defined as capabilities per path.

HCL
# myapp-policy.hcl
# KV v2 path secret/data/...
path "secret/data/myapp/*" {
  capabilities = ["read", "list"]
}
path "secret/metadata/myapp/*" {
  capabilities = ["list", "read"]
}
Bash
vault policy write myapp myapp-policy.hcl
vault policy read myapp

Capabilities are create, read, update, delete, list, sudo, deny. Grant them on a least-privilege basis.

Dynamic Credentials — Database Secrets Engine

Vault connects to PostgreSQL and creates a temporary account on every request.

Bash
#
vault secrets enable database

# DB settings (Vault )
vault write database/config/postgres \
    plugin_name=postgresql-database-plugin \
    allowed_roles="readonly" \
    connection_url="postgresql://{{username}}:{{password}}@db.example.com:5432/app?sslmode=require" \
    username="vault_admin" \
    password="adminpass"

# : when run SQL TTL
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="1h" \
    max_ttl="24h"

Requesting credentials then looks like this:

Bash
vault read database/creds/readonly
# Key                Value
# lease_id           database/creds/readonly/abc123
# lease_duration     1h
# username           v-token-readonly-x9f2...
# password           A1b2-randomgenerated

The issued account is automatically revoked after one hour. To revoke immediately:

Bash
vault lease revoke database/creds/readonly/abc123

Using dynamic credentials requires the Vault admin account to have CREATEROLE on the database. Rotate that admin account itself periodically with vault write database/rotate-root/postgres.

AppRole — Application Authentication

The standard way for applications and CI (not humans) to authenticate to Vault.

Bash
vault auth enable approle

vault write auth/approle/role/myapp \
    token_policies="myapp" \
    token_ttl=1h token_max_ttl=4h \
    secret_id_ttl=24h

# RoleID + SecretID
vault read auth/approle/role/myapp/role-id
vault write -f auth/approle/role/myapp/secret-id

# →
vault write auth/approle/login \
    role_id="<role_id>" secret_id="<secret_id>"

A common pattern is to bake the RoleID into the build and inject the SecretID safely at runtime (e.g., as a CI secret).

Audit Logs

Bash
vault audit enable file file_path=/var/log/vault/audit.log

Every request and response is recorded in hashed form. This is central to compliance.

Recap

ItemKey point
Seal/UnsealSealed at start; unsealed with Shamir K-of-N keys
KV v2Static secrets, versioning and soft delete, /data/ in the path
PolicyPath-level capabilities, least privilege
Database engineTemporary accounts on request, auto-revoked after TTL
AppRoleApp auth with RoleID + SecretID
AuditRecord all requests with vault audit enable

Vault’s real value goes beyond storing static secrets: it is dynamic, short-lived credentials. The core mindset is “don’t store passwords—issue them briefly when needed.”

#vault#secrets#hashicorp#security#kv
Editorial note

AI tools may assist drafting. Check the evidence in each guide for whether commands were run and which environment was used. Confirm the current docs for your version before applying instructions, and email us about errors. email us

Topic-related official docs (auto-linked · not per-claim sources)OWASP documentation ↗HashiCorp Vault documentation ↗

Questions & answers

Ask a question about this guide. We'll review and reply.