From 916cfafae3601935b04601acfb30da812f0dd526 Mon Sep 17 00:00:00 2001 From: Lee Yarwood Date: Wed, 4 Jan 2017 17:16:05 +0000 Subject: [PATCH] encryptors: Introduce encryption provider constants These constants detail the supported encryption formats and their associated in tree encryption provider implementations. The use of out of tree and direct use of these in tree implementations is now deprecated and will be blocked in the Pike release of os-brick. Change-Id: Ic155bd29d46059832cce970bf60375e7e472eca6 Partial-bug: #1639293 --- os_brick/encryptors/__init__.py | 43 +++++-- os_brick/tests/encryptors/test_base.py | 118 +++++++++++++----- ...n-provider-constants-a7cd0ce58da2bae8.yaml | 14 +++ 3 files changed, 133 insertions(+), 42 deletions(-) create mode 100644 releasenotes/notes/introduce-encryption-provider-constants-a7cd0ce58da2bae8.yaml diff --git a/os_brick/encryptors/__init__.py b/os_brick/encryptors/__init__.py index 92aca1b03..064fbd50f 100644 --- a/os_brick/encryptors/__init__.py +++ b/os_brick/encryptors/__init__.py @@ -22,6 +22,23 @@ from oslo_utils import strutils LOG = logging.getLogger(__name__) +LUKS = "luks" +PLAIN = "plain" + +FORMAT_TO_FRONTEND_ENCRYPTOR_MAP = { + LUKS: 'os_brick.encryptors.luks.LuksEncryptor', + PLAIN: 'os_brick.encryptors.cryptsetup.CryptsetupEncryptor' +} + +LEGACY_PROVIDER_CLASS_TO_FORMAT_MAP = { + "os_brick.encryptors.luks.LuksEncryptor": LUKS, + "os_brick.encryptors.cryptsetup.CryptsetupEncryptor": PLAIN, + "os_brick.encryptors.nop.NoopEncryptor": None, + "LuksEncryptor": LUKS, + "CryptsetupEncryptor": PLAIN, + "NoOpEncryptor": None, +} + def get_volume_encryptor(root_helper, connection_info, @@ -43,14 +60,24 @@ def get_volume_encryptor(root_helper, if location and location.lower() == 'front-end': # case insensitive provider = kwargs.get('provider') - if provider == 'LuksEncryptor' or 'LuksEncryptor' in provider: - provider = 'os_brick.encryptors.luks.LuksEncryptor' - elif (provider == 'CryptsetupEncryptor' or - 'CryptsetupEncryptor' in provider): - provider = \ - 'os_brick.encryptors.cryptsetup.CryptsetupEncryptor' - elif (provider == 'NoOpEncryptor' or 'NoOpEncryptor' in provider): - provider = 'os_brick.encryptors.nop.NoOpEncryptor' + # TODO(lyarwood): Remove the following in Pike and raise an + # ERROR if provider is not a key in SUPPORTED_ENCRYPTION_PROVIDERS. + # Until then continue to allow both the class name and path to be used. + if provider in LEGACY_PROVIDER_CLASS_TO_FORMAT_MAP: + LOG.warning(_LW("Use of the in tree encryptor class %(provider)s" + " by directly referencing the implementation class" + " will be blocked in the Pike release of" + " os-brick."), {'provider': provider}) + provider = LEGACY_PROVIDER_CLASS_TO_FORMAT_MAP[provider] + + if provider in FORMAT_TO_FRONTEND_ENCRYPTOR_MAP: + provider = FORMAT_TO_FRONTEND_ENCRYPTOR_MAP[provider] + elif provider is None: + provider = "os_brick.encryptors.nop.NoOpEncryptor" + else: + LOG.warning(_LW("Use of the out of tree encryptor class " + "%(provider)s will be blocked with the Pike " + "release of os-brick."), {'provider': provider}) try: encryptor = importutils.import_object( diff --git a/os_brick/tests/encryptors/test_base.py b/os_brick/tests/encryptors/test_base.py index b9d8d19ed..8609cb9f7 100644 --- a/os_brick/tests/encryptors/test_base.py +++ b/os_brick/tests/encryptors/test_base.py @@ -40,44 +40,42 @@ class VolumeEncryptorTestCase(base.TestCase): class BaseEncryptorTestCase(VolumeEncryptorTestCase): + def _test_get_encryptor(self, provider, expected_provider_class): + encryption = {'control_location': 'front-end', + 'provider': provider} + encryptor = encryptors.get_volume_encryptor( + root_helper=self.root_helper, + connection_info=self.connection_info, + keymgr=self.keymgr, + **encryption) + self.assertIsInstance(encryptor, expected_provider_class) + def test_get_encryptors(self): - encryption = {'control_location': 'front-end', - 'provider': 'LuksEncryptor'} - encryptor = encryptors.get_volume_encryptor( - root_helper=self.root_helper, - connection_info=self.connection_info, - keymgr=self.keymgr, - **encryption) + self._test_get_encryptor('luks', + encryptors.luks.LuksEncryptor) + # TODO(lyarwood): Remove the following in Pike + self._test_get_encryptor('LuksEncryptor', + encryptors.luks.LuksEncryptor) + self._test_get_encryptor('os_brick.encryptors.luks.LuksEncryptor', + encryptors.luks.LuksEncryptor) - self.assertIsInstance(encryptor, - encryptors.luks.LuksEncryptor, - "encryptor is not an instance of LuksEncryptor") + self._test_get_encryptor('plain', + encryptors.cryptsetup.CryptsetupEncryptor) + # TODO(lyarwood): Remove the following in Pike + self._test_get_encryptor('CryptsetupEncryptor', + encryptors.cryptsetup.CryptsetupEncryptor) + self._test_get_encryptor( + 'os_brick.encryptors.cryptsetup.CryptsetupEncryptor', + encryptors.cryptsetup.CryptsetupEncryptor) - encryption = {'control_location': 'front-end', - 'provider': 'CryptsetupEncryptor'} - encryptor = encryptors.get_volume_encryptor( - root_helper=self.root_helper, - connection_info=self.connection_info, - keymgr=self.keymgr, - **encryption) - - self.assertIsInstance(encryptor, - encryptors.cryptsetup.CryptsetupEncryptor, - "encryptor is not an instance of" - "CryptsetupEncryptor") - - encryption = {'control_location': 'front-end', - 'provider': 'NoOpEncryptor'} - encryptor = encryptors.get_volume_encryptor( - root_helper=self.root_helper, - connection_info=self.connection_info, - keymgr=self.keymgr, - **encryption) - - self.assertIsInstance(encryptor, - encryptors.nop.NoOpEncryptor, - "encryptor is not an instance of NoOpEncryptor") + self._test_get_encryptor(None, + encryptors.nop.NoOpEncryptor) + # TODO(lyarwood): Remove the following in Pike + self._test_get_encryptor('NoOpEncryptor', + encryptors.nop.NoOpEncryptor) + self._test_get_encryptor('os_brick.encryptors.nop.NoOpEncryptor', + encryptors.nop.NoOpEncryptor) def test_get_error_encryptors(self): encryption = {'control_location': 'front-end', @@ -106,3 +104,55 @@ class BaseEncryptorTestCase(VolumeEncryptorTestCase): "%(exception)s", {'provider': provider, 'exception': e}) + + @mock.patch('os_brick.encryptors.LOG') + def test_get_missing_out_of_tree_encryptor_log(self, log): + provider = 'TestEncryptor' + encryption = {'control_location': 'front-end', + 'provider': provider} + try: + encryptors.get_volume_encryptor( + root_helper=self.root_helper, + connection_info=self.connection_info, + keymgr=self.keymgr, + **encryption) + except Exception as e: + log.error.assert_called_once_with("Error instantiating " + "%(provider)s: " + "%(exception)s", + {'provider': provider, + 'exception': e}) + log.warning.assert_called_once_with("Use of the out of tree " + "encryptor class %(provider)s " + "will be blocked with the " + "Pike release of os-brick.", + {'provider': provider}) + + @mock.patch('os_brick.encryptors.LOG') + def test_get_direct_encryptor_log(self, log): + encryption = {'control_location': 'front-end', + 'provider': 'LuksEncryptor'} + encryptors.get_volume_encryptor( + root_helper=self.root_helper, + connection_info=self.connection_info, + keymgr=self.keymgr, + **encryption) + + encryption = {'control_location': 'front-end', + 'provider': 'os_brick.encryptors.luks.LuksEncryptor'} + encryptors.get_volume_encryptor( + root_helper=self.root_helper, + connection_info=self.connection_info, + keymgr=self.keymgr, + **encryption) + + log.warning.assert_has_calls([ + mock.call("Use of the in tree encryptor class %(provider)s by " + "directly referencing the implementation class will be " + "blocked in the Pike release of os-brick.", + {'provider': 'LuksEncryptor'}), + mock.call("Use of the in tree encryptor class %(provider)s by " + "directly referencing the implementation class will be " + "blocked in the Pike release of os-brick.", + {'provider': + 'os_brick.encryptors.luks.LuksEncryptor'})]) diff --git a/releasenotes/notes/introduce-encryption-provider-constants-a7cd0ce58da2bae8.yaml b/releasenotes/notes/introduce-encryption-provider-constants-a7cd0ce58da2bae8.yaml new file mode 100644 index 000000000..ec9fe21d1 --- /dev/null +++ b/releasenotes/notes/introduce-encryption-provider-constants-a7cd0ce58da2bae8.yaml @@ -0,0 +1,14 @@ +--- +features: + - | + Encryption provider constants have been introduced detailing the supported + encryption formats such as LUKs along with their associated in-tree + provider implementations. These constants should now be used to identify an + encryption provider implementation for a given encryption format. +deprecations: + - | + The direct use of the encryption provider classes such as + os_brick.encryptors.luks.LuksEncryptor is now deprecated and will be + blocked in the Pike release of os-brick. The use of out of tree encryption + provider classes is also deprecated and will be blocked in the Pike release + of os-brick.