Vault

Vault KV v2: Versioning and Metadata, Cleanly Explained

2026-04-19
NicheeLab Editorial Team

The headline feature of KV v2 is safely keeping multiple versions of the same secret. In real-world operations, that maps directly to rollback, audit, and conflict prevention via CAS (check-and-set).

This article covers the differences from v1, the behavior of delete/destroy/undelete, the metadata fields, and the API-path pitfalls — all framed around what the exam tends to ask.

The Big Picture and How KV v2 Differs from v1

KV v2 manages metadata independently from the value itself and auto-assigns a version number on every write. Overwriting the latest version preserves the previous ones, so you can restore or diff them.

The API paths are not compatible with v1. The CLI hides this, but in policies and direct API calls you must split between `data/` and `metadata/`.

  • Every write creates a new version, and older versions remain readable
  • Metadata includes `created_time`, `deletion_time`, `destroyed`, and `version`
  • API endpoints split into /v1/<mount>/data/<path> (value and versions) and /v1/<mount>/metadata/<path> (attributes, limits, deletion state)
  • CAS (check-and-set) detects concurrent-update conflicts
  • `delete` is reversible (undelete), `destroy` is permanent
AspectKV v1KV v2Exam angle
VersioningNoneYes (auto-numbered)Whether you can read/restore a specific version
API path/v1/<mount>/<path>/v1/<mount>/data|metadata/<path>Policies must also reference `data/` and `metadata/`
Delete behaviorSimple delete`delete` = tombstone, `destroy` = purgeOnly `delete` is reversible via `undelete`
CASNoneYes (`-cas` flag and `metadata.cas_required`)The basics of optimistic concurrency control
Metadata configLimited`max_versions`, `cas_required`, `delete_version_after`, etc.Mind how older versions are handled when the limit is exceeded

KV v2 request path and version retention

Client
  |  vault kv put/get/delete
  v
[Mount: secret (kv-v2)]
  |-- /v1/secret/data/<path>       # Value and version operations
  |-- /v1/secret/metadata/<path>   # Attributes, limits, deletion state
  '-- backend storage (raft/consul)

Versions: 1 -> 2 -> 3 (latest)
 delete: tombstone (reversible)
 destroy: purge (permanent)

Enable the engine and verify the basics

vault secrets enable -path=secret kv-v2
vault kv put secret/app api_key=AAA env=prod   # create v1
vault kv put secret/app api_key=BBB            # create v2
vault kv get secret/app                        # default returns the latest (v2)
vault kv get -version=1 secret/app             # read a previous version

Basic Operations: put/get/list with Version Selection

On the CLI, the `-version` flag reads any previous version you want. Writes always create a new version — they never overwrite an existing one.

`list` returns the keys under a hierarchy (the CLI `list` works on v2 too). When calling the API directly, listings live under the `metadata/` path.

  • Read a non-latest version: `vault kv get -version=N <mount>/<path>`
  • List keys: `vault kv list <mount>/<prefix>`
  • Get metadata as JSON: `vault kv get -format=json` and read `.data.metadata.version`

Version reads and listings

# Latest and a specific version
vault kv get secret/app
vault kv get -version=1 secret/app

# Pull just the version number via JSON
vault kv get -format=json secret/app | jq -r '.data.metadata.version'

# List
vault kv list secret/

Metadata Deep Dive: Fields and Settings

Each version's metadata carries `created_time`, `deletion_time`, `destroyed`, and `version`. That lets your code decide programmatically whether a version is recoverable and when it was created.

Metadata settings control `max_versions` (retention cap), `cas_required` (require CAS on updates), and `delete_version_after` (auto-cleanup timer for soft-deleted versions). When unset, the mount's defaults apply.

  • `max_versions`: when a new write exceeds the cap, the oldest version is auto-pruned
  • `cas_required`: updates must include `-cas` (or `options.cas` via the API)
  • `delete_version_after`: duration from tombstone to auto-cleanup (e.g., `168h`)

Reading and writing metadata (CLI and API)

# Read metadata for a single key
vault kv metadata get secret/app

# Set metadata (limit / CAS / delayed delete)
vault kv metadata put -max-versions=20 -cas-required=true -delete-version-after=168h secret/app

# Read and write metadata via the API
curl -s \
  -H "X-Vault-Token: $VAULT_TOKEN" \
  $VAULT_ADDR/v1/secret/metadata/app | jq

curl -s -X POST \
  -H "X-Vault-Token: $VAULT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"max_versions":20, "cas_required":true, "delete_version_after":"168h"}' \
  $VAULT_ADDR/v1/secret/metadata/app

Delete, Destroy, and Undelete Behavior

In KV v2, `delete` soft-deletes (tombstones) the specified version. You can bring it back with `undelete`. `destroy` permanently wipes the version's data — there is no coming back.

