2018-04-17 21:42:14 +00:00
---
2020-01-18 00:18:09 +00:00
layout: guides
page_title: Versioned KV Secret Engine - Guides
sidebar_title: Versioned KV Secret Engine
2018-04-17 21:42:14 +00:00
description: |-
Vault 0.10.0 introduced version 2 of key-value secret engine which supports
versioning of your secrets so that you can undo the accidental deletion of
secrets, or compare the different versions of the secret.
---
# Versioned Key/Value Secret Engine
2020-01-22 20:05:41 +00:00
The [Static Secrets](/guides/secret-mgmt/static-secrets) guide introduced
2018-04-17 21:42:14 +00:00
the basics of working with key-value secret engine. **Vault 0.10** introduced [_K/V
Secrets Engine v2 with Secret
2020-01-18 00:18:09 +00:00
Versioning_](https://www.hashicorp.com/blog/vault-0-10). This guide
2018-04-17 21:42:14 +00:00
demonstrates the new features introduced by the key-value secret engine v2.
## Reference Material
2020-01-22 20:05:41 +00:00
- [Static Secrets guide](/guides/secret-mgmt/static-secrets)
- [KV Secrets Engine - Version 2](/docs/secrets/kv/kv-v2)
- [KV Secrets Engine - Version 2 (API)](/api/secret/kv/kv-v2)
2018-04-17 21:42:14 +00:00
2018-07-31 16:19:23 +00:00
~> **NOTE:** An [interactive
tutorial](https://www.katacoda.com/hashicorp/scenarios/vault-static-secrets) is
also available if you do not have a Vault environment to perform the steps
described in this guide.
2018-04-17 21:42:14 +00:00
## Estimated Time to Complete
10 minutes
## Challenge
The KV secret engine v1 does not provide a way to version or roll back secrets.
This made it difficult to recover from unintentional data loss or overwrite when
more than one user is writing at the same path.
## Solution
Run the **version 2** of KV secret engine which can retain a configurable
number of secret versions. This enables older versions' data to be retrievable
2020-01-18 00:18:09 +00:00
in case of unwanted deletion or updates of the data. In addition, its
2018-04-17 21:42:14 +00:00
_Check-and-Set_ operations can be used to protect the data from being overwritten
unintentionally.
New Docs Website (#5535)
* conversion stage 1
* correct image paths
* add sidebar title to frontmatter
* docs/concepts and docs/internals
* configuration docs and multi-level nav corrections
* commands docs, index file corrections, small item nav correction
* secrets converted
* auth
* add enterprise and agent docs
* add extra dividers
* secret section, wip
* correct sidebar nav title in front matter for apu section, start working on api items
* auth and backend, a couple directory structure fixes
* remove old docs
* intro side nav converted
* reset sidebar styles, add hashi-global-styles
* basic styling for nav sidebar
* folder collapse functionality
* patch up border length on last list item
* wip restructure for content component
* taking middleman hacking to the extreme, but its working
* small css fix
* add new mega nav
* fix a small mistake from the rebase
* fix a content resolution issue with middleman
* title a couple missing docs pages
* update deps, remove temporary markup
* community page
* footer to layout, community page css adjustments
* wip downloads page
* deps updated, downloads page ready
* fix community page
* homepage progress
* add components, adjust spacing
* docs and api landing pages
* a bunch of fixes, add docs and api landing pages
* update deps, add deploy scripts
* add readme note
* update deploy command
* overview page, index title
* Update doc fields
Note this still requires the link fields to be populated -- this is solely related to copy on the description fields
* Update api_basic_categories.yml
Updated API category descriptions. Like the document descriptions you'll still need to update the link headers to the proper target pages.
* Add bottom hero, adjust CSS, responsive friendly
* Add mega nav title
* homepage adjustments, asset boosts
* small fixes
* docs page styling fixes
* meganav title
* some category link corrections
* Update API categories page
updated to reflect the second level headings for api categories
* Update docs_detailed_categories.yml
Updated to represent the existing docs structure
* Update docs_detailed_categories.yml
* docs page data fix, extra operator page remove
* api data fix
* fix makefile
* update deps, add product subnav to docs and api landing pages
* Rearrange non-hands-on guides to _docs_
Since there is no place for these on learn.hashicorp, we'll put them
under _docs_.
* WIP Redirects for guides to docs
* content and component updates
* font weight hotfix, redirects
* fix guides and intro sidenavs
* fix some redirects
* small style tweaks
* Redirects to learn and internally to docs
* Remove redirect to `/vault`
* Remove `.html` from destination on redirects
* fix incorrect index redirect
* final touchups
* address feedback from michell for makefile and product downloads
2018-10-19 15:40:11 +00:00
![Versioned KV](/img/vault-versioned-kv-1.png)
2018-04-17 21:42:14 +00:00
## Prerequisites
To perform the tasks described in this guide, you need to have a Vault
2020-01-18 00:18:09 +00:00
environment. Refer to the [Getting
2020-01-22 20:05:41 +00:00
Started](/intro/getting-started/install) guide to install Vault. Make sure
2018-04-17 21:42:14 +00:00
that your Vault server has been [initialized and
2020-01-22 20:05:41 +00:00
unsealed](/intro/getting-started/deploy).
2018-04-17 21:42:14 +00:00
### Policy requirements
-> **NOTE:** For the purpose of this guide, you can use **`root`** token to work
with Vault. However, it is recommended that root tokens are only used for
initial setup or in emergencies. As a best practice, use tokens with
appropriate set of policies based on your role in the organization.
To perform all tasks demonstrated in this guide, your policy must include the
following permissions:
```shell
# To view in Web UI
path "sys/mounts" {
capabilities = [ "read", "update" ]
}
# Write and manage secrets in key-value secret engine
path "secret*" {
capabilities = [ "create", "read", "update", "delete", "list" ]
}
# To enable secret engines
path "sys/mounts/*" {
capabilities = [ "create", "read", "update", "delete" ]
}
```
If you are not familiar with policies, complete the
2020-01-22 20:05:41 +00:00
[policies](/guides/identity/policies) guide.
2018-04-17 21:42:14 +00:00
## Steps
2020-01-18 00:18:09 +00:00
This guide demonstrates the basic commands for working with KV secret engine v2.
2018-04-17 21:42:14 +00:00
You will perform the following:
1. [Check the KV secret engine version](#step1)
2. [Write secrets](#step2)
3. [Retrieve a specific version of secret](#step3)
4. [Specify the number of versions to keep](#step4)
5. [Delete versions of secret](#step5)
6. [Permanently delete data](#step6)
2020-05-21 17:18:17 +00:00
### Step 1: Check the KV secret engine version ((#step1))
2020-01-18 00:18:09 +00:00
2018-04-17 21:42:14 +00:00
(**Persona:** devops)
Before beginning, verify that you are using the v2 of the KV secret engine.
#### CLI command
To check the KV secret engine version:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault secrets list -format=json
...
"secret/": {
"type": "kv",
"description": "key/value secret storage",
"accessor": "kv_f05b8b9c",
"config": {
"default_lease_ttl": 0,
"max_lease_ttl": 0,
"force_no_cache": false
},
"options": {
"version": "2"
},
...
```
The indicated **`version`** should be **`2`**. If the version is **`1`**,
upgrade it to v2.
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault kv enable-versioning secret/
```
#### API call using cURL
To check the KV secret engine version:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ curl --header "X-Vault-Token: <TOKEN>" \
<VAULT_ADDRESS>/v1/sys/mounts
```
Where `<TOKEN>` is your valid token, and `<VAULT_ADDRESS>` is where your vault
server is running.
**Example:**
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ curl --header "X-Vault-Token: ..." \
http://127.0.0.1:8200/v1/sys/mounts | jq
...
"secret/": {
"accessor": "kv_f05b8b9c",
"config": {
"default_lease_ttl": 0,
"force_no_cache": false,
"max_lease_ttl": 0,
"plugin_name": ""
},
"description": "key/value secret storage",
"local": false,
"options": {
"version": "2"
},
"seal_wrap": false,
"type": "kv"
},
...
```
The indicated **`version`** should be **`2`**. If the version is **`1`**,
upgrade it to v2.
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ cat payload.json
{
"options": {
"version": "2"
}
}
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data @payload.json \
http://127.0.0.1:8200/v1/sys/mounts/secret/tune
```
#### Web UI
Open a web browser and launch the Vault UI (e.g. `http://127.0.0.1:8200/ui`) and
then login.
New Docs Website (#5535)
* conversion stage 1
* correct image paths
* add sidebar title to frontmatter
* docs/concepts and docs/internals
* configuration docs and multi-level nav corrections
* commands docs, index file corrections, small item nav correction
* secrets converted
* auth
* add enterprise and agent docs
* add extra dividers
* secret section, wip
* correct sidebar nav title in front matter for apu section, start working on api items
* auth and backend, a couple directory structure fixes
* remove old docs
* intro side nav converted
* reset sidebar styles, add hashi-global-styles
* basic styling for nav sidebar
* folder collapse functionality
* patch up border length on last list item
* wip restructure for content component
* taking middleman hacking to the extreme, but its working
* small css fix
* add new mega nav
* fix a small mistake from the rebase
* fix a content resolution issue with middleman
* title a couple missing docs pages
* update deps, remove temporary markup
* community page
* footer to layout, community page css adjustments
* wip downloads page
* deps updated, downloads page ready
* fix community page
* homepage progress
* add components, adjust spacing
* docs and api landing pages
* a bunch of fixes, add docs and api landing pages
* update deps, add deploy scripts
* add readme note
* update deploy command
* overview page, index title
* Update doc fields
Note this still requires the link fields to be populated -- this is solely related to copy on the description fields
* Update api_basic_categories.yml
Updated API category descriptions. Like the document descriptions you'll still need to update the link headers to the proper target pages.
* Add bottom hero, adjust CSS, responsive friendly
* Add mega nav title
* homepage adjustments, asset boosts
* small fixes
* docs page styling fixes
* meganav title
* some category link corrections
* Update API categories page
updated to reflect the second level headings for api categories
* Update docs_detailed_categories.yml
Updated to represent the existing docs structure
* Update docs_detailed_categories.yml
* docs page data fix, extra operator page remove
* api data fix
* fix makefile
* update deps, add product subnav to docs and api landing pages
* Rearrange non-hands-on guides to _docs_
Since there is no place for these on learn.hashicorp, we'll put them
under _docs_.
* WIP Redirects for guides to docs
* content and component updates
* font weight hotfix, redirects
* fix guides and intro sidenavs
* fix some redirects
* small style tweaks
* Redirects to learn and internally to docs
* Remove redirect to `/vault`
* Remove `.html` from destination on redirects
* fix incorrect index redirect
* final touchups
* address feedback from michell for makefile and product downloads
2018-10-19 15:40:11 +00:00
![Web UI](/img/vault-versioned-kv-2.png)
2018-04-17 21:42:14 +00:00
If `secret/` does not indicates **`v2`**, you can upgrade it from `v1` to `v2`
by executing the following CLI command:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault kv enable-versioning secret/
```
Alternatively, you can enable KV secret engine v2 at a different path by
clicking **Enable new engine**. Select **KV** from the **Secret engine type**
2020-01-18 00:18:09 +00:00
drop-down list. Be sure that the **Version** is set to be **Version 2**.
2018-04-17 21:42:14 +00:00
New Docs Website (#5535)
* conversion stage 1
* correct image paths
* add sidebar title to frontmatter
* docs/concepts and docs/internals
* configuration docs and multi-level nav corrections
* commands docs, index file corrections, small item nav correction
* secrets converted
* auth
* add enterprise and agent docs
* add extra dividers
* secret section, wip
* correct sidebar nav title in front matter for apu section, start working on api items
* auth and backend, a couple directory structure fixes
* remove old docs
* intro side nav converted
* reset sidebar styles, add hashi-global-styles
* basic styling for nav sidebar
* folder collapse functionality
* patch up border length on last list item
* wip restructure for content component
* taking middleman hacking to the extreme, but its working
* small css fix
* add new mega nav
* fix a small mistake from the rebase
* fix a content resolution issue with middleman
* title a couple missing docs pages
* update deps, remove temporary markup
* community page
* footer to layout, community page css adjustments
* wip downloads page
* deps updated, downloads page ready
* fix community page
* homepage progress
* add components, adjust spacing
* docs and api landing pages
* a bunch of fixes, add docs and api landing pages
* update deps, add deploy scripts
* add readme note
* update deploy command
* overview page, index title
* Update doc fields
Note this still requires the link fields to be populated -- this is solely related to copy on the description fields
* Update api_basic_categories.yml
Updated API category descriptions. Like the document descriptions you'll still need to update the link headers to the proper target pages.
* Add bottom hero, adjust CSS, responsive friendly
* Add mega nav title
* homepage adjustments, asset boosts
* small fixes
* docs page styling fixes
* meganav title
* some category link corrections
* Update API categories page
updated to reflect the second level headings for api categories
* Update docs_detailed_categories.yml
Updated to represent the existing docs structure
* Update docs_detailed_categories.yml
* docs page data fix, extra operator page remove
* api data fix
* fix makefile
* update deps, add product subnav to docs and api landing pages
* Rearrange non-hands-on guides to _docs_
Since there is no place for these on learn.hashicorp, we'll put them
under _docs_.
* WIP Redirects for guides to docs
* content and component updates
* font weight hotfix, redirects
* fix guides and intro sidenavs
* fix some redirects
* small style tweaks
* Redirects to learn and internally to docs
* Remove redirect to `/vault`
* Remove `.html` from destination on redirects
* fix incorrect index redirect
* final touchups
* address feedback from michell for makefile and product downloads
2018-10-19 15:40:11 +00:00
![Enabling kv-v2](/img/vault-versioned-kv-3.png)
2018-04-17 21:42:14 +00:00
Click **Enable Engine** to complete.
2020-05-21 17:18:17 +00:00
### Step 2: Write Secrets ((#step2))
2018-04-17 21:42:14 +00:00
To understand how the versioning works, let's write some test data.
#### CLI commands
To write secrets, run `vault kv put` command instead of `vault write`:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault kv put secret/customer/acme name="ACME Inc." contact_email="jsmith@acme.com"
Key Value
--- -----
created_time 2018-04-14T00:05:47.115378933Z
deletion_time n/a
destroyed false
version 1
```
To update the existing secret, run the `vault kv put` command again:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault kv put secret/customer/acme name="ACME Inc." contact_email="john.smith@acme.com"
Key Value
--- -----
created_time 2018-04-14T00:13:35.296018431Z
deletion_time n/a
destroyed false
version 2
```
Now you have two versions of the `secret/customer/acme` data. Run `vault kv get`
to read the data.
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault kv get secret/customer/acme
====== Metadata ======
Key Value
--- -----
created_time 2018-04-14T00:13:35.296018431Z
deletion_time n/a
destroyed false
version 2
======== Data ========
Key Value
--- -----
contact_email john.smith@acme.com
name ACME Inc.
```
#### API call using cURL
Write some data at `secret/customer/acme`:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ tee payload.json <<EOF
{
"data": {
"name": "ACME Inc.",
"contact_email": "jsmith@acme.com"
}
}
EOF
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data @payload.json \
http://127.0.0.1:8200/v1/secret/data/customer/acme
```
Notice that the endpoint for KV v2 is **`/secret/data/<path>`**; therefore, to
write secrets at `secret/customer/acme`, the API endpoint becomes
`/secret/data/customer/acme`.
Update the secret to create another version:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ tee payload.json <<EOF
{
"data": {
"name": "ACME Inc.",
"contact_email": "john.smith@acme.com"
}
}
EOF
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data @payload.json \
http://127.0.0.1:8200/v1/secret/data/customer/acme
```
Now you have two versions of the `secret/customer/acme` data. Read back the secret.
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ curl --header "X-Vault-Token: ..." \
http://127.0.0.1:8200/v1/secret/data/customer/acme
{
"request_id": "7233b69d-35d9-6c1b-ae81-9a679a03082d",
"lease_id": "",
"renewable": false,
"lease_duration": 0,
"data": {
"data": {
"contact_email": "john.smith@acme.com",
"name": "ACME Inc."
},
"metadata": {
"created_time": "2018-04-14T00:59:11.27903511Z",
"deletion_time": "",
"destroyed": false,
"version": 2
}
},
"wrap_info": null,
"warnings": null,
"auth": null
}
```
#### Web UI
In the Web UI, select `secret/` and then click **Create secret**.
New Docs Website (#5535)
* conversion stage 1
* correct image paths
* add sidebar title to frontmatter
* docs/concepts and docs/internals
* configuration docs and multi-level nav corrections
* commands docs, index file corrections, small item nav correction
* secrets converted
* auth
* add enterprise and agent docs
* add extra dividers
* secret section, wip
* correct sidebar nav title in front matter for apu section, start working on api items
* auth and backend, a couple directory structure fixes
* remove old docs
* intro side nav converted
* reset sidebar styles, add hashi-global-styles
* basic styling for nav sidebar
* folder collapse functionality
* patch up border length on last list item
* wip restructure for content component
* taking middleman hacking to the extreme, but its working
* small css fix
* add new mega nav
* fix a small mistake from the rebase
* fix a content resolution issue with middleman
* title a couple missing docs pages
* update deps, remove temporary markup
* community page
* footer to layout, community page css adjustments
* wip downloads page
* deps updated, downloads page ready
* fix community page
* homepage progress
* add components, adjust spacing
* docs and api landing pages
* a bunch of fixes, add docs and api landing pages
* update deps, add deploy scripts
* add readme note
* update deploy command
* overview page, index title
* Update doc fields
Note this still requires the link fields to be populated -- this is solely related to copy on the description fields
* Update api_basic_categories.yml
Updated API category descriptions. Like the document descriptions you'll still need to update the link headers to the proper target pages.
* Add bottom hero, adjust CSS, responsive friendly
* Add mega nav title
* homepage adjustments, asset boosts
* small fixes
* docs page styling fixes
* meganav title
* some category link corrections
* Update API categories page
updated to reflect the second level headings for api categories
* Update docs_detailed_categories.yml
Updated to represent the existing docs structure
* Update docs_detailed_categories.yml
* docs page data fix, extra operator page remove
* api data fix
* fix makefile
* update deps, add product subnav to docs and api landing pages
* Rearrange non-hands-on guides to _docs_
Since there is no place for these on learn.hashicorp, we'll put them
under _docs_.
* WIP Redirects for guides to docs
* content and component updates
* font weight hotfix, redirects
* fix guides and intro sidenavs
* fix some redirects
* small style tweaks
* Redirects to learn and internally to docs
* Remove redirect to `/vault`
* Remove `.html` from destination on redirects
* fix incorrect index redirect
* final touchups
* address feedback from michell for makefile and product downloads
2018-10-19 15:40:11 +00:00
![Write Secret](/img/vault-versioned-kv-5.png)
2018-04-17 21:42:14 +00:00
Click **Save**.
To update the existing secret, select **Edit**, change the `contact_email`
value, and then click **Save**.
New Docs Website (#5535)
* conversion stage 1
* correct image paths
* add sidebar title to frontmatter
* docs/concepts and docs/internals
* configuration docs and multi-level nav corrections
* commands docs, index file corrections, small item nav correction
* secrets converted
* auth
* add enterprise and agent docs
* add extra dividers
* secret section, wip
* correct sidebar nav title in front matter for apu section, start working on api items
* auth and backend, a couple directory structure fixes
* remove old docs
* intro side nav converted
* reset sidebar styles, add hashi-global-styles
* basic styling for nav sidebar
* folder collapse functionality
* patch up border length on last list item
* wip restructure for content component
* taking middleman hacking to the extreme, but its working
* small css fix
* add new mega nav
* fix a small mistake from the rebase
* fix a content resolution issue with middleman
* title a couple missing docs pages
* update deps, remove temporary markup
* community page
* footer to layout, community page css adjustments
* wip downloads page
* deps updated, downloads page ready
* fix community page
* homepage progress
* add components, adjust spacing
* docs and api landing pages
* a bunch of fixes, add docs and api landing pages
* update deps, add deploy scripts
* add readme note
* update deploy command
* overview page, index title
* Update doc fields
Note this still requires the link fields to be populated -- this is solely related to copy on the description fields
* Update api_basic_categories.yml
Updated API category descriptions. Like the document descriptions you'll still need to update the link headers to the proper target pages.
* Add bottom hero, adjust CSS, responsive friendly
* Add mega nav title
* homepage adjustments, asset boosts
* small fixes
* docs page styling fixes
* meganav title
* some category link corrections
* Update API categories page
updated to reflect the second level headings for api categories
* Update docs_detailed_categories.yml
Updated to represent the existing docs structure
* Update docs_detailed_categories.yml
* docs page data fix, extra operator page remove
* api data fix
* fix makefile
* update deps, add product subnav to docs and api landing pages
* Rearrange non-hands-on guides to _docs_
Since there is no place for these on learn.hashicorp, we'll put them
under _docs_.
* WIP Redirects for guides to docs
* content and component updates
* font weight hotfix, redirects
* fix guides and intro sidenavs
* fix some redirects
* small style tweaks
* Redirects to learn and internally to docs
* Remove redirect to `/vault`
* Remove `.html` from destination on redirects
* fix incorrect index redirect
* final touchups
* address feedback from michell for makefile and product downloads
2018-10-19 15:40:11 +00:00
![Write Secret](/img/vault-versioned-kv-6.png)
2018-04-17 21:42:14 +00:00
2020-05-21 17:18:17 +00:00
### Step 3: Retrieve a Specific Version of Secret ((#step3))
2018-04-17 21:42:14 +00:00
You may run into a situation where you need to view the secret before an update.
#### CLI commands
To retrieve the version 1 of the secret written at `secret/customer/acme`:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault kv get -version=1 secret/customer/acme
====== Metadata ======
Key Value
--- -----
created_time 2018-04-14T00:05:47.115378933Z
deletion_time n/a
destroyed false
version 1
======== Data ========
Key Value
--- -----
contact_email jsmith@acme.com
name ACME Inc.
```
To read the **metadata** of `secret/customer/acme`:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault kv metadata get secret/customer/acme
======= Metadata =======
Key Value
--- -----
created_time 2018-04-14T00:05:47.115378933Z
current_version 2
max_versions 0
oldest_version 0
updated_time 2018-04-14T00:13:35.296018431Z
====== Version 1 ======
Key Value
--- -----
created_time 2018-04-14T00:05:47.115378933Z
deletion_time n/a
destroyed false
====== Version 2 ======
Key Value
--- -----
created_time 2018-04-14T00:13:35.296018431Z
deletion_time n/a
destroyed false
```
#### API call using cURL
To retrieve the version 1 of the secret written at `secret/customer/acme`:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ curl --header "X-Vault-Token: ..." \
http://127.0.0.1:8200/v1/secret/data/customer/acme?version=1 | jq
{
"request_id": "3bf5a2c1-d89b-9dd5-9bb5-0bc61a4a6d83",
"lease_id": "",
"renewable": false,
"lease_duration": 0,
"data": {
"data": {
"contact_email": "jsmith@acme.com",
"name": "ACME Inc."
},
"metadata": {
"created_time": "2018-04-14T00:05:47.115378933Z",
"deletion_time": "",
"destroyed": false,
"version": 1
}
},
"wrap_info": null,
"warnings": null,
"auth": null
}
```
To read the **metadata** of `secret/customer/acme`:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ curl --header "X-Vault-Token: ..." \
http://127.0.0.1:8200/v1/secret/metadata/customer/acme | jq
{
"request_id": "34708262-59cd-9a94-247f-3b1db0909050",
"lease_id": "",
"renewable": false,
"lease_duration": 0,
"data": {
"created_time": "2018-04-14T00:05:47.115378933Z",
"current_version": 2,
"max_versions": 0,
"oldest_version": 0,
"updated_time": "2018-04-14T00:13:35.296018431Z",
"versions": {
"1": {
"created_time": "2018-04-14T00:05:47.115378933Z",
"deletion_time": "",
"destroyed": false
},
"2": {
"created_time": "2018-04-14T00:13:35.296018431Z",
"deletion_time": "",
"destroyed": false
}
}
},
"wrap_info": null,
"warnings": null,
"auth": null
}
```
2020-05-21 17:18:17 +00:00
### Step 4: Specify the number of versions to keep ((#step4))
2018-04-17 21:42:14 +00:00
2020-01-18 00:18:09 +00:00
By default, the `kv-v2` secret engine keeps up to 10 versions. Let's limit the
2018-04-17 21:42:14 +00:00
maximum number of versions to keep to be 4.
#### CLI command
To set the `secret/` to keep up to 4 versions:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault write secret/config max_versions=4
Success! Data written to: secret/config
# View the configuration settings
$ vault read secret/config
Key Value
--- -----
cas_required false
max_versions 4
```
Alternatively, to limit the number of versions only on the
**`secret/customer/acme`** path rather than the entire `secret/` engine:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault kv metadata put -max-versions=4 secret/customer/acme
```
Overwrite the data a few more times to see what happens to the data.
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault kv metadata get secret/customer/acme
======= Metadata =======
Key Value
--- -----
created_time 2018-04-14T00:42:25.677078177Z
current_version 6
max_versions 0
oldest_version 3
updated_time 2018-04-16T00:17:23.930473344Z
====== Version 3 ======
Key Value
--- -----
created_time 2018-04-16T00:15:59.880368849Z
deletion_time n/a
destroyed false
====== Version 4 ======
Key Value
--- -----
created_time 2018-04-16T00:16:18.941331243Z
deletion_time n/a
destroyed false
====== Version 5 ======
Key Value
--- -----
created_time 2018-04-16T00:16:34.407951572Z
deletion_time n/a
destroyed false
====== Version 6 ======
Key Value
--- -----
created_time 2018-04-16T00:17:23.930473344Z
deletion_time n/a
destroyed false
```
In this example, the current version is 6. Notice that version 1 and 2 do not
show up in the metadata. Because the kv secret engine is configured to keep only
4 versions, the oldest two versions are permanently deleted and you won't be
able to read them.
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault kv get -version=1 secret/customer/acme
No value found at secret/data/customer/data
```
#### API call using cURL
To set the `secret/` to keep up to 4 versions:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ tee payload.json<<EOF
{
"max_versions": 4,
"cas_required": false
}
EOF
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data @payload.json
http://127.0.0.1:8200/v1/secret/config
```
To view the configuration:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ curl --header "X-Vault-Token: ..." \
http://127.0.0.1:8200/v1/secret/config | jq
{
"request_id": "8addfed1-41eb-6a19-8342-93f493c51538",
"lease_id": "",
"renewable": false,
"lease_duration": 0,
"data": {
"cas_required": false,
"max_versions": 4
},
"wrap_info": null,
"warnings": null,
"auth": null
}
```
Alternatively, to limit the number of versions only on the
**`secret/customer/acme`** path rather than the entire `secret/` engine:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data @payload.json
http://127.0.0.1:8200/v1/secret/metadata/customer/acme
```
Invoke the `secret/metadata/customer/acme` endpoint instead.
Overwrite the data a few more times to see what happens to the data.
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ curl --header "X-Vault-Token: ..." \
http://127.0.0.1:8200/v1/secret/metadata/customer/acme | jq
{
"request_id": "f2dd7f69-294c-e5c3-d582-f723005ea243",
"lease_id": "",
"renewable": false,
"lease_duration": 0,
"data": {
"created_time": "2018-04-14T00:42:25.677078177Z",
"current_version": 6,
"max_versions": 0,
"oldest_version": 3,
"updated_time": "2018-04-16T00:17:23.930473344Z",
"versions": {
"3": {
"created_time": "2018-04-16T00:15:59.880368849Z",
"deletion_time": "",
"destroyed": false
},
"4": {
"created_time": "2018-04-16T00:16:18.941331243Z",
"deletion_time": "",
"destroyed": false
},
"5": {
"created_time": "2018-04-16T00:16:34.407951572Z",
"deletion_time": "",
"destroyed": false
},
"6": {
"created_time": "2018-04-16T00:17:23.930473344Z",
"deletion_time": "",
"destroyed": false
}
}
},
"wrap_info": null,
"warnings": null,
"auth": null
}
```
In this example, the current version is 6. Notice that version 1 and 2 do not
show up in the metadata. Because the kv secret engine is configured to keep only
4 versions, the oldest two versions are permanently deleted and you won't be
able to read them.
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ curl --header "X-Vault-Token: ..." \
http://127.0.0.1:8200/v1/secret/data/customer/acme?version=1 | jq
{
"errors": []
}
```
2020-05-21 17:18:17 +00:00
### Step 5: Delete versions of secret ((#step5))
2018-04-17 21:42:14 +00:00
#### CLI command
Let's delete versions 4 and 5:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault kv delete -versions="4,5" secret/customer/acme
Success! Data deleted (if it existed) at: secret/customer/acme
# Check the metadata
$ vault kv metadata get secret/customer/acme
...
====== Version 4 ======
Key Value
--- -----
created_time 2018-04-16T00:12:25.404198622Z
deletion_time 2018-04-16T01:04:01.160426888Z
destroyed false
====== Version 5 ======
Key Value
--- -----
created_time 2018-04-16T00:12:47.527981267Z
deletion_time 2018-04-16T01:04:01.160427742Z
destroyed false
...
```
The metadata on versions 4 and 5 reports its deletion timestamp
(`deletion_time`); however, the `destroyed` parameter is set to `false`.
2020-01-18 00:18:09 +00:00
If version 5 was deleted by mistake and you wish to recover, invoke the `vault kv undelete` command:
2018-04-17 21:42:14 +00:00
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault kv undelete -versions=5 secret/customer/acme
Success! Data written to: secret/undelete/customer/acme
```
#### API call using cURL
Let's delete versions 4 and 5:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data '{ "versions":[4,5] }'
http://127.0.0.1:8200/v1/secret/delete/customer/acme
# Check the metadata
$ curl --header "X-Vault-Token: ..." \
http://127.0.0.1:8200/v1/secret/metadata/customer/acme | jq
...
"4": {
"created_time": "2018-04-16T00:16:18.941331243Z",
"deletion_time": "2018-04-16T01:17:42.003111567Z",
"destroyed": false
},
"5": {
"created_time": "2018-04-16T00:16:34.407951572Z",
"deletion_time": "2018-04-16T01:17:42.003111978Z",
"destroyed": false
},
...
```
The metadata on versions 4 and 5 reports its deletion timestamp
(`deletion_time`); however, the `destroyed` parameter is set to `false`.
If version 5 was deleted by mistake and you wish to recover, invoke the
`/secret/undelete` endpoint:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data '{ "versions":[5] }'
http://127.0.0.1:8200/v1/secret/undelete/customer/acme
```
2020-05-21 17:18:17 +00:00
### Step 6: Permanently delete data ((#step6))
2018-04-17 21:42:14 +00:00
#### CLI command
To permanently delete a version of secret:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault kv destroy -versions=4 secret/customer/acme
Success! Data written to: secret/destroy/customer/acme
# Check the metadata
$ vault kv metadata get secret/customer/acme
...
====== Version 4 ======
Key Value
--- -----
created_time 2018-04-16T00:12:25.404198622Z
deletion_time 2018-04-16T01:04:01.160426888Z
destroyed true
...
```
The metadata indicates that Version 4 is destroyed.
If you wish to destroy all the keys and versions at `secret/customer/acme`,
invoke the `vault kv metadata delete` command:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault kv metadata delete secret/customer/acme
Success! Data deleted (if it existed) at: secret/metadata/customer/acme
```
#### API call using cURL
To permanently delete a version of secret:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data '{ "versions":[4] }'
http://127.0.0.1:8200/v1/secret/destroy/customer/acme
# Check the metadata
$ curl --header "X-Vault-Token: ..." \
http://127.0.0.1:8200/v1/secret/metadata/customer/acme | jq
...
"4": {
"created_time": "2018-04-16T00:16:18.941331243Z",
"deletion_time": "2018-04-16T01:17:42.003111567Z",
"destroyed": true
},
...
```
The metadata indicates that Version 4 is destroyed.
If you wish to destroy all the keys and versions at `secret/customer/acme`,
invoke the `secret/metadata` endpoint:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ curl --header "X-Vault-Token: ..." \
--request DELETE
http://127.0.0.1:8200/v1/secret/metadata/customer/acme
```
### Additional Discussion
The v2 of KV secret engine supports a **_Check-And-Set_** operation to prevent
unintentional secret overwrite. When you pass the `cas` flag to Vault, it first
checks if the key already exists.
By default, _Check-And-Set_ operation is not enabled on the KV secret engine;
2020-01-18 00:18:09 +00:00
therefore, write is always allowed (no checking is performed).
2018-04-17 21:42:14 +00:00
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ vault read secret/config
Key Value
--- -----
cas_required false
max_versions 0
```
#### CLI command
To enable the **_Check-And-Set_** operation:
```shell
# Enable cas_requied on the secret engine mounted at secret/
$ vault write secret/config cas-required=true
# Enable cas_requied only on the secret/partner path
$ vault kv metadata put -cas-required=true secret/partner
```
Once check-and-set is enabled, every write operation requires `cas` value to be
passed. If you are sure that you want to overwrite the existing key-value, set
`cas` to match the current version. Set `cas` to `0` if you want to write the
2019-12-03 22:25:09 +00:00
secret _only if_ the key does not exist.
2018-04-17 21:42:14 +00:00
**Example:**
```shell
# To write if the key does not already exists
$ vault kv put -cas=0 secret/partner name="Example Co." partner_id="123456789"
Key Value
--- -----
created_time 2018-04-16T22:58:15.798753323Z
deletion_time n/a
destroyed false
version 1
# To overwrite the secret, you must specify the current version with -cas flag
$ vault kv put -cas=1 secret/partner name="Example Co." partner_id="ABCDEFGHIJKLMN"
Key Value
--- -----
created_time 2018-04-16T23:00:28.66552289Z
deletion_time n/a
destroyed false
version 2
```
#### API call using cURL
To enable the **_Check-And-Set_** operation:
2020-05-21 17:18:17 +00:00
```shell-session
2018-04-17 21:42:14 +00:00
$ tee payload.json<<EOF
{
"max_versions": 10,
"cas_required": true
}
EOF
# Enable cas_requied on the secret engine mounted at secret/
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data @payload.json
http://127.0.0.1:8200/v1/secret/config
# Enable cas_requied only on the secret/partner path
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data @payload.json
http://127.0.0.1:8200/v1/secret/metadata/partner
```
Once check-and-set is enabled, every write operation requires `cas` value to be
passed. If you are sure that you want to overwrite the existing key-value, set
`cas` to match the current version. Set `cas` to `0` if you want to write the
2019-12-03 22:25:09 +00:00
secret _only if_ the key does not exist.
2018-04-17 21:42:14 +00:00
**Example:**
```shell
# Write if the key does not already exists
$ tee payload.json <<EOF
{
"options": {
"cas": 0
},
"data": {
"name": "Example Co.",
"partner_id": "123456789"
}
}
EOF
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data @payload.json \
http://127.0.0.1:8200/v1/secret/data/partner
# To overwrite the secret, you must pass the current version
$ tee payload.json <<EOF
{
"options": {
"cas": 1
},
"data": {
"name": "Example Co.",
"partner_id": "ABCDEFGHIJKLMN"
}
}
EOF
$ curl --header "X-Vault-Token: ..." \
--request POST \
--data @payload.json \
http://127.0.0.1:8200/v1/secret/data/partner
```
~> If the **`cas`** value is missing in your write request, the
2020-01-18 00:18:09 +00:00
"`check-and-set parameter required for this call`" error will be returned. If
2018-04-17 21:42:14 +00:00
the `cas` does not match the current version number, you will receive the
"`check-and-set parameter did not match the current version`" message.
## Next steps
This guide introduced the CLI commands and API endpoints to read and write
2020-01-22 20:05:41 +00:00
static secrets in the key-value secret engine. Read [Secret as a Service: Dynamic Secrets](/guides/secret-mgmt/dynamic-secrets) guide to learn about the
2018-04-17 21:42:14 +00:00
usage of database secret engine.