diff --git a/changelog/61857.added b/changelog/61857.added new file mode 100644 index 00000000000..d9400702845 --- /dev/null +++ b/changelog/61857.added @@ -0,0 +1 @@ +Added new optional vault option, ``config_location``. This can be either ``master`` or ``local`` and defines where vault will look for connection details, either requesting them from the master or using the local config. diff --git a/salt/modules/vault.py b/salt/modules/vault.py index 3e7168b0f87..3f0064bd787 100644 --- a/salt/modules/vault.py +++ b/salt/modules/vault.py @@ -163,6 +163,14 @@ Functions to interact with Hashicorp Vault. keys List of keys to use to unseal vault server with the vault.unseal runner. + config_location + Where to get the connection details for calling vault. By default, + vault will try to determine if it needs to request the connection + details from the master or from the local config. This optional option + will force vault to use the connection details from the master or the + local config. Can only be either ``master`` or ``local``. + + .. versionadded:: 3006 Add this segment to the master configuration file, or /etc/salt/master.d/peer_run.conf: diff --git a/salt/utils/vault.py b/salt/utils/vault.py index 7aaabd8f249..b480b5e3b15 100644 --- a/salt/utils/vault.py +++ b/salt/utils/vault.py @@ -172,6 +172,16 @@ def get_vault_connection(): ) raise salt.exceptions.CommandExecutionError(errmsg) + config = __opts__["vault"].get("config_location") + if config: + if config not in ["local", "master"]: + log.error("config_location must be either local or master") + return False + if config == "local": + return _use_local_config() + elif config == "master": + return _get_token_and_url_from_master() + if "vault" in __opts__ and __opts__.get("__role", "minion") == "master": if "id" in __grains__: log.debug("Contacting master for Vault connection details") diff --git a/tests/pytests/unit/utils/test_vault.py b/tests/pytests/unit/utils/test_vault.py index 55eea0811b1..e6abcc13557 100644 --- a/tests/pytests/unit/utils/test_vault.py +++ b/tests/pytests/unit/utils/test_vault.py @@ -544,3 +544,35 @@ def test_get_secret_path_metadata_no_cache(metadata_v2, cache_uses, cache_secret assert function_result == metadata_v2 mock_write_cache.assert_called_with(cache_object) assert cache_object == expected_cache_object + + +@pytest.mark.parametrize( + "conf_location,called", + [("local", False), ("master", True), (None, False), ("doesnotexist", False)], +) +def test_get_vault_connection_config_location(tmp_path, conf_location, called, caplog): + """ + test the get_vault_connection function when + config_location is set in opts + """ + token_url = { + "url": "http://127.0.0.1", + "namespace": None, + "token": "test", + "verify": None, + "issued": 1666100373, + "ttl": 3600, + } + + opts = {"config_location": conf_location, "pki_dir": tmp_path / "pki"} + with patch.object(vault, "_get_token_and_url_from_master") as patch_token: + patch_token.return_vaule = token_url + with patch.dict(vault.__opts__["vault"], opts): + vault.get_vault_connection() + + if called: + patch_token.assert_called() + else: + patch_token.assert_not_called() + if conf_location == "doesnotexist": + assert "config_location must be either local or master" in caplog.text