Fix Vault K/V API compatibility.
Starting from version 0.10.0, HashiCorp Vault has a different
API for the Key/Value Secrets Engine. This fix implements both
the new API support and the fallback for the legacy one.
Fixes https://bugs.launchpad.net/castellan/+bug/1788375
Change-Id: I7fed7b5091440dae15551d83f0ee0895651e47bf
Signed-off-by: Moises Guimaraes de Medeiros <moguimar@redhat.com>
Moises Guimaraes de Medeiros
5 years ago
92 | 92 | self._verify_server = self._conf.vault.ssl_ca_crt_file or True |
93 | 93 | else: |
94 | 94 | self._verify_server = False |
95 | self._vault_kv_version = None | |
95 | 96 | |
96 | 97 | def _get_url(self): |
97 | 98 | if not self._vault_url.endswith('/'): |
98 | 99 | self._vault_url += '/' |
99 | 100 | return self._vault_url |
101 | ||
102 | def _get_api_version(self): | |
103 | if self._vault_kv_version: | |
104 | return self._vault_kv_version | |
105 | ||
106 | headers = {'X-Vault-Token': self._root_token_id} | |
107 | try: | |
108 | resource_url = self._get_url() + 'v1/sys/internal/ui/mounts/secret' | |
109 | resp = self._session.get(resource_url, | |
110 | verify=self._verify_server, | |
111 | headers=headers) | |
112 | except requests.exceptions.Timeout as ex: | |
113 | raise exception.KeyManagerError(six.text_type(ex)) | |
114 | except requests.exceptions.ConnectionError as ex: | |
115 | raise exception.KeyManagerError(six.text_type(ex)) | |
116 | except Exception as ex: | |
117 | raise exception.KeyManagerError(six.text_type(ex)) | |
118 | ||
119 | if resp.status_code in _EXCEPTIONS_BY_CODE: | |
120 | raise exception.KeyManagerError(resp.reason) | |
121 | if resp.status_code == requests.codes['forbidden']: | |
122 | raise exception.Forbidden() | |
123 | if resp.status_code == requests.codes['not_found']: | |
124 | self._vault_kv_version = '1' | |
125 | else: | |
126 | self._vault_kv_version = resp.json()['data']['options']['version'] | |
127 | ||
128 | return self._vault_kv_version | |
100 | 129 | |
101 | 130 | def create_key_pair(self, context, algorithm, length, |
102 | 131 | expiration=None, name=None): |
158 | 187 | |
159 | 188 | headers = {'X-Vault-Token': self._root_token_id} |
160 | 189 | try: |
161 | resource_url = self._get_url() + 'v1/secret/' + key_id | |
190 | resource_url = '{}v1/secret/{}{}'.format( | |
191 | self._get_url(), | |
192 | '' if self._get_api_version() == '1' else 'data/', | |
193 | key_id) | |
194 | ||
162 | 195 | record = { |
163 | 196 | 'type': type_value, |
164 | 197 | 'value': binascii.hexlify(value.get_encoded()).decode('utf-8'), |
169 | 202 | 'name': value.name, |
170 | 203 | 'created': value.created |
171 | 204 | } |
205 | if self._get_api_version() != '1': | |
206 | record = {'data': record} | |
207 | ||
172 | 208 | resp = self._session.post(resource_url, |
173 | 209 | verify=self._verify_server, |
174 | 210 | json=record, |
228 | 264 | |
229 | 265 | headers = {'X-Vault-Token': self._root_token_id} |
230 | 266 | try: |
231 | resource_url = self._get_url() + 'v1/secret/' + key_id | |
267 | resource_url = '{}v1/secret/{}{}'.format( | |
268 | self._get_url(), | |
269 | '' if self._get_api_version() == '1' else 'data/', | |
270 | key_id) | |
271 | ||
232 | 272 | resp = self._session.get(resource_url, |
233 | 273 | verify=self._verify_server, |
234 | 274 | headers=headers) |
247 | 287 | raise exception.ManagedObjectNotFoundError(uuid=key_id) |
248 | 288 | |
249 | 289 | record = resp.json()['data'] |
290 | if self._get_api_version() != '1': | |
291 | record = record['data'] | |
292 | ||
250 | 293 | key = None if metadata_only else binascii.unhexlify(record['value']) |
251 | 294 | |
252 | 295 | clazz = None |
284 | 327 | |
285 | 328 | headers = {'X-Vault-Token': self._root_token_id} |
286 | 329 | try: |
287 | resource_url = self._get_url() + 'v1/secret/' + key_id | |
330 | resource_url = '{}v1/secret/{}{}'.format( | |
331 | self._get_url(), | |
332 | '' if self._get_api_version() == '1' else 'data/', | |
333 | key_id) | |
334 | ||
288 | 335 | resp = self._session.delete(resource_url, |
289 | 336 | verify=self._verify_server, |
290 | 337 | headers=headers) |
316 | 363 | |
317 | 364 | headers = {'X-Vault-Token': self._root_token_id} |
318 | 365 | try: |
319 | resource_url = self._get_url() + 'v1/secret/?list=true' | |
366 | resource_url = '{}v1/secret/{}?list=true'.format( | |
367 | self._get_url(), | |
368 | '' if self._get_api_version() == '1' else 'metadata/') | |
369 | ||
320 | 370 | resp = self._session.get(resource_url, |
321 | 371 | verify=self._verify_server, |
322 | 372 | headers=headers) |