← Back to team overview

curtin-dev team mailing list archive

[Merge] ~ogayot/curtin:recovery-key into curtin:master

 

Olivier Gayot has proposed merging ~ogayot/curtin:recovery-key into curtin:master.

Commit message:
block_meta: add luks recovery key if requested

If the storage configuration contains the key "recovery_keyfile", call
cryptsetup luksAddKey after cryptsetup luksFormat so that the key
specified is added as a recovery key (i.e., a normal key in the second
key slot).
    
Signed-off-by: Olivier Gayot <olivier.gayot@xxxxxxxxxxxxx>


Requested reviews:
  curtin developers (curtin-dev)

For more details, see:
https://code.launchpad.net/~ogayot/curtin/+git/curtin/+merge/449362

This adds support for adding a LUKS recovery key. Something special probably needs to be done for s390x but that's all I have at the moment.
-- 
Your team curtin developers is requested to review the proposed merge of ~ogayot/curtin:recovery-key into curtin:master.
diff --git a/curtin/commands/block_meta.py b/curtin/commands/block_meta.py
index dd6992d..64bf393 100644
--- a/curtin/commands/block_meta.py
+++ b/curtin/commands/block_meta.py
@@ -1645,6 +1645,8 @@ def dm_crypt_handler(info, storage_config, context):
     else:
         raise ValueError("encryption key or keyfile must be specified")
 
+    recovery_keyfile = info.get('recovery_keyfile')
+
     create_dmcrypt = True
     if preserve:
         dm_crypt_verify(dmcrypt_dev, volume_path)
@@ -1688,8 +1690,20 @@ def dm_crypt_handler(info, storage_config, context):
             if keysize:
                 cmd.extend(["--key-size", keysize])
             cmd.extend(["luksFormat", volume_path, keyfile])
+
             util.subp(cmd)
 
+            # Should this be done as well if we are using zkey?
+            if recovery_keyfile is not None:
+                LOG.debug("Adding recovery key to %s", volume_path)
+
+                cmd = [
+                    "cryptsetup", "luksAddKey",
+                    "--key-file", keyfile,
+                    volume_path, recovery_keyfile]
+
+                util.subp(cmd)
+
         cmd = ["cryptsetup", "open", "--type", luks_type, volume_path, dm_name,
                "--key-file", keyfile]
 
diff --git a/tests/unittests/test_commands_block_meta.py b/tests/unittests/test_commands_block_meta.py
index 87e46eb..1a1f65d 100644
--- a/tests/unittests/test_commands_block_meta.py
+++ b/tests/unittests/test_commands_block_meta.py
@@ -2100,6 +2100,58 @@ class TestDmCryptHandler(CiTestCase):
         self.m_subp.assert_has_calls(expected_calls)
         self.assertEqual(len(util.load_file(self.crypttab).splitlines()), 1)
 
+    def test_dm_crypt_calls_cryptsetup_with_recovery_key(self):
+        """ verify dm_crypt calls (format, addKey, open) w/ correct params"""
+        volume_path = self.random_string()
+        self.m_getpath.return_value = volume_path
+
+        recovery_keyfile = self.random_string()
+        config = {
+            'storage': {
+                'version': 1,
+                'config': [
+                    {'grub_device': True,
+                     'id': 'sda',
+                     'name': 'sda',
+                     'path': '/wark/xxx',
+                     'ptable': 'msdos',
+                     'type': 'disk',
+                     'wipe': 'superblock'},
+                    {'device': 'sda',
+                     'id': 'sda-part1',
+                     'name': 'sda-part1',
+                     'number': 1,
+                     'size': '511705088B',
+                     'type': 'partition'},
+                    {'id': 'dmcrypt0',
+                     'type': 'dm_crypt',
+                     'dm_name': 'cryptroot',
+                     'volume': 'sda-part1',
+                     'cipher': self.cipher,
+                     'keysize': self.keysize,
+                     'keyfile': self.keyfile,
+                     'recovery_keyfile': recovery_keyfile},
+                ],
+            }
+        }
+        storage_config = block_meta.extract_storage_ordered_dict(config)
+
+        info = storage_config['dmcrypt0']
+
+        block_meta.dm_crypt_handler(info, storage_config, empty_context)
+        expected_calls = [
+            call(['cryptsetup', '--cipher', self.cipher,
+                  '--key-size', self.keysize,
+                  'luksFormat', volume_path, self.keyfile]),
+            call(['cryptsetup', 'luksAddKey',
+                  '--key-file', self.keyfile,
+                  volume_path, recovery_keyfile]),
+            call(['cryptsetup', 'open', '--type', 'luks', volume_path,
+                  info['dm_name'], '--key-file', self.keyfile])
+        ]
+        self.m_subp.assert_has_calls(expected_calls)
+        self.assertEqual(len(util.load_file(self.crypttab).splitlines()), 1)
+
     def test_dm_crypt_defaults_dm_name_to_id(self):
         """ verify dm_crypt_handler falls back to id with no dm_name. """
         volume_path = self.random_string()

Follow ups