Support trying all available tokens
Since the relation with vault maybe contain more than one token and we have no way to know if they are valid, we support trying them all until we get a good one and raise the error only if we tried them all unsuccessfully and have no current secret-id otherwise return current secret-id. Change-Id: I2ee5ffe5d53e874efb3fabc6a880bf95b00a44f9 Partial-Bug: #1849323
This commit is contained in:
parent
c8b24309e2
commit
4a1517d2fb
|
@ -11,6 +11,8 @@
|
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import hvac
|
||||
|
||||
import charmhelpers.core as ch_core
|
||||
|
||||
import charms.reactive as reactive
|
||||
|
@ -44,12 +46,44 @@ def secret_backend_vault_request():
|
|||
barbican_vault_charm.assess_status()
|
||||
|
||||
|
||||
def get_secret_id(secrets_storage, current_secret_id=None):
|
||||
"""Get tokens from relation and try to fetch secret-id from Vault api
|
||||
|
||||
Try all tokens until one succeeds. If all fail, return cached token
|
||||
otherwise raise hvac.exceptions.InvalidRequest.
|
||||
"""
|
||||
tokens = secrets_storage.all_unit_tokens
|
||||
url = secrets_storage.vault_url
|
||||
for i, token in enumerate(tokens):
|
||||
try:
|
||||
secret_id = vault_utils.retrieve_secret_id(url, token)
|
||||
return secret_id
|
||||
except hvac.exceptions.InvalidRequest:
|
||||
if i == len(tokens) - 1:
|
||||
if current_secret_id:
|
||||
return current_secret_id
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
@reactive.when_all('endpoint.secrets.joined', 'secrets-storage.available',
|
||||
'endpoint.secrets-storage.changed')
|
||||
def plugin_info_barbican_publish():
|
||||
barbican = reactive.endpoint_from_flag('endpoint.secrets.joined')
|
||||
secrets_storage = reactive.endpoint_from_flag(
|
||||
'secrets-storage.available')
|
||||
|
||||
# fetch current secret-id, if any, from relation with barbican principle
|
||||
current_secret_id = None
|
||||
secrets = reactive.endpoint_from_flag('secrets.available')
|
||||
if secrets:
|
||||
for relation in secrets.relations:
|
||||
data = relation.to_publish.get('data')
|
||||
if data and data.get('approle_secret_id'):
|
||||
current_secret_id = data.get('approle_secret_id')
|
||||
|
||||
with charm.provide_charm_instance() as barbican_vault_charm:
|
||||
if secrets_storage.vault_ca:
|
||||
ch_core.hookenv.log('Installing vault CA certificate')
|
||||
|
@ -57,9 +91,7 @@ def plugin_info_barbican_publish():
|
|||
ch_core.hookenv.log('Retrieving secret-id from vault ({})'
|
||||
.format(secrets_storage.vault_url),
|
||||
level=ch_core.hookenv.INFO)
|
||||
secret_id = vault_utils.retrieve_secret_id(
|
||||
secrets_storage.vault_url,
|
||||
secrets_storage.unit_token)
|
||||
secret_id = get_secret_id(secrets_storage, current_secret_id)
|
||||
vault_data = {
|
||||
'approle_role_id': secrets_storage.unit_role_id,
|
||||
'approle_secret_id': secret_id,
|
||||
|
|
|
@ -51,6 +51,13 @@ class TestRegisteredHooks(test_utils.TestRegisteredHooks):
|
|||
|
||||
class TestBarbicanVaultHandlers(test_utils.PatchHelper):
|
||||
|
||||
def fake_hvac(self):
|
||||
fake_exc = mock.MagicMock()
|
||||
fake_exc.InvalidRequest = Exception
|
||||
self.fake_hvac = mock.MagicMock()
|
||||
self.fake_hvac.exceptions = fake_exc
|
||||
return self.fake_hvac
|
||||
|
||||
def patch_charm(self):
|
||||
barbican_vault_charm = mock.MagicMock()
|
||||
self.patch_object(handlers.charm, 'provide_charm_instance',
|
||||
|
@ -74,30 +81,60 @@ class TestBarbicanVaultHandlers(test_utils.PatchHelper):
|
|||
secrets_storage.request_secret_backend.assert_called_once_with(
|
||||
'charm-barbican-vault', isolated=False)
|
||||
|
||||
@mock.patch.object(handlers.vault_utils, 'retrieve_secret_id')
|
||||
@mock.patch.object(handlers.reactive, 'endpoint_from_flag')
|
||||
def test_get_secret_id(self, endpoint_from_flag, retrieve_secret_id):
|
||||
with mock.patch.object(handlers, 'hvac', self.fake_hvac()):
|
||||
endpoint_from_flag.all_unit_tokens = ['token1']
|
||||
endpoint_from_flag.vault_url = 'https://foo.fl:8200'
|
||||
retrieve_secret_id.return_value = 'big-secret'
|
||||
self.assertEquals(handlers.get_secret_id(endpoint_from_flag,
|
||||
'old-secret'),
|
||||
'big-secret')
|
||||
|
||||
@mock.patch.object(handlers.vault_utils, 'retrieve_secret_id')
|
||||
@mock.patch.object(handlers.reactive, 'endpoint_from_flag')
|
||||
def test_get_secret_id_fail(self, endpoint_from_flag, retrieve_secret_id):
|
||||
with mock.patch.object(handlers, 'hvac', self.fake_hvac()):
|
||||
endpoint_from_flag.all_unit_tokens = ['token1']
|
||||
endpoint_from_flag.vault_url = 'https://foo.fl:8200'
|
||||
|
||||
def fail(*args, **kwargs):
|
||||
raise self.fake_hvac.exceptions.InvalidRequest
|
||||
|
||||
retrieve_secret_id.side_effect = fail
|
||||
self.assertEquals(handlers.get_secret_id(endpoint_from_flag,
|
||||
'old-secret'),
|
||||
'old-secret')
|
||||
|
||||
def test_plugin_info_barbican_publish(self):
|
||||
barbican_vault_charm = self.patch_charm()
|
||||
self.patch_object(handlers.reactive, 'endpoint_from_flag')
|
||||
barbican = mock.MagicMock()
|
||||
secrets = mock.MagicMock()
|
||||
secrets_storage = mock.MagicMock()
|
||||
self.endpoint_from_flag.side_effect = [barbican, secrets_storage]
|
||||
self.patch_object(handlers.vault_utils, 'retrieve_secret_id')
|
||||
self.endpoint_from_flag.side_effect = [barbican, secrets_storage,
|
||||
secrets]
|
||||
self.patch_object(handlers, 'get_secret_id')
|
||||
self.get_secret_id.return_value = 'big-secret'
|
||||
self.patch_object(handlers.reactive, 'clear_flag')
|
||||
|
||||
handlers.plugin_info_barbican_publish()
|
||||
self.endpoint_from_flag.assert_has_calls([
|
||||
mock.call('endpoint.secrets.joined'),
|
||||
mock.call('secrets-storage.available'),
|
||||
mock.call('secrets.available'),
|
||||
])
|
||||
vault_data = {
|
||||
'approle_role_id': secrets_storage.unit_role_id,
|
||||
'approle_secret_id': self.retrieve_secret_id(),
|
||||
'approle_secret_id': self.get_secret_id(),
|
||||
'vault_url': secrets_storage.vault_url,
|
||||
'kv_mountpoint': barbican_vault_charm.secret_backend_name,
|
||||
'ssl_ca_crt_file': barbican_vault_charm.installed_ca_name,
|
||||
}
|
||||
barbican_vault_charm.install_ca_cert.assert_called_once_with(
|
||||
secrets_storage.vault_ca)
|
||||
barbican.publish_plugin_info.assert_called_once_with(
|
||||
'vault', vault_data)
|
||||
calls = [mock.call('vault', vault_data)]
|
||||
barbican.publish_plugin_info.assert_has_calls(calls)
|
||||
self.clear_flag.assert_called_once_with(
|
||||
'endpoint.secrets-storage.changed')
|
||||
|
|
Loading…
Reference in New Issue