Deleting the metadata for an entire key (`metadata delete`) wipes every version and all metadata at once. The blast radius is huge, so design your capabilities carefully.

  • Soft delete: `vault kv delete -versions=N <mount>/<path>`
  • Undelete: `vault kv undelete -versions=N <mount>/<path>`
  • Permanent destroy: `vault kv destroy -versions=N <mount>/<path>`
  • Delete an entire key: `vault kv metadata delete <mount>/<path>`

Delete-and-undelete sequence

# Check v2 (the latest)
vault kv get secret/app

# Soft-delete v1 (reversible)
vault kv delete -versions=1 secret/app
vault kv get -version=1 secret/app        # unreadable (tombstone)
vault kv undelete -versions=1 secret/app  # bring it back
vault kv get -version=1 secret/app        # readable again

# Destroy v1 permanently (irreversible)
vault kv destroy -versions=1 secret/app

# Wipe the entire key (all versions and metadata)
vault kv metadata delete secret/app

Concurrent-Update Control with CAS, and Safe Rollback

With CAS, the client states the version it expects to update, and the write is accepted only if that matches. It prevents mix-ups under concurrent updates.

Rollback usually means reading a previous version and writing its contents back as a brand-new version. You are not really "going back" to the old version — you are creating a new version that contains the old contents.

  • Confirm the expected version: extract `.data.metadata.version` with jq
  • Run `put` with `-cas=N`; mismatched versions fail
  • Enabling `cas_required` rejects any update without CAS

CAS update and rollback example

# Look up the current version
CURR=$(vault kv get -format=json secret/app | jq -r '.data.metadata.version')

# Safe update with CAS (fails on mismatch)
vault kv put -cas="$CURR" secret/app api_key=CCC

# Roll back using v1's contents (written as v3)
OLD=$(vault kv get -format=json -version=1 secret/app | jq -r '.data.data | to_entries | map(\"\(.key)=\(.value)\") | join(" ")')
eval vault kv put secret/app $OLD

Policy and Operations Essentials (Associate-Level)

On v2 you must grant appropriate capabilities on both `data/` and `metadata/`. Keep `read` vs `list`, and `delete` vs `destroy` / `metadata delete`, clearly separated.

To control storage growth, combine `max_versions` with `delete_version_after`. Pruning older versions when the cap is hit avoids hoarding data you do not need.

  • Grant read capabilities on `data/`, and listing or metadata operations on `metadata/`
  • Reserve `destroy` and `metadata delete` for tightly scoped roles only
  • Combine the version cap with auto-cleanup to keep storage from ballooning

Least-privilege policy example for v2

path "secret/data/app" {
  capabilities = ["create", "update", "read"]
}
path "secret/metadata/app" {
  capabilities = ["read", "list", "update"]
}
# Keep destructive operations in a separate role
path "secret/destroy/app" {
  capabilities = ["update"]
}
path "secret/metadata/app" {
  capabilities = ["delete"]  # for metadata delete (use carefully)
}

Check Your Understanding

Associate

問題 1

In KV v2, you want to make a specific version inaccessible while keeping future restoration possible. Which operation fits best?

  1. vault kv delete -versions=3 secret/app
  2. vault kv destroy -versions=3 secret/app
  3. vault kv metadata delete secret/app
  4. vault kv put -cas=3 secret/app

正解: A

`delete` is a soft delete (tombstone) and can be reversed later with `undelete`. `destroy` is irreversible, `metadata delete` wipes the entire key, and `put -cas` is an update, not a delete.

Frequently Asked Questions

How do I permanently remove a specific version?

Use `vault kv destroy -versions=N <mount>/<path>`. `delete` is a soft delete — the data still lives in storage and can be undeleted, so it is not a real purge.

After switching to v2, my API calls return 404 or permission denied.

Your policies or request paths are probably still v1-shaped. For v2, reads go through `/v1/<mount>/data/<path>`, while metadata and listings go through `/v1/<mount>/metadata/<path>`. Grant capabilities on the matching paths.

What happens to older versions once `max_versions` is exceeded?

When a new write pushes the count over the limit, the oldest versions are automatically pruned and can no longer be read or undeleted. Plan the limit around your retention requirements.

Check what you learned with practice questions

Practice with certification-focused question sets

無料で問題を解いてみる
Author

NicheeLab Editorial Team

NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.


Related articles
Vault

Vault Core Concepts: Sealed/Unsealed, Auth, Secrets (2026)

Vault fundamentals — sealed/unsealed state, auth methods, se...

Vault

Vault Operations Professional (VOP-003): Complete Guide (2026)

Pass the Vault Operations Professional exam — enterprise pat...

Vault

Vault Path-Based Routing: API URL Structure (2026)

How Vault's path-based routing works — mount points, sub-pat...

Vault

Vault Tokens: Auth Token Mechanics (2026)

Token fundamentals — service vs. batch tokens, accessor, ren...

Vault

Vault Token Types: Service, Batch, Periodic (2026)

Service vs. batch tokens compared — performance, ACL behavio...

Browse all Vault articles (101)
© 2026 NicheeLab All rights reserved.