File: //opt/saltstack/salt/lib/python3.10/site-packages/salt/sdb/vault.py
"""
Vault SDB Module
:maintainer: SaltStack
:maturity: New
:platform: all
.. versionadded:: 2016.11.0
This module allows access to Hashicorp Vault using an ``sdb://`` URI.
Base configuration instructions are documented in the :ref:`execution module docs <vault-setup>`.
Below are noted extra configuration required for the sdb module, but the base
configuration must also be completed.
Like all sdb modules, the vault module requires a configuration profile to
be configured in either the minion configuration file or a pillar. This profile
requires only setting the ``driver`` parameter to ``vault``:
.. code-block:: yaml
myvault:
driver: vault
Once configured you can access data using a URL such as:
.. code-block:: yaml
password: sdb://myvault/secret/passwords/mypassword
In this URL, ``myvault`` refers to the configuration profile,
``secret/passwords`` is the path where the data resides, and ``mypassword`` is
the key of the data to return.
The above URI is analogous to running the following vault command:
.. code-block:: bash
$ vault read -field=mypassword secret/passwords
Further configuration
---------------------
The following options can be set in the profile:
patch
When writing data, partially update the secret instead of overwriting it completely.
This is usually the expected behavior, since without this option,
each secret path can only contain a single mapping key safely.
Defaults to ``False`` for backwards-compatibility reasons.
.. versionadded:: 3007.0
"""
import logging
import salt.exceptions
import salt.utils.vault as vault
log = logging.getLogger(__name__)
__func_alias__ = {"set_": "set"}
def set_(key, value, profile=None):
"""
Set a key/value pair in the vault service
"""
if "?" in key:
path, key = key.split("?")
else:
path, key = key.rsplit("/", 1)
data = {key: value}
curr_data = {}
profile = profile or {}
if profile.get("patch"):
try:
# Patching only works on existing secrets.
# Save the current data if patching is enabled
# to write it back later, if any errors happen in patch_kv.
# This also checks that the path exists, otherwise patching fails as well.
curr_data = vault.read_kv(path, __opts__, __context__)
vault.patch_kv(path, data, __opts__, __context__)
return True
except (vault.VaultNotFoundError, vault.VaultPermissionDeniedError):
pass
curr_data.update(data)
try:
vault.write_kv(path, data, __opts__, __context__)
return True
except Exception as err: # pylint: disable=broad-except
log.error("Failed to write secret! %s: %s", type(err).__name__, err)
raise salt.exceptions.CommandExecutionError(err) from err
def get(key, profile=None):
"""
Get a value from the vault service
"""
full_path = key
if "?" in key:
path, key = key.split("?")
else:
path, key = key.rsplit("/", 1)
try:
try:
res = vault.read_kv(path, __opts__, __context__)
if key in res:
return res[key]
return None
except vault.VaultNotFoundError:
return vault.read_kv(full_path, __opts__, __context__)
except vault.VaultNotFoundError:
return None
except Exception as err: # pylint: disable=broad-except
log.error("Failed to read secret! %s: %s", type(err).__name__, err)
raise salt.exceptions.CommandExecutionError(err) from err