Skip to content

Commit

Permalink
Add support for custom metadata in kv2 engine (#805)
Browse files Browse the repository at this point in the history
* Add support for custom metadata in kv2 engine

Vault 1.9 added support to custom metadata, "a map of arbitrary string
to string valued user-provided metadata meant to describe the secret.".

This is already supported by the read_secret_metadata method as part
of the Vault server response. This change adds support to update it,
as a new parameter `custom_metadata` for the update_metadata method.

Reference: https://www.vaultproject.io/api-docs/secret/kv/kv-v2

Fixes #804

* update docs example

* only run against supported Vault versions

* reorder param, add Vault version detail.

---------

Co-authored-by: Brian Scholer <1260690+briantist@users.noreply.github.com>
  • Loading branch information
dereckson and briantist committed Feb 19, 2023
1 parent d7e9557 commit 1b0b8fe
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 0 deletions.
15 changes: 15 additions & 0 deletions docs/usage/secrets_engines/kv_v2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,21 @@ Set "delete_version_after" value to 30 minutes for all new versions written to t
delete_version_after="30m",
)
Describe the secret with custom metadata values in ``custom_metadata`` (Vault >= 1.9.0):

.. code:: python
import hvac
client = hvac.Client()
clients.secrets.kv.v2.update_metadata(
path='hvac',
custom_metadata={
"type": "api-token",
"color": "blue",
},
)
Delete Metadata and All Versions
--------------------------------
Expand Down
12 changes: 12 additions & 0 deletions hvac/api/secrets_engines/kv_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ def update_metadata(
cas_required=None,
delete_version_after="0s",
mount_point=DEFAULT_MOUNT_POINT,
custom_metadata=None,
):
"""Updates the max_versions of cas_required setting on an existing path.
Expand All @@ -380,6 +381,8 @@ def update_metadata(
:type delete_version_after: str
:param mount_point: The "path" the secret engine was mounted on.
:type mount_point: str | unicode
:param custom_metadata: A dictionary of key/value metadata to describe the secret. Requires Vault 1.9.0 or greater.
:type custom_metadata: dict
:return: The response of the request.
:rtype: requests.Response
"""
Expand All @@ -397,6 +400,15 @@ def update_metadata(
)
raise exceptions.ParamValidationError(error_msg)
params["cas_required"] = cas_required
if custom_metadata is not None:
if not isinstance(custom_metadata, dict):
error_msg = (
"dict expected for custom_metadata param, {type} received".format(
type=type(custom_metadata)
)
)
raise exceptions.ParamValidationError(error_msg)
params["custom_metadata"] = custom_metadata
api_path = utils.format_url(
"/v1/{mount_point}/metadata/{path}", mount_point=mount_point, path=path
)
Expand Down
20 changes: 20 additions & 0 deletions tests/integration_tests/api/secrets_engines/test_kv_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -778,10 +778,23 @@ def test_list_secrets(
None,
"cats",
"0s",
None,
True,
exceptions.ParamValidationError,
"bool expected for cas_required param",
),
("update custom_medata", "hvac", None, None, "0s", dict(color="blue")),
(
"update with invalid custom_metadata param",
"hvac",
None,
None,
"0s",
"not-a-dict",
True,
exceptions.ParamValidationError,
"dict expected for custom_metadata param",
),
("update with delete_version_after set", "hvac", None, True, "30s"),
]
)
Expand All @@ -792,10 +805,14 @@ def test_update_metadata(
max_versions=None,
cas_required=None,
delete_version_after="0s",
custom_metadata=None,
write_secret_before_test=True,
raises=None,
exception_message="",
):
if test_label == "update custom_medata" and utils.vault_version_lt("1.9.0"):
self.skipTest("custom_metadata support added in Vault 1.9.0")

if write_secret_before_test:
test_secret = {
"pssst": "hi itsame hvac",
Expand All @@ -809,6 +826,7 @@ def test_update_metadata(
path=path,
max_versions=max_versions,
cas_required=cas_required,
custom_metadata=custom_metadata,
delete_version_after=delete_version_after,
mount_point=self.DEFAULT_MOUNT_POINT,
)
Expand All @@ -821,6 +839,7 @@ def test_update_metadata(
path=path,
max_versions=max_versions,
cas_required=cas_required,
custom_metadata=custom_metadata,
delete_version_after=delete_version_after,
mount_point=self.DEFAULT_MOUNT_POINT,
)
Expand All @@ -837,6 +856,7 @@ def test_update_metadata(
for key, argument in dict(
max_versions=max_versions,
cas_required=cas_required,
custom_metadata=custom_metadata,
delete_version_after=delete_version_after,
).items():
if argument is not None:
Expand Down

0 comments on commit 1b0b8fe

Please sign in to comment.