encryptors: Introduce support for LUKS2
LUKS2 support was introduced into cryptsetup 2.0.0 [1] and offers various improvements over the original format now referred to as LUKS1. This change introduces an encryptor to os-brick mostly using the existing LuksEncryptor class with the only difference being the `--type` switch supplied to cryptsetup when formatting a volume. As such the bulk of the _format_volume method from the original class has been extracted into a new _format_luks_volume method both the original and new Luks2Encryptor class can now reuse. [1] https://www.saout.de/pipermail/dm-crypt/2017-December/005771.html Change-Id: I09fb2b2be1e376f8ec0f49741c855cfd54ee27f0
This commit is contained in:
parent
80da84a09d
commit
6a01bacda7
@ -22,10 +22,12 @@ from oslo_utils import strutils
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
LUKS = "luks"
|
||||
LUKS2 = "luks2"
|
||||
PLAIN = "plain"
|
||||
|
||||
FORMAT_TO_FRONTEND_ENCRYPTOR_MAP = {
|
||||
LUKS: 'os_brick.encryptors.luks.LuksEncryptor',
|
||||
LUKS2: 'os_brick.encryptors.luks.Luks2Encryptor',
|
||||
PLAIN: 'os_brick.encryptors.cryptsetup.CryptsetupEncryptor'
|
||||
}
|
||||
|
||||
|
@ -61,15 +61,29 @@ class LuksEncryptor(cryptsetup.CryptsetupEncryptor):
|
||||
*args, **kwargs)
|
||||
|
||||
def _format_volume(self, passphrase, **kwargs):
|
||||
"""Creates a LUKS header on the volume.
|
||||
"""Creates a LUKS v1 header on the volume.
|
||||
|
||||
:param passphrase: the passphrase used to access the volume
|
||||
"""
|
||||
self._format_luks_volume(passphrase, 'luks1', **kwargs)
|
||||
|
||||
def _format_luks_volume(self, passphrase, version, **kwargs):
|
||||
"""Creates a LUKS header of a given version or type on the volume.
|
||||
|
||||
:param passphrase: the passphrase used to access the volume
|
||||
:param version: the LUKS version or type to use: one of `luks`,
|
||||
`luks1`, or `luks2`. Be aware that `luks` gives you
|
||||
the default LUKS format preferred by the particular
|
||||
cryptsetup being used (depends on version and compile
|
||||
time parameters), which could be either LUKS1 or
|
||||
LUKS2, so it's better to be specific about what you
|
||||
want here
|
||||
"""
|
||||
LOG.debug("formatting encrypted volume %s", self.dev_path)
|
||||
|
||||
# NOTE(joel-coffman): cryptsetup will strip trailing newlines from
|
||||
# input specified on stdin unless --key-file=- is specified.
|
||||
cmd = ["cryptsetup", "--batch-mode", "luksFormat", "--type", "luks1",
|
||||
cmd = ["cryptsetup", "--batch-mode", "luksFormat", "--type", version,
|
||||
"--key-file=-"]
|
||||
|
||||
cipher = kwargs.get("cipher", None)
|
||||
@ -191,3 +205,28 @@ class LuksEncryptor(cryptsetup.CryptsetupEncryptor):
|
||||
run_as_root=True, check_exit_code=[0, 4],
|
||||
root_helper=self._root_helper,
|
||||
attempts=3)
|
||||
|
||||
|
||||
class Luks2Encryptor(LuksEncryptor):
|
||||
"""A VolumeEncryptor based on LUKS v2.
|
||||
|
||||
This VolumeEncryptor uses dm-crypt to encrypt the specified volume.
|
||||
"""
|
||||
def __init__(self, root_helper,
|
||||
connection_info,
|
||||
keymgr,
|
||||
execute=None,
|
||||
*args, **kwargs):
|
||||
super(Luks2Encryptor, self).__init__(
|
||||
root_helper=root_helper,
|
||||
connection_info=connection_info,
|
||||
keymgr=keymgr,
|
||||
execute=execute,
|
||||
*args, **kwargs)
|
||||
|
||||
def _format_volume(self, passphrase, **kwargs):
|
||||
"""Creates a LUKS v2 header on the volume.
|
||||
|
||||
:param passphrase: the passphrase used to access the volume
|
||||
"""
|
||||
self._format_luks_volume(passphrase, 'luks2', **kwargs)
|
||||
|
@ -253,3 +253,62 @@ class LuksEncryptorTestCase(test_cryptsetup.CryptsetupEncryptorTestCase):
|
||||
check_exit_code=True),
|
||||
], any_order=False)
|
||||
self.assertEqual(9, mock_execute.call_count)
|
||||
|
||||
|
||||
class Luks2EncryptorTestCase(LuksEncryptorTestCase):
|
||||
def _create(self):
|
||||
return luks.Luks2Encryptor(root_helper=self.root_helper,
|
||||
connection_info=self.connection_info,
|
||||
keymgr=self.keymgr)
|
||||
|
||||
@mock.patch('os_brick.executor.Executor._execute')
|
||||
def test__format_volume(self, mock_execute):
|
||||
self.encryptor._format_volume("passphrase")
|
||||
|
||||
mock_execute.assert_has_calls([
|
||||
mock.call('cryptsetup', '--batch-mode', 'luksFormat',
|
||||
'--type', 'luks2', '--key-file=-', self.dev_path,
|
||||
process_input='passphrase',
|
||||
root_helper=self.root_helper,
|
||||
run_as_root=True, check_exit_code=True, attempts=3),
|
||||
])
|
||||
|
||||
@mock.patch('os_brick.executor.Executor._execute')
|
||||
def test_attach_volume_not_formatted(self, mock_execute):
|
||||
fake_key = 'bc37c5eccebe403f9cc2d0dd20dac2bc'
|
||||
self.encryptor._get_key = mock.MagicMock()
|
||||
self.encryptor._get_key.return_value = (
|
||||
test_cryptsetup.fake__get_key(None, fake_key))
|
||||
|
||||
mock_execute.side_effect = [
|
||||
putils.ProcessExecutionError(exit_code=1), # luksOpen
|
||||
putils.ProcessExecutionError(exit_code=1), # isLuks
|
||||
mock.DEFAULT, # luksFormat
|
||||
mock.DEFAULT, # luksOpen
|
||||
mock.DEFAULT, # ln
|
||||
]
|
||||
|
||||
self.encryptor.attach_volume(None)
|
||||
|
||||
mock_execute.assert_has_calls([
|
||||
mock.call('cryptsetup', 'luksOpen', '--key-file=-', self.dev_path,
|
||||
self.dev_name, process_input=fake_key,
|
||||
root_helper=self.root_helper,
|
||||
run_as_root=True, check_exit_code=True),
|
||||
mock.call('cryptsetup', 'isLuks', '--verbose', self.dev_path,
|
||||
root_helper=self.root_helper,
|
||||
run_as_root=True, check_exit_code=True),
|
||||
mock.call('cryptsetup', '--batch-mode', 'luksFormat',
|
||||
'--type', 'luks2', '--key-file=-', self.dev_path,
|
||||
process_input=fake_key,
|
||||
root_helper=self.root_helper,
|
||||
run_as_root=True, check_exit_code=True, attempts=3),
|
||||
mock.call('cryptsetup', 'luksOpen', '--key-file=-', self.dev_path,
|
||||
self.dev_name, process_input=fake_key,
|
||||
root_helper=self.root_helper,
|
||||
run_as_root=True, check_exit_code=True),
|
||||
mock.call('ln', '--symbolic', '--force',
|
||||
'/dev/mapper/%s' % self.dev_name, self.symlink_path,
|
||||
root_helper=self.root_helper,
|
||||
run_as_root=True, check_exit_code=True),
|
||||
], any_order=False)
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
A LUKS2 encryptor has been introduced providing support for this latest
|
||||
version of the Linux Unified Key Setup disk encryption format. This
|
||||
requires ``cryptsetup`` version 2.0.0 or greater.
|
Loading…
Reference in New Issue
Block a user