class VaultService extends Object
Provides easy access to HashiCorp Vault Key-Value secrets engine. Both KV v1 and KV v2 secrets engines are supported.
There are two ways to set up instantiation of this class. Manually specifying key-value mounts or auto-discovering mounts. In general, auto-discovery is more reliable and recommended. Manually specifying mounts is available to reduce API usage.
import net.gleske.jervis.remotes.interfaces.TokenCredential
import net.gleske.jervis.remotes.VaultService
VaultService vault = new VaultService('http://active.vault.service.consul:8200/', creds)
// auto-discover mounts
vault.discoverKVMounts()
import net.gleske.jervis.remotes.interfaces.TokenCredential
import net.gleske.jervis.remotes.VaultService
VaultService vault = new VaultService('http://active.vault.service.consul:8200/', creds)
// Specify mounts
vault.mountVersions = [kv: '2', secret: '1']
// Optional: KV v2 might require Check-and-Set to be enabled.
vault.cas_required = ['kv']
Ideally, your policy for an application would be limited only to what that application needs. This section provides some guidance for Vault policy.
If you decide to use discoverMounts() method, then you'll need the following policy addition. However, this is insecure and could leak other secrets engine mounts.
# Read all mounts to find KV stores
path "sys/mounts" {
capabilities = ["read"]
}
# Read mount config for Check-and-Set configuration.
path "+/config" {
capabilities = ["read"]
}
Instead of the above policy, it is recommended you instantiate your code with static values. The following will not generate any API calls to vault and so do not need a policy.
// Set secrets engines KV v1 and KV v2 mounts
vault.mountVersions = [kv: 2, secret: 1, kv_cas: 2]
// Only mount kv_cas requires Check-and-Set
vault.cas_required = ['kv_cas']
On a KV secrets store, you'll want to limit access for an application to read-only most likely. Here's an example policy which would look the same whether a KV v1 or KV v2 secrets engine. The following policy will allow your application to walk the full secrets store. You can further restrict the policy to certain paths inside of the secret store.
path "kv/*" {
capabilities = ["read", "list"]
}
Be aware that list capability enables recursive searching through the secrets store or path. Ideally, your application will only be looking for secrets in a specific path so there should be no need to grant list capability.
To run examples, clone Jervis and execute ./gradlew console to bring up a Groovy Console with the classpath set up. Additionally, you'll need to clone and setup a local Vault cluster. After you instantiate the local Vault cluster you'll need to run the following Shell commands relative to the root of the repository at ~/git/github/docker-compose-ha-consul-vault-ui.
# Enable secrets engines KV v1 and KV v2
./scripts/curl-api.sh --request POST --data '{"type": "kv", "options": {"version": "1"}}' http://active.vault.service.consul:8200/v1/sys/mounts/secret
./scripts/curl-api.sh --request POST --data '{"type": "kv", "options": {"version": "2"}}' http://active.vault.service.consul:8200/v1/sys/mounts/kv
# Generate an admin token for initial setup
./scripts/get-admin-token.sh
Afterwards, run the following Groovy Console script to populate the local Vault cluster with dummy secret data.
System.setProperty("socksProxyHost", "localhost")
System.setProperty("socksProxyPort", "1080")
import net.gleske.jervis.remotes.interfaces.TokenCredential
import net.gleske.jervis.remotes.VaultService
// generate token by executing ./scripts/get-admin-token.sh in
// docker-compose-ha-consul-vault-ui repo
TokenCredential creds = [getToken: {-> 'admin token' }] as TokenCredential
VaultService vault = new VaultService('http://active.vault.service.consul:8200/', creds)
// populate secret mounts with dummy data
vault.setSecret("kv/foo", ['hello':'world'])
vault.setSecret("kv/foo", ['another':'secret', 'hello':'world'])
vault.setSecret("kv/foo/bar", ['hello':'friend'])
vault.setSecret("kv/foo/bar/baz", ['foo':'bar'])
vault.setSecret("secret/foo", ['test':'data'])
vault.setSecret("secret/foo/bar", ['someother':'data'])
vault.setSecret("secret/foo/bar/baz", ['more':'secrets'])
println 'Success.'
Please note: If you're practicing against the local Vault cluster, then your Groovy Console requires the following lines of code at the top of the Groovy script. It uses the SOCKS proxy provided by the test cluster.
System.setProperty("socksProxyHost", "localhost")
System.setProperty("socksProxyPort", "1080")
The recommended way to authenticate with Vault is to use AppRole authentication. Token-based authentication is possible but not recommended. This section will discuss both AppRole and Token-based authentication.
Refer to VaultRoleIdCredential for production-use examples of securely managing the Role ID and Secret ID. This example is for simple demonstration purposes of this class.
import net.gleske.jervis.remotes.creds.VaultAppRoleCredential
import net.gleske.jervis.remotes.VaultService
VaultAppRoleCredential creds = new VaultAppRoleCredential('http://active.vault.service.consul:8200/', 'my-app-role', 'my-secret-id')
VaultService vault = new VaultService(creds)
// read a secret
vault.getSecret('path/to/secret')
Authenticating with Vault using a Token is pretty basic. There's no built-in support in this library because in general there's no need for it. Instead, the recommended method for authentication is AppRole. However, if you must use a Vault Token, then this example describes a basic method. This example uses a basic static token and will not automatically renew the token like AppRole support.
import net.gleske.jervis.remotes.interfaces.TokenCredential
import net.gleske.jervis.remotes.VaultService
// 's.fuFc...' is a vault token in this example
TokenCredential creds = [getToken: {-> 's.fuFc...' }] as TokenCredential
VaultService vault = new VaultService('http://active.vault.service.consul:8200/', creds)
// get a secret using the basic Vault Token
vault.getSecret('path/to/secret')
Type | Name and description |
---|---|
List |
cas_required A list of KV v2 mounts which enforce cas_required for all write operations. |
Map<String, String> |
headers Customizable HTTP headers which get sent to Vault in addition to authentication headers. |
Map<String, String> |
mountVersions This property tracks whether a mount is KV v1 or KV v2 secrets engine. |
Constructor and description |
---|
VaultService
(String vault_url, TokenCredential credential) Authenticate with a Vault instance using a basic token credential. |
VaultService
(VaultCredential credential) Authenticate with Vault using AppRole authentication via VaultAppRoleCredential. |
Type Params | Return Type | Name and description |
---|---|---|
|
String |
baseUrl() Resolves the API base URL to be used by SimpleRestService.apiFetch. |
|
void |
copyAllKeys(Map srcLocation, Map destLocation, Integer level = 0) Recursively copies all secrets from the source location, srcLocation, to the destination location, destLocation. |
|
void |
copyAllKeys(String srcPath, String destPath, Integer level = 0) Recursively copies all secrets from the source location, srcPaht, to the destination location, destPath. |
|
void |
copySecret(String srcKey, String destKey, Integer srcVersion = 0) Copies the contents of secret from a source key to the destination key. |
|
void |
copySecret(Map srcLocation, Map destLocation, Integer srcVersion = 0) Copies the contents of secret from a source key to the destination key using location maps. |
|
void |
deletePath(Map location, Integer level, Boolean destroyAllVersions = false) Recursively deletes a path of keys including all child keys from a KV v1 or KV v2 secrets engine. |
|
void |
deletePath(Map location, Boolean destroyAllVersions = false) Recursively deletes a path of keys including all child keys from a KV v1 or KV v2 secrets engine. |
|
void |
deletePath(String path, Boolean destroyAllVersions = false) Recursively deletes a path of keys including all child keys from a KV v1 or KV v2 secrets engine. |
|
void |
deletePath(String path, Integer level, Boolean destroyAllVersions = false) Recursively deletes a path of keys including all child keys from a KV v1 or KV v2 secrets engine. |
|
void |
deleteSecret(Map location, List<Integer> deleteVersions, Boolean destroyAllVersions = false) Deletes data from a KV v1 or KV v2 secrets engine. |
|
void |
deleteSecret(Map location, Boolean destroyAllVersions = false) Deletes data from a KV v1 or KV v2 secrets engine. |
|
void |
deleteSecret(String path, List<Integer> destroyVersions, Boolean destroyAllVersions = false) Deletes data from a KV v1 or KV v2 secrets engine. |
|
void |
deleteSecret(String path, Boolean destroyAllVersions = false) Deletes data from a KV v1 or KV v2 secrets engine. |
|
void |
discoverKVMounts() Query Vault to find all of the KV mounts. |
|
List<String> |
findAllKeys(Map location, Integer level = 0) Recursively traverses the path for subkeys. |
|
List<String> |
findAllKeys(String path, Integer level = 0) Recursively traverses the path for subkeys. |
|
Map<String, String> |
getEnvironmentSecret(Map location, Integer version = 0, Boolean allowInvalidKeys = false) Returns a Map of key-value pairs compatible with bash environment variables. |
|
Map<String, String> |
getEnvironmentSecret(String path, Integer version = 0, Boolean allowInvalidKeys = false) Returns a Map of key-value pairs compatible with bash environment variables. |
|
Map<String, String> |
getEnvironmentSecrets(List paths, Boolean allowInvalidKeys = false) Returns a Map of key-value pairs compatible with bash environment variables. |
|
String |
getLocationFromPath(String path) Given a path representing the full path including a mount and secret path, only the location relative to the parent mount is returned. |
|
Map |
getLocationMapFromPath(String path) If given a full path to a secret in Vault, a location Map is returned. |
|
String |
getMountFromPath(String path) Given a path this method will return the Vault secrets mount. |
|
String |
getPathFromLocationMap(Map location) If given a location Map it will convert it to a String path for Vault APIs. |
|
Map |
getSecret(Map location, Integer version = 0) Get secret from a KV v1 or KV v2 secret engine. |
|
Map |
getSecret(String path, Integer version = 0) Get secret from a KV v1 or KV v2 secret engine. |
|
Map |
header(Map headers = [:]) Resolves authentication headers to be used by SimpleRestService.apiFetch. |
|
Boolean |
isDeletedSecret(Map location, Integer version = 0) Check if a secret is deleted by attempting to retrieve it or check its status. |
|
Boolean |
isDeletedSecret(String path, Integer version = 0) Check if a secret is deleted by attempting to retrieve it or check its status. |
|
List |
listPath(Map location) List a path in Vault to find KV secret entries. |
|
List |
listPath(String path) List a path in Vault to find KV secret entries. |
|
void |
setMountVersions(String mount, def version) Forces a specified secrets engine mount to be KV v1 or KV v2. |
|
void |
setMountVersions(Map mountVersions) Forces a specified secrets engine mount to be KV v1 or KV v2. |
|
void |
setSecret(Map location, Map secret, Boolean enableCas = false) Set a secret in a KV v1 or KV v2 secret engine. |
|
void |
setSecret(String path, Map secret, Boolean enableCas = false) Writes a secret to Vault KV v1 or KV v2 secrets engine. |
A list of KV v2 mounts which enforce cas_required for all write operations.
Customizable HTTP headers which get sent to Vault in addition to authentication headers.
This property tracks whether a mount is KV v1 or KV v2 secrets engine. This only gets discovered once by API and does not change during the lifetime of the object. If a version is not manually set, then the mount version is detected by calling /sys/mounts/:path/tune API where :path is the name of the mount used for the KV secrets engine.
If you choose not to manually set the mount version, then you'll need the following Vault policy ACL.
# Read mount config to detect KV secrets engine version
path "sys/mounts/+/tune" {
capabilities = ["read"]
}
Recommendation: manually setting the mount version avoids making an API call to read the mount configuration. If the application using this library creates several instances of VaultService, then manually setting the KV engine version will significantly save on API calls to Vault.
The default mount points for KV secrets engines are the following.
import net.gleske.jervis.remotes.VaultService
import net.gleske.jervis.remotes.creds.VaultAppRoleCredential
VaultAppRoleCredential cred = new VaultAppRoleCredential('http://active.vault.service.consul:8200/', 'app-id', 'secret-id')
VaultService vault = new VaultService(cred)
// add a single entry to mountVersions for secret being KV v1
vault.setMountVersions('secret', '1')
vault.setMountVersions('kv', '2')
// alternately
Map versions = [secret: '1', kv: '2']
vault.setMountVersions(versions)
vault.mountVersions = versions
Authenticate with a Vault instance using a basic token credential. This constructor is provided for simplicity and testing. However, AppRole authentication is recommended, instead.
import net.gleske.jervis.remotes.interfaces.TokenCredential
import net.gleske.jervis.remotes.VaultService
TokenCredential creds = [getToken: {-> 'some vault token' }] as TokenCredential
VaultService vault = new VaultService('http://vault:8200/', creds)
// ready to perform vault operations
vault.discoverKVMounts()
vault.mountVersions
Authenticate with Vault using AppRole authentication via VaultAppRoleCredential. Any valid VaultCredential could be provided.
Resolves the API base URL to be used by SimpleRestService.apiFetch. SimpleRestService.apiFetch is used internally for VaultService communication.
Recursively copies all secrets from the source location, srcLocation, to the destination location, destLocation.
srcLocation
- A location map contains two keys: mount and path. The
mount is a KV mount in Vault and the path is a location
of a secret relative to the given mount.destLocation
- A location map contains two keys: mount and path. The
mount is a KV mount in Vault and the path is a
location of a secret relative to the given mount.level
- When traversing secrets paths level limits how deep
the path goes when returning results.Recursively copies all secrets from the source location, srcPaht, to the destination location, destPath.
srcPath
- A path to a secret in Vault. The path includes the KV v1
or KV v2 secret engine mount path.destPath
- A path to a secret in Vault. The path includes the KV v1
or KV v2 secret engine mount path.level
- When traversing secrets paths level limits how deep
the path goes when returning results.Copies the contents of secret from a source key to the destination key. Optional argument srcVersion allows you to select a specific version from a Key-Value v2 engine (default is get latest version of secret).
srcKey
- The source key to copy from.destKey
- The destination key to copy to.srcVersion
- The version to select in the source key if the
srcKey is a KV v2 secrets engine. By default
it will get the latest version. This option is ignored
if srcKey is a KV v1 secrets engine.Copies the contents of secret from a source key to the destination key using location maps. Optional argument srcVersion allows you to select a specific version from a Key-Value v2 engine (default is get latest version of secret).
srcLocation
- The source to copy from. A location map contains two
keys: mount and path. The mount is a KV mount in Vault
and the path is a location of a secret relative to the
given mount.destLocation
- The destination key to copy to. See
srcLocation for definition of a location.srcVersion
- The version to select in the source key if the
srcLocation is a KV v2 secrets engine. By
default it will get the latest version. This option is
ignored if srcLocation is a KV v1 secrets
engine.Recursively deletes a path of keys including all child keys from a KV v1 or KV v2 secrets engine. The trailing slash on location.path behaves similarly to findAllKeys(java.util.Map, java.lang.Integer).
location
- A location map contains two keys: mount and path. The
mount is a KV mount in Vault and the path is a location of
a secret relative to the given mount.level
- When traversing secrets paths level limits how deep
the path goes when returning results.destroyAllVersions
- Permanently deletes the key metadata and all
version data for the specified key.
When enabled, destroyVersions is
ignored. This option is ignored for KV v1
secrets engine.Recursively deletes a path of keys including all child keys from a KV v1 or KV v2 secrets engine. The trailing slash on location.path behaves similarly to findAllKeys(java.util.Map, java.lang.Integer).
location
- A location map contains two keys: mount and path. The
mount is a KV mount in Vault and the path is a location of
a secret relative to the given mount.destroyAllVersions
- Permanently deletes the key metadata and all
version data for the specified key.
When enabled, destroyVersions is
ignored. This option is ignored for KV v1
secrets engine.Recursively deletes a path of keys including all child keys from a KV v1 or KV v2 secrets engine. The trailing slash on path behaves similarly to findAllKeys(java.util.Map, java.lang.Integer).
path
- A path to a secret in Vault. The path includes the KV v1 or
KV v2 secret engine mount path.destroyAllVersions
- Permanently deletes the key metadata and all
version data for the specified key.
When enabled, destroyVersions is
ignored. This option is ignored for KV v1
secrets engine.Recursively deletes a path of keys including all child keys from a KV v1 or KV v2 secrets engine. The trailing slash on path behaves similarly to findAllKeys(java.util.Map, java.lang.Integer).
path
- A path to a secret in Vault. The path includes the KV v1 or
KV v2 secret engine mount path.level
- When traversing secrets paths level limits how deep
the path goes when returning results.destroyAllVersions
- Permanently deletes the key metadata and all
version data for the specified key.
When enabled, destroyVersions is
ignored. This option is ignored for KV v1
secrets engine.Deletes data from a KV v1 or KV v2 secrets engine.
location
- A location map contains two keys: mount and path. The
mount is a KV mount in Vault and the path is a location of
a secret relative to the given mount.destroyVersions
- When a key has multiple versions you might want to
only delete a specific version. Pass in a list of
version numbers and only those versions of the
secret will be deleted or destroyed.destroyAllVersions
- Permanently deletes a secret. If no
destroyVersions are given, then all
secret metadata and versions will be permanently
deleted. If specific destroyVersions
are given, then those specific versions are
permanently destroyed so they can't be
un-deleted. This option is ignored for KV v1
secrets engine.Deletes data from a KV v1 or KV v2 secrets engine.
location
- A location map contains two keys: mount and path. The
mount is a KV mount in Vault and the path is a location of
a secret relative to the given mount.destroyAllVersions
- Permanently deletes a secret. If no
destroyVersions are given, then all
secret metadata and versions will be permanently
deleted. If specific destroyVersions
are given, then those specific versions are
permanently destroyed so they can't be
un-deleted. This option is ignored for KV v1
secrets engine.Deletes data from a KV v1 or KV v2 secrets engine.
path
- A path to a secret in Vault. The path includes the KV v1 or
KV v2 secret engine mount path.destroyVersions
- When a key has multiple versions you might want to
only delete a specific version. Pass in a list of
version numbers and only those versions of the
secret will be deleted or destroyed.destroyAllVersions
- Permanently deletes a secret. If no
destroyVersions are given, then all
secret metadata and versions will be permanently
deleted. If specific destroyVersions
are given, then those specific versions are
permanently destroyed so they can't be
un-deleted. This option is ignored for KV v1
secrets engine.Deletes data from a KV v1 or KV v2 secrets engine.
path
- A path to a secret in Vault. The path includes the KV v1 or
KV v2 secret engine mount path.destroyAllVersions
- Permanently deletes a secret. If no
destroyVersions are given, then all
secret metadata and versions will be permanently
deleted. If specific destroyVersions
are given, then those specific versions are
permanently destroyed so they can't be
un-deleted. This option is ignored for KV v1
secrets engine.Query Vault to find all of the KV mounts. This can be called immediately following the constructor to initiate service connectivity. For KV v2 mounts, this will check the mount config to see if Check and Set is required. If you want to skip this check, then set cas_required List with all KV v2 mounts.
VaultService vault = new VaultService(...)
// Avoid cas check by setting cas_required before discovering mount version.
vault.cas_required = ['kv']
vault.discoverKVMounts()
Recursively traverses the path for subkeys. If level is 0 then there's no depth limit. When level = n, keys are traversed up to the limit.
A trailing slash / is optional and will have different behavior depending on the existence of keys in Vault. For example, let's say Vault has the following key layout. kv is a KV v2 and secret is a KV v1 secrets engine.
kv/
|- foo
|- foo/
|- bar
|- bar/
|- baz
|- hello/
|- world
|- friend
secret/
|- foo
|- foo/
|- bar
findAllKeys operates on both KV v1 and KV v2 secrets engines the same way.
Given level parameter and the layout of the kv KV v2 secrets store from earlier. You can expect the following behavior when passing different integers of level.
Recursively traverses the path for subkeys. If level is 0 then there's no depth limit. When level = n, keys are traversed up to the limit.
To learn more see findAllKeys(java.util.Map, java.lang.Integer).
location
- A location map contains two keys: mount and path. The
mount is a KV mount in Vault and the path is a location of
a secret relative to the given mount.level
- When traversing secrets paths level limits how deep
the path goes when returning results.Returns a Map of key-value pairs compatible with bash environment variables. The key and value returned in the Map will always be type String.
location
- A location map contains two keys: mount and path. The
mount is a KV mount in Vault and the path is a location of
a secret relative to the given mount.version
- Request a specific version of a secret. If 0,
then the latest version is returned. This option is
ignored for KV v1 secrets engine.allowInvalidKeys
- Allow key names which are valid String keys but
invalid bash environment variables.Returns a Map of key-value pairs compatible with bash environment variables. The key and value returned in the Map will always be type String.
path
- A path to a secret in Vault. The path includes the KV v1 or
KV v2 secret engine mount path.version
- Request a specific version of a secret. If 0,
then the latest version is returned. This option is
ignored for KV v1 secrets engine.allowInvalidKeys
- Includes keys which have invalid bash variable
names. This might be useful for additional logic
processing.Returns a Map of key-value pairs compatible with bash environment variables. Given a list of paths, they'll be combined with the end of the list taking precedence over the beginning of the list. When combining the Maps, the last Key-Value pair wins when key names conflict.
paths
- A List of paths to search Vault for Maps. Maps are
eventually combined. A path can be a String or a location
Map. A location Map includes a mount and path key e.g.
[mount: 'kv', path: 'my/secret/path'].allowInvalidKeys
- Includes keys which have invalid bash variable
names. This might be useful for additional logic
processing.Given a path representing the full path including a mount and secret path, only the location relative to the parent mount is returned.
path
- A path to a secret in Vault. The path includes the KV v1 or
KV v2 secret engine mount path.If given a full path to a secret in Vault, a location Map is returned.
path
- A String representing a valid path to a Vault secret including
its secret engine mount.Given a path this method will return the Vault secrets mount.
path
- A path to a secret in Vault. The path includes the KV v1 or
KV v2 secret engine mount path.If given a location Map it will convert it to a String path for Vault APIs.
location
- A map with two keys: mount and path. The mount is a KV
mount in Vault and the path is a location of a secret
relative to the given mount.Get secret from a KV v1 or KV v2 secret engine.
location
- A location map contains two keys: mount and path. The
mount is a KV mount in Vault and the path is a location of
a secret relative to the given mount.version
- Request a specific version of a secret. If 0,
then the latest version is returned. This option is
ignored for KV v1 secrets engine.Get secret from a KV v1 or KV v2 secret engine.
path
- A path to a secret JSON object to read from Vault.version
- Request a specific version of a secret. If 0,
then the latest version is returned. This option is
ignored for KV v1 secrets engine.Resolves authentication headers to be used by SimpleRestService.apiFetch. SimpleRestService.apiFetch is used internally for VaultService communication.
Check if a secret is deleted by attempting to retrieve it or check its status. A secret could be in one of three states: non-existent, deleted (recoverable), and destroyed (exists but not recoverable).
location
- A location map contains two keys: mount and path. The
mount is a KV mount in Vault and the path is a location of
a secret relative to the given mount.version
- Request a specific version of a secret. If 0,
then the latest version is returned. This option is
ignored for KV v1 secrets engine.Check if a secret is deleted by attempting to retrieve it or check its status. A secret could be in one of three states: non-existent, deleted (recoverable), and destroyed (exists but not recoverable).
path
- A path to a secret in Vault. The path includes the KV v1 or
KV v2 secret engine mount path.version
- Request a specific version of a secret. If 0,
then the latest version is returned. This option is
ignored for KV v1 secrets engine.List a path in Vault to find KV secret entries.
location
- A map with two keys: mount and path. The mount is a KV
mount in Vault and the path is a location of a secret
relative to the given mount.List a path in Vault to find KV secret entries.
path
- A path in Vault including the KV store mount.Forces a specified secrets engine mount to be KV v1 or KV v2. See mountVersions for additional usage.
mount
- A Vault secrets engine mount.version
- Must be "1" or "2" to denote KV v1 or KV
v2 secrets engine. Any type is allowed to catch invalid
version setting.Forces a specified secrets engine mount to be KV v1 or KV v2. See mountVersions for additional usage.
mountVersions
- A Key-Value map containing multiple Vault mounts and
respective version numbers.Set a secret in a KV v1 or KV v2 secret engine.
location
- A location map contains two keys: mount and path. The
mount is a KV mount in Vault and the path is a location of
a secret relative to the given mount.secret
- A secret to set at the given location in a Vault secret
store.enableCas
- Enable
Check and set.
This prevents unintentional overwriting of secrets. This
creates two requests: get current version of secret to be
written, write secret with version set. If the secret
being set has been altered, then it will have a different
version and Vault will reject the request..Writes a secret to Vault KV v1 or KV v2 secrets engine. This method will gracefully handle either KV v1 or KV v2. It is recommend to set enableCas=true when writing to Vault, because it will only write if the destination path is in an expected state.
path
- The destination to write the secret.secret
- A Map converted to a JSON Object written to the Vault
path.enableCas
- Enable
Check and set.
This prevents unintentional overwriting of secrets. This
creates two requests: get current version of secret to be
written, write secret with version set. If the secret
being set has been altered, then it will have a different
version and Vault will reject the request..Jervis API documentation.