Configuring HashiCorp Vault's KV v2 Secrets Engine for Versioned Storage
Enable HashiCorp Vault's KV v2 secrets engine to store versioned secrets, control access with ACL policies, and recover data using snapshots.
02 Jun 2026, 22:30 UTC

The Problem: Secrets Without History
When an application credential rotates or a database password changes, teams often need to know what the previous value was, when it changed, and how to restore it quickly. HashiCorp Vault's Key-Value (KV) secrets engine version 2 (kv-v2) addresses this by storing each secret as a versioned JSON blob under a specific mount path. Unlike KV version 1, which overwrites data in place, KV v2 retains multiple revisions, supports logical deletes, and exposes metadata for audits and rollbacks.
Desired Outcome
By the end of this guide, you will have a KV v2 mount enabled at a known path, a test secret written and versioned, an ACL policy that controls access without over-granting, and a snapshot-based recovery plan. The result is a secret store where every change is tracked and recoverable.
Prerequisites
- A running Vault cluster that is initialized and unsealed.
- A token with permissions to enable secrets engines, write policies, and create snapshots (typically a root or admin token for initial setup).
- The Vault CLI installed on your administrative workstation.
- Assumption: you are using a modern Vault release (1.15 or later) where
vault kvcommands are standard. Verify your version withvault version.
Enable the KV v2 Mount
KV v2 is not active by default at the secret/ path in all deployments; it must be explicitly enabled at a mount path. A mount path is the prefix under which the engine operates, such as secret/ or kv/.
Run the following command from a terminal with Vault CLI access, using a token that has sudo or engine-enable capabilities:
vault secrets enable -path=secret kv-v2
If the path is already in use, Vault returns an error. Choose a unique path or disable the existing engine first. Writing to a path where KV v2 is not enabled results in a 404 error from the API.
Write and Read a Versioned Secret
Secrets in KV v2 are arbitrary JSON key-value pairs. Each write creates a new immutable version.
From the same CLI session, write a test secret:
vault kv put secret/app username="dbuser" password="example-password"
Read it back:
vault kv get secret/app
The read returns the latest non-deleted version by default. To confirm the version number and metadata, use:
vault kv metadata get secret/app
This metadata includes the current version, the oldest available version, and timestamps for each revision.
Control Access with ACL Policies
Vault uses ACL (Access Control List) policies to grant capabilities on specific paths. For KV v2, the relevant capabilities are create, read, update, delete, and list. Over-granting can expose secrets; under-granting breaks automation.
Create a policy file named app-policy.hcl:
path "secret/data/app" {
capabilities = ["create", "read", "update"]
}
path "secret/metadata/app" {
capabilities = ["read", "list"]
}
The secret/data/ path controls the secret payloads, while secret/metadata/ controls version history and deletion operations. Load the policy:
vault policy write app-policy app-policy.hcl
Verify it:
vault policy read app-policy
Test the policy by generating a token with it and attempting a read. If the token cannot read the secret, re-check the path and capabilities.
Delete, Destroy, and Retention
KV v2 distinguishes between logical and physical deletion.
A logical delete marks the latest version as deleted without removing the underlying data immediately:
vault kv delete secret/app
The data is physically removed later based on the engine's delete_version_after setting or when max_versions retention is exceeded. To permanently remove a specific version immediately, use destroy:
vault kv destroy secret/app -versions=1
To remove all versions and metadata for a secret, use:
vault kv metadata delete secret/app
Be aware that max_versions can consume significant storage if set too high. Set a realistic limit based on your audit requirements.
Backup with Snapshots
For disaster recovery, Vault provides an integrated snapshot mechanism that captures the full storage backend state, including KV v2 data and metadata.
Run this from a node with storage backend access and a token with operator capabilities:
vault operator snapshot save backup.snap
Store the snapshot in a secure location. Unseal keys and root tokens must be protected separately; leaking them compromises all KV v2 data and the entire cluster.
Expected Checks and Recovery
After configuration, verify the mount and secret state:
- Confirm the mount:
vault secrets listshould showsecret/with typekvand version2. - Verify versioning:
vault kv metadata get secret/appshould showcreated_versionandcurrent_versionmatching your writes. - Check deletion status: After
vault kv delete secret/app, a subsequentvault kv get secret/appshould indicate the version is deleted, while metadata still lists it. - Test recovery: Restore the snapshot in an isolated test environment with
vault operator snapshot restoreand confirm the secret and its versions are present.
To roll back to a previous version, read it explicitly:
vault kv get -version=1 secret/app
Then write that value back as a new version if needed.
Limitations and Practical Verification
KV v2 retention is bounded by max_versions; older versions are purged automatically. Logical deletes do not purge data immediately, so sensitive values may persist on disk until the retention window passes. ACL policies must be tested before production use—misconfiguration can expose secrets to unintended actors.
The most practical verification is a round-trip test: write a secret, read it back, inspect metadata, apply a restrictive policy, and confirm an unauthorized token is denied. For recovery, restore a snapshot into a non-production Vault instance and validate that the secret payload and version history match the source.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.