diff --git a/castellan/key_manager/vault_key_manager.py b/castellan/key_manager/vault_key_manager.py index b18dac9..1eb3836 100644 --- a/castellan/key_manager/vault_key_manager.py +++ b/castellan/key_manager/vault_key_manager.py @@ -44,6 +44,7 @@ from castellan.key_manager import key_manager DEFAULT_VAULT_URL = "http://127.0.0.1:8200" +DEFAULT_MOUNTPOINT = "secret" vault_opts = [ cfg.StrOpt('root_token_id', @@ -52,6 +53,10 @@ help='AppRole role_id for authentication with vault'), cfg.StrOpt('approle_secret_id', help='AppRole secret_id for authentication with vault'), + cfg.StrOpt('kv_mountpoint', + default=DEFAULT_MOUNTPOINT, + help='Mountpoint of KV store in Vault to use, for example: ' + '{}'.format(DEFAULT_MOUNTPOINT)), cfg.StrOpt('vault_url', default=DEFAULT_VAULT_URL, help='Use this endpoint to connect to Vault, for example: ' @@ -98,6 +103,7 @@ self._cached_approle_token_id = None self._approle_token_ttl = None self._approle_token_issue = None + self._kv_mountpoint = self._conf.vault.kv_mountpoint self._vault_url = self._conf.vault.vault_url if self._vault_url.startswith("https://"): self._verify_server = self._conf.vault.ssl_ca_crt_file or True @@ -114,7 +120,10 @@ if self._vault_kv_version: return self._vault_kv_version - resource_url = self._get_url() + 'v1/sys/internal/ui/mounts/secret' + resource_url = '{}v1/sys/internal/ui/mounts/{}'.format( + self._get_url(), + self._kv_mountpoint + ) resp = self._do_http_request(self._session.get, resource_url) if resp.status_code == requests.codes['not_found']: @@ -125,8 +134,9 @@ return self._vault_kv_version def _get_resource_url(self, key_id=None): - return '{}v1/secret/{}{}'.format( + return '{}v1/{}/{}{}'.format( self._get_url(), + self._kv_mountpoint, '' if self._get_api_version() == '1' else 'data/' if key_id else diff --git a/castellan/options.py b/castellan/options.py index 3aaa138..2caed9a 100644 --- a/castellan/options.py +++ b/castellan/options.py @@ -41,7 +41,7 @@ retry_delay=None, number_of_retries=None, verify_ssl=None, api_class=None, vault_root_token_id=None, vault_approle_role_id=None, vault_approle_secret_id=None, - vault_url=None, + vault_kv_mountpoint=None, vault_url=None, vault_ssl_ca_crt_file=None, vault_use_ssl=None, barbican_endpoint_type=None): """Set defaults for configuration values. @@ -59,6 +59,7 @@ :param vault_approle_role_id: Use this for the approle role_id for vault. :param vault_approle_secret_id: Use this for the approle secret_id for vault. + :param vault_kv_mountpoint: Mountpoint of KV store in vault to use. :param vault_url: Use this for the url for vault. :param vault_use_ssl: Use this to force vault driver to use ssl. :param vault_ssl_ca_crt_file: Use this for the CA file for vault. @@ -109,6 +110,9 @@ if vault_approle_secret_id is not None: conf.set_default('approle_secret_id', vault_approle_secret_id, group=vkm.VAULT_OPT_GROUP) + if vault_kv_mountpoint is not None: + conf.set_default('kv_mountpoint', vault_kv_mountpoint, + group=vkm.VAULT_OPT_GROUP) if vault_url is not None: conf.set_default('vault_url', vault_url, group=vkm.VAULT_OPT_GROUP) diff --git a/castellan/tests/functional/key_manager/test_vault_key_manager.py b/castellan/tests/functional/key_manager/test_vault_key_manager.py index c145164..f72cf6a 100644 --- a/castellan/tests/functional/key_manager/test_vault_key_manager.py +++ b/castellan/tests/functional/key_manager/test_vault_key_manager.py @@ -130,6 +130,8 @@ class VaultKeyManagerAppRoleTestCase(VaultKeyManagerOSLOContextTestCase): + mountpoint = 'secret' + def _create_key_manager(self): key_mgr = vault_key_manager.VaultKeyManager(cfg.CONF) @@ -147,6 +149,7 @@ self.session = requests.Session() self.session.headers.update({'X-Vault-Token': self.root_token_id}) + self._mount_kv(self.mountpoint) self._enable_approle() self._create_policy(vault_policy) self._create_approle(vault_approle, vault_policy) @@ -154,8 +157,24 @@ key_mgr._approle_role_id, key_mgr._approle_secret_id = ( self._retrieve_approle(vault_approle) ) + key_mgr._kv_mountpoint = self.mountpoint key_mgr._vault_url = self.vault_url return key_mgr + + def _mount_kv(self, vault_mountpoint): + backends = self.session.get( + '{}/v1/sys/mounts'.format(self.vault_url)).json() + if vault_mountpoint not in backends: + params = { + 'type': 'kv', + 'options': { + 'version': 2, + } + } + self.session.post( + '{}/v1/sys/mounts/{}'.format(self.vault_url, + vault_mountpoint), + json=params) def _enable_approle(self): params = { @@ -171,7 +190,7 @@ def _create_policy(self, vault_policy): params = { - 'rules': TEST_POLICY.format(backend='secret'), + 'rules': TEST_POLICY.format(backend=self.mountpoint), } self.session.put( '{}/{}'.format( @@ -213,3 +232,8 @@ )).json()['data']['secret_id'] ) return (approle_role_id, approle_secret_id) + + +class VaultKeyManagerAltMountpointTestCase(VaultKeyManagerAppRoleTestCase): + + mountpoint = 'different-secrets' diff --git a/releasenotes/notes/vault-kv-mountpoint-919eb547764a0c74.yaml b/releasenotes/notes/vault-kv-mountpoint-919eb547764a0c74.yaml new file mode 100644 index 0000000..2aaaf31 --- /dev/null +++ b/releasenotes/notes/vault-kv-mountpoint-919eb547764a0c74.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Added configuration option to the Vault key manager to allow + the KV store mountpoint in Vault to be specified; the existing + default of 'secret' is maintained.