PageSourceSearch

https://openbao.org/assets/js/2fce2d48.d828c7d6.js

js openbao.org collected 2026-10-02 06:33:47 UTC 27,807 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([["12610"],{64315(e,n,s){s.r(n),s.d(n,{metadata:()=>a,default:()=>h,frontMatter:()=>i,contentTitle:()=>l,toc:()=>o,assets:()=>d});var a=JSON.parse('{"id":"secrets/kv/kv-v2","title":"KV secrets engine - version 2","description":"The KV secrets engine can store arbitrary secrets.","source":"@site/content/docs/secrets/kv/kv-v2.mdx","sourceDirName":"secrets/kv","slug":"/secrets/kv/kv-v2","permalink":"/docs/next/secrets/kv/kv-v2","draft":false,"unlisted":false,"editUrl":"https://github.com/openbao/openbao/blob/main/website/content/docs/secrets/kv/kv-v2.mdx","tags":[],"version":"current","frontMatter":{"sidebar_label":"K/V Version 2","description":"The KV secrets engine can store arbitrary secrets."},"sidebar":"docs","previous":{"title":"K/V Version 1","permalink":"/docs/next/secrets/kv/kv-v1"},"next":{"title":"Kubernetes","permalink":"/docs/next/secrets/kubernetes"}}'),t=s(94686),r=s(44812);let i={sidebar_label:"K/V Version 2",description:"The KV secrets engine can store arbitrary secrets."},l="KV secrets engine - version 2",d={},o=[{value:"Setup",id:"setup",level:2},{value:"Upgrading from version 1",id:"upgrading-from-version-1",level:2},{value:"ACL rules",id:"acl-rules",level:2},{value:"Usage",id:"usage",level:2},{value:"Writing/Reading arbitrary data",id:"writingreading-arbitrary-data",level:3},{value:"Deleting and destroying data",id:"deleting-and-destroying-data",level:3},{value:"Key metadata",id:"key-metadata",level:3},{value:"API",id:"api",level:2}];function c(e){let n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"kv-secrets-engine---version-2",children:"KV secrets engine - version 2"})}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"kv"})," secrets engine is used to store arbitrary secrets within the\nconfigured physical storage for OpenBao."]}),"\n",(0,t.jsx)(n.p,{children:"Key names must always be strings. If you write non-string values directly via\nthe CLI, they will be converted into strings. However, you can preserve\nnon-string values by writing the key/value pairs to OpenBao from a JSON file or\nusing the HTTP API."}),"\n",(0,t.jsxs)(n.p,{children:["This secrets engine honors the distinction between the ",(0,t.jsx)(n.code,{children:"create"})," and ",(0,t.jsx)(n.code,{children:"update"}),"\ncapabilities inside ACL policies. The ",(0,t.jsx)(n.code,{children:"patch"})," capability is also supported\nwhich is used to represent partial updates whereas the ",(0,t.jsx)(n.code,{children:"update"})," capability\nrepresents full overwrites."]}),"\n",(0,t.jsx)(n.h2,{id:"setup",children:"Setup"}),"\n",(0,t.jsx)(n.p,{children:"Most secrets engines must be configured in advance before they can perform their\nfunctions. These steps are usually completed by an operator or configuration\nmanagement tool."}),"\n",(0,t.jsxs)(n.p,{children:["A v2 ",(0,t.jsx)(n.code,{children:"kv"})," secrets engine can be enabled by:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao secrets enable -version=2 kv\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Or, you can pass ",(0,t.jsx)(n.code,{children:"kv-v2"})," as the secrets engine type:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao secrets enable kv-v2\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Additionally, when running a dev-mode server, the v2 ",(0,t.jsx)(n.code,{children:"kv"})," secrets engine is enabled by default at the\npath ",(0,t.jsx)(n.code,{children:"secret/"})," (for non-dev servers, it is currently v1). It can be disabled, moved, or enabled multiple times at\ndifferent paths. Each instance of the KV secrets engine is isolated and unique."]}),"\n",(0,t.jsx)(n.h2,{id:"upgrading-from-version-1",children:"Upgrading from version 1"}),"\n",(0,t.jsx)(n.p,{children:"An existing version 1 kv store can be upgraded to a version 2 kv store via the CLI or API, as shown below. This will start an upgrade process to upgrade the existing key/value data to a versioned format. The mount will be inaccessible during this process. This process could take a long time, so plan accordingly."}),"\n",(0,t.jsxs)(n.p,{children:["Once upgraded to version 2, the former paths at which the data was accessible will no longer suffice. You will need to adjust user policies to add access to the version 2 paths as detailed in the ",(0,t.jsx)(n.a,{href:"/docs/next/secrets/kv/kv-v2#acl-rules",children:"ACL Rules section below"}),". Similarly, users/applications will need to update the paths at which they interact with the kv data once it has been upgraded to version 2."]}),"\n",(0,t.jsx)(n.p,{children:"An existing version 1 kv can be upgraded to a version 2 KV store with the CLI command:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv enable-versioning secret/\nSuccess! Tuned the secrets engine at: secret/\n"})}),"\n",(0,t.jsx)(n.p,{children:"or via the API:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:'$ cat payload.json\n{\n  "options": {\n      "version": "2"\n  }\n}\n'})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:'$ curl \\\n    --header "X-Vault-Token: ..." \\\n    --request POST \\\n    --data @payload.json \\\n    http://127.0.0.1:8200/v1/sys/mounts/secret/tune\n'})}),"\n",(0,t.jsx)(n.h2,{id:"acl-rules",children:"ACL rules"}),"\n",(0,t.jsx)(n.p,{children:"The version 2 kv store uses a prefixed API, which is different from the\nversion 1 API. Before upgrading from a version 1 kv the ACL rules\nshould be changed. Also different paths in the version 2 API can be ACL'ed\ndifferently."}),"\n",(0,t.jsxs)(n.p,{children:["Writing and reading versions are prefixed with the ",(0,t.jsx)(n.code,{children:"data/"})," path. This policy\nthat worked for the version 1 kv:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-plaintext",children:'path "secret/dev/team-1/*" {\n  capabilities = ["create", "update", "read"]\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"Should be changed to:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-plaintext",children:'path "secret/data/dev/team-1/*" {\n  capabilities = ["create", "update", "read"]\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"There are different levels of data deletion for this backend. To grant a policy\nthe permissions to delete the latest version of a key:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-plaintext",children:'path "secret/data/dev/team-1/*" {\n  capabilities = ["delete"]\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"To allow the policy to delete any version of a key:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-plaintext",children:'path "secret/delete/dev/team-1/*" {\n  capabilities = ["update"]\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"To allow a policy to undelete data:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-plaintext",children:'path "secret/undelete/dev/team-1/*" {\n  capabilities = ["update"]\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"To allow a policy to destroy versions:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-plaintext",children:'path "secret/destroy/dev/team-1/*" {\n  capabilities = ["update"]\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"To allow a policy to list keys:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-plaintext",children:'path "secret/metadata/dev/team-1/*" {\n  capabilities = ["list"]\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"To allow a policy to view metadata for each version:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-plaintext",children:'path "secret/metadata/dev/team-1/*" {\n  capabilities = ["read"]\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"To allow a policy to permanently remove all versions and metadata for a key:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-plaintext",children:'path "secret/metadata/dev/team-1/*" {\n  capabilities = ["delete"]\n}\n'})}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"allowed_parameters"}),", ",(0,t.jsx)(n.code,{children:"denied_parameters"}),", and ",(0,t.jsx)(n.code,{children:"required_parameters"})," fields are\nnot supported for policies used with the version 2 kv store. See the ",(0,t.jsx)(n.a,{href:"/docs/next/concepts/policies",children:"Policies Concepts"}),"\nfor a description of these parameters."]}),"\n",(0,t.jsxs)(n.p,{children:["See the ",(0,t.jsx)(n.a,{href:"/docs/next/api/secret/kv/kv-v2",children:"API Specification"})," for more\ninformation."]}),"\n",(0,t.jsx)(n.h2,{id:"usage",children:"Usage"}),"\n",(0,t.jsxs)(n.p,{children:["After the secrets engine is configured and a user/machine has an OpenBao token with\nthe proper permission, it can generate credentials. The ",(0,t.jsx)(n.code,{children:"kv"})," secrets engine\nallows for writing keys with arbitrary values."]}),"\n",(0,t.jsxs)(n.p,{children:["The path-like KV-v1 syntax for referencing a secret (",(0,t.jsx)(n.code,{children:"secret/foo"}),") can still\nbe used in KV-v2, but we recommend using the ",(0,t.jsx)(n.code,{children:"-mount=secret"})," flag syntax to\navoid mistaking it for the actual path to the secret (",(0,t.jsx)(n.code,{children:"secret/data/foo"})," is the\nreal path)."]}),"\n",(0,t.jsx)(n.h3,{id:"writingreading-arbitrary-data",children:"Writing/Reading arbitrary data"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Write arbitrary data:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv put -mount=secret my-secret foo=a bar=b\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:20:22.985303Z\ncustom_metadata  <nil>\ndeletion_time    n/a\ndestroyed        false\nversion          1\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Read arbitrary data:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv get -mount=secret my-secret\n====== Metadata ======\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:20:22.985303Z\ncustom_metadata  <nil>\ndeletion_time    n/a\ndestroyed        false\nversion          1\n\n====== Data ======\nKey         Value\n---         -----\nfoo         a\nbar         b\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:["Write another version, the previous version will still be accessible. The\n",(0,t.jsx)(n.code,{children:"-cas"})," flag can optionally be passed to perform a check-and-set operation. If\nnot set the write will be allowed. In order for a write to be successful, ",(0,t.jsx)(n.code,{children:"cas"})," must be set to\nthe current version of the secret. If set to 0 a write will only be allowed if\nthe key doesn\u2019t exist as unset keys do n
1ot have any version information. Also\nremember that soft deletes do not remove any underlying version data from storage.\nIn order to write to a soft deleted key, the cas parameter must match the key's\ncurrent version."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv put -mount=secret -cas=1 my-secret foo=aa bar=bb\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:22:23.369372Z\ncustom_metadata  <nil>\ndeletion_time    n/a\ndestroyed        false\nversion          2\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Reading now will return the newest version of the data:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv get -mount=secret my-secret\n====== Metadata ======\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:22:23.369372Z\ncustom_metadata  <nil>\ndeletion_time    n/a\ndestroyed        false\nversion          2\n\n====== Data ======\nKey         Value\n---         -----\nfoo         aa\nbar         bb\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:["Partial updates can be accomplished using the ",(0,t.jsx)(n.code,{children:"bao kv patch"})," command. A\ncommand will initially attempt an HTTP ",(0,t.jsx)(n.code,{children:"PATCH"})," request which requires the\n",(0,t.jsx)(n.code,{children:"patch"})," ACL capability. The ",(0,t.jsx)(n.code,{children:"PATCH"})," request will fail if the token used\nis associated with a policy that does not contain the ",(0,t.jsx)(n.code,{children:"patch"})," capability. In\nthis case the command will perform a read, local update, and subsequent write\nwhich require both the ",(0,t.jsx)(n.code,{children:"read"})," and ",(0,t.jsx)(n.code,{children:"update"})," ACL capabilities."]}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"-cas"})," flag can optionally be passed to perform a check-and-set operation.\nIt will only be used in the case of the initial ",(0,t.jsx)(n.code,{children:"PATCH"})," request. The\nread-then-write flow will use the ",(0,t.jsx)(n.code,{children:"version"})," value from the secret returned by\nthe read to perform a check-and-set operation in the subsequent write."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv patch -mount=secret -cas=2 my-secret bar=bbb\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:23:49.199802Z\ncustom_metadata  <nil>\ndeletion_time    n/a\ndestroyed        false\nversion          3\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"bao kv patch"})," command also supports a ",(0,t.jsx)(n.code,{children:"-method"})," flag which can be\nused to specify HTTP ",(0,t.jsx)(n.code,{children:"PATCH"})," or read-then-write. The supported values are\n",(0,t.jsx)(n.code,{children:"patch"})," and ",(0,t.jsx)(n.code,{children:"rw"})," for HTTP ",(0,t.jsx)(n.code,{children:"PATCH"})," and read-then-write, respectively."]}),"\n",(0,t.jsxs)(n.p,{children:["Perform a patch using the ",(0,t.jsx)(n.code,{children:"patch"})," method:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv patch -mount=secret -method=patch -cas=2 my-secret bar=bbb\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:23:49.199802Z\ncustom_metadata  <nil>\ndeletion_time    n/a\ndestroyed        false\nversion          3\n"})}),"\n",(0,t.jsx)(n.p,{children:"Perform a patch using the read-then-write method:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv patch -mount=secret -method=rw my-secret bar=bbb\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:23:49.199802Z\ncustom_metadata  <nil>\ndeletion_time    n/a\ndestroyed        false\nversion          3\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Reading after a patch will return the newest version of the data in which\nonly the specified fields were updated:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv get -mount=secret my-secret\n====== Metadata ======\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:23:49.199802Z\ncustom_metadata  <nil>\ndeletion_time    n/a\ndestroyed        false\nversion          3\n\n====== Data ======\nKey         Value\n---         -----\nfoo         aa\nbar         bbb\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:["Previous versions can be accessed with the ",(0,t.jsx)(n.code,{children:"-version"})," flag:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv get -mount=secret -version=1 my-secret\n====== Metadata ======\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:20:22.985303Z\ncustom_metadata  <nil>\ndeletion_time    n/a\ndestroyed        false\nversion          1\n\n====== Data ======\nKey         Value\n---         -----\nfoo         a\nbar         b\n"})}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["You can also use ",(0,t.jsx)(n.a,{href:"/docs/next/concepts/password-policies",children:"OpenBao's password policy"})," feature to generate arbitrary values."]}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Write a password policy:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:'$ bao write sys/policies/password/example policy=-<<EOF\n\n  length=20\n\n  rule "charset" {\n    charset = "abcdefghij0123456789"\n    min-chars = 1\n  }\n\n  rule "charset" {\n    charset = "!@#$%^&*STUVWXYZ"\n    min-chars = 1\n  }\n\nEOF\n'})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:["Write data using the ",(0,t.jsx)(n.code,{children:"example"})," policy:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv put -mount=secret my-generated-secret \\\n    password=$(bao read -field password sys/policies/password/example/generate)\n"})}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Example output:"})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-plaintext",children:"========= Secret Path =========\nsecret/data/my-generated-secret\n\n======= Metadata =======\nKey                Value\n---                -----\ncreated_time       2023-05-10T14:32:32.37354939Z\ncustom_metadata    <nil>\ndeletion_time      n/a\ndestroyed          false\nversion            1\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Read the generated data:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv get -mount=secret my-generated-secret\n========= Secret Path =========\nsecret/data/my-generated-secret\n\n======= Metadata =======\nKey                Value\n---                -----\ncreated_time       2023-05-10T14:32:32.37354939Z\ncustom_metadata    <nil>\ndeletion_time      n/a\ndestroyed          false\nversion            1\n\n====== Data ======\nKey         Value\n---         -----\npassword    !hh&be1e4j16dVc0ggae\n"})}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"deleting-and-destroying-data",children:"Deleting and destroying data"}),"\n",(0,t.jsxs)(n.p,{children:["When deleting data the standard ",(0,t.jsx)(n.code,{children:"bao kv delete"})," command will perform a\nsoft delete. It will mark the version as deleted and populate a ",(0,t.jsx)(n.code,{children:"deleti
1on_time"}),"\ntimestamp. Soft deletes do not remove the underlying version data from storage,\nwhich allows the version to be undeleted. The ",(0,t.jsx)(n.code,{children:"bao kv undelete"})," command\nhandles undeleting versions."]}),"\n",(0,t.jsxs)(n.p,{children:["A version's data is permanently deleted only when the key has more versions than\nare allowed by the max-versions setting, or when using ",(0,t.jsx)(n.code,{children:"bao kv destroy"}),". When\nthe destroy command is used the underlying version data will be removed and the\nkey metadata will be marked as destroyed. If a version is cleaned up by going\nover max-versions the version metadata will also be removed from the key."]}),"\n",(0,t.jsx)(n.p,{children:"See the commands below for more information:"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:["The latest version of a key can be deleted with the delete command, this also\ntakes a ",(0,t.jsx)(n.code,{children:"-versions"})," flag to delete prior versions:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv delete -mount=secret my-secret\nSuccess! Data deleted (if it existed) at: secret/data/my-secret\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Versions can be undeleted:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv undelete -mount=secret -versions=2 my-secret\nSuccess! Data written to: secret/undelete/my-secret\n\n$ bao kv get -mount=secret my-secret\n====== Metadata ======\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:23:21.834403Z\ncustom_metadata  <nil>\ndeletion_time    n/a\ndestroyed        false\nversion          2\n\n====== Data ======\nKey         Value\n---         -----\nmy-value    short-lived-s3cr3t\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Destroying a version permanently deletes the underlying data:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv destroy -mount=secret -versions=2 my-secret\nSuccess! Data written to: secret/destroy/my-secret\n"})}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"key-metadata",children:"Key metadata"}),"\n",(0,t.jsx)(n.p,{children:"All versions and key metadata can be tracked with the metadata command & API.\nDeleting the metadata key will cause all metadata and versions for that key to\nbe permanently removed."}),"\n",(0,t.jsx)(n.p,{children:"See the commands below for more information:"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"All metadata and versions for a key can be viewed:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv metadata get -mount=secret my-secret\n========== Metadata ==========\nKey                     Value\n---                     -----\ncas_required            false\ncreated_time            2019-06-19T17:20:22.985303Z\ncurrent_version         2\ncustom_metadata         <nil>\ndelete_version_after    0s\nmax_versions            0\noldest_version          0\nupdated_time            2019-06-19T17:22:23.369372Z\n\n====== Version 1 ======\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:20:22.985303Z\ndeletion_time    n/a\ndestroyed        false\n\n====== Version 2 ======\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:22:23.369372Z\ndeletion_time    n/a\ndestroyed        true\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"The metadata settings for a key can be configured:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:'$ bao kv metadata put -mount=secret -max-versions 2 -delete-version-after="3h25m19s" my-secret\nSuccess! Data written to: secret/metadata/my-secret\n'})}),"\n",(0,t.jsx)(n.p,{children:"Delete-version-after settings will apply only to new versions. Max versions\nchanges will be applied on 
1next write:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv put -mount=secret my-secret my-value=newer-s3cr3t\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:31:16.662563Z\ncustom_metadata  <nil>\ndeletion_time    2019-06-19T20:56:35.662563Z\ndestroyed        false\nversion          4\n"})}),"\n",(0,t.jsx)(n.p,{children:"Once a key has more versions than max versions the oldest versions\nare cleaned up:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv metadata get -mount=secret my-secret\n========== Metadata ==========\nKey                     Value\n---                     -----\ncas_required            false\ncreated_time            2019-06-19T17:20:22.985303Z\ncurrent_version         4\ncustom_metadata         <nil>\ndelete_version_after    3h25m19s\nmax_versions            2\noldest_version          3\nupdated_time            2019-06-19T17:31:16.662563Z\n\n====== Version 3 ======\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:23:21.834403Z\ndeletion_time    n/a\ndestroyed        true\n\n====== Version 4 ======\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:31:16.662563Z\ndeletion_time    2019-06-19T20:56:35.662563Z\ndestroyed        false\n"})}),"\n",(0,t.jsxs)(n.p,{children:["A secret's key metadata can contain custom metadata used to describe the secret.\nThe data will be stored as string-to-string key-value pairs.\nThe ",(0,t.jsx)(n.code,{children:"-custom-metadata"})," flag can be repeated to add multiple key-value pairs."]}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"bao kv metadata put"})," command can be used to fully overwrite the value of ",(0,t.jsx)(n.code,{children:"custom_metadata"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv metadata put -mount=secret -custom-metadata=foo=abc -custom-metadata=bar=123 my-secret\nSuccess! Data written to: secret/metadata/my-secret\n\n$ bao kv get -mount=secret my-secret\n====== Metadata ======\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:22:23.369372Z\ncustom_metadata  map[bar:123 foo:abc]\ndeletion_time    n/a\ndestroyed        false\nversion          2\n\n====== Data ======\nKey         Value\n---         -----\nfoo         aa\nbar         bb\n"})}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"bao kv metadata patch"})," command can be used to partially overwrite the value of ",(0,t.jsx)(n.code,{children:"custom_metadata"}),".\nThe following invocation will update ",(0,t.jsx)(n.code,{children:"custom_metadata"})," sub-field ",(0,t.jsx)(n.code,{children:"foo"})," but leave ",(0,t.jsx)(n.code,{children:"bar"})," untouched:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv metadata patch -mount=secret -custom-metadata=foo=def my-secret\nSuccess! Data written to: secret/metadata/my-secret\n"})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv get -mount=secret my-secret\n====== Metadata ======\nKey              Value\n---              -----\ncreated_time     2019-06-19T17:22:23.369372Z\ncustom_metadata  map[bar:123 foo:def]\ndeletion_time    n/a\ndestroyed        false\nversion          2\n\n====== Data ======\nKey         Value\n---         -----\nfoo         aa\nbar         bb\n"})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsx)(n.p,{children:"Permanently delete all metadata and versions for a key:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell-session",children:"$ bao kv metadata delete -mount=secret my-secret\nSuccess! Data deleted (if it existed) at: secret/metadata/my-secret\n"})}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"api",children:"API"}),"\n",(0,t.jsxs)(n.p,{children:["The KV secrets engine has a full HTTP API. Please see the\n",(0,t.jsx)(n.a,{href:"/docs/next/api/secret/kv/kv-v2",children:"KV secrets engine API"})," for more\ndetails."]})]})}function h(e={}){let{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(c,{...e})}):c(e)}},44812(e,n,s){s.d(n,{R:()=>i,x:()=>l});var a=s(92990);let t={},r=a.createContext(t);function i(e){let n=a.useContext(r);return a.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:i(e.components),a.createElement(r.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.