Added metadata service encryption key retrieval

The encryption public key, if existent, will be used to encrypt the
user password to be sent to the metadata service.
By default, in case of OpenStack, the first public key set by the user
will be used to encrypt the user password.

This special method is needed by metadata services implementations
which will not rely on the same behaviour, as the the encryption key
can be set at another metadata endpoint.

Partially implements: blueprint packet-metadata-suport

Co-Authored-By: Paula Madalina Crismaru <pcrismaru@cloudbasesolutions.com>

Change-Id: I8bfde766d74dcd09e659d09a33a12f6f50b36ed2
This commit is contained in:
Adrian Vladu 2017-06-20 13:54:00 +03:00
parent 526d939240
commit 8dd0d9dbc3
4 changed files with 26 additions and 30 deletions

View File

@ -110,6 +110,19 @@ class BaseMetadataService(object):
"""Get a list of space-stripped strings as public keys."""
pass
def get_user_pwd_encryption_key(self):
"""Get the user password encryption public key as a string.
The encryption public key, if existent, will be used to encrypt the
user password to be sent to the metadata service.
By default, the first public key set by the user
will be used to encrypt the user password.
"""
public_keys = self.get_public_keys()
if public_keys:
return list(public_keys)[0]
def get_network_details(self):
"""Return a list of `NetworkDetails` objects.

View File

@ -36,11 +36,6 @@ class SetUserPasswordPlugin(base.BasePlugin):
enc_password = rsa.public_encrypt(password.encode())
return base64.b64encode(enc_password)
def _get_ssh_public_key(self, service):
public_keys = service.get_public_keys()
if public_keys:
return list(public_keys)[0]
def _get_password(self, service, shared_data):
injected = False
if CONF.inject_user_password:
@ -63,10 +58,10 @@ class SetUserPasswordPlugin(base.BasePlugin):
'and it cannot be updated in the instance metadata')
return True
else:
ssh_pub_key = self._get_ssh_public_key(service)
if ssh_pub_key:
enc_password_b64 = self._encrypt_password(ssh_pub_key,
password)
user_pwd_encryption_key = service.get_user_pwd_encryption_key()
if user_pwd_encryption_key:
enc_password_b64 = self._encrypt_password(
user_pwd_encryption_key, password)
return service.post_password(enc_password_b64)
else:
LOG.info('No SSH public key available for password encryption')

View File

@ -54,6 +54,13 @@ class TestBase(unittest.TestCase):
def test_is_password_changed(self):
self.assertFalse(self._service.is_password_changed())
@mock.patch('cloudbaseinit.metadata.services.base.'
'BaseMetadataService.get_public_keys')
def test_get_user_pwd_encryption_key(self, mock_get_public_keys):
mock_get_public_keys.return_value = ['fake', 'keys']
result = self._service.get_user_pwd_encryption_key()
self.assertEqual(result, mock_get_public_keys.return_value[0])
class TestBaseHTTPMetadataService(unittest.TestCase):

View File

@ -57,22 +57,6 @@ class SetUserPasswordPluginTests(unittest.TestCase):
mock_b64encode.assert_called_with('public encrypted')
self.assertEqual('encrypted password', response)
def _test_get_ssh_public_key(self, data_exists):
mock_service = mock.MagicMock()
public_keys = self.fake_data['public_keys']
mock_service.get_public_keys.return_value = public_keys.values()
response = self._setpassword_plugin._get_ssh_public_key(mock_service)
mock_service.get_public_keys.assert_called_with()
self.assertEqual(list(public_keys.values())[0], response)
def test_get_ssh_plublic_key(self):
self._test_get_ssh_public_key(data_exists=True)
def test_get_ssh_plublic_key_no_pub_keys(self):
self._test_get_ssh_public_key(data_exists=False)
def _test_get_password(self, inject_password):
shared_data = {}
expected_password = 'Passw0rd'
@ -112,18 +96,16 @@ class SetUserPasswordPluginTests(unittest.TestCase):
def test_get_password_inject_false(self):
self._test_get_password(inject_password=False)
@mock.patch('cloudbaseinit.plugins.common.setuserpassword.'
'SetUserPasswordPlugin._get_ssh_public_key')
@mock.patch('cloudbaseinit.plugins.common.setuserpassword.'
'SetUserPasswordPlugin._encrypt_password')
def _test_set_metadata_password(self, mock_encrypt_password,
mock_get_key, ssh_pub_key):
ssh_pub_key):
fake_passw0rd = 'fake Passw0rd'
mock_service = mock.MagicMock()
mock_get_key.return_value = ssh_pub_key
mock_encrypt_password.return_value = 'encrypted password'
mock_service.post_password.return_value = 'value'
mock_service.can_post_password = True
mock_service.get_user_pwd_encryption_key.return_value = ssh_pub_key
mock_service.is_password_set = False
with testutils.LogSnatcher('cloudbaseinit.plugins.common.'
'setuserpassword') as snatcher:
@ -137,7 +119,6 @@ class SetUserPasswordPluginTests(unittest.TestCase):
]
self.assertTrue(response)
else:
mock_get_key.assert_called_once_with(mock_service)
mock_encrypt_password.assert_called_once_with(ssh_pub_key,
fake_passw0rd)
mock_service.post_password.assert_called_with(