diff options
author | Dan Bungert <[email protected]> | 2024-03-19 21:40:26 -0600 |
---|---|---|
committer | Dan Bungert <[email protected]> | 2024-03-25 10:42:32 -0600 |
commit | 204562c277b096229ca20ba546149deef1d85e38 (patch) | |
tree | 9b115d546122675e3afe002596a7017e5d9278d2 | |
parent | 974c0d0c365fa3068fa1c43e38261189e622e17d (diff) |
block/zfs: flock for ZFS24.0.0
Add flock calls around encrypted ZFS creation areas
LP: #2057661
-rw-r--r-- | curtin/block/zfs.py | 49 | ||||
-rw-r--r-- | tests/unittests/test_block_zfs.py | 14 |
2 files changed, 36 insertions, 27 deletions
diff --git a/curtin/block/zfs.py b/curtin/block/zfs.py index 767ad304..ccdddbb3 100644 --- a/curtin/block/zfs.py +++ b/curtin/block/zfs.py @@ -8,6 +8,7 @@ import os import tempfile import secrets import shutil +from contextlib import ExitStack from pathlib import Path from curtin.config import merge_config @@ -31,11 +32,12 @@ ZFS_UNSUPPORTED_RELEASES = ['precise', 'trusty'] class ZPoolEncryption: - def __init__(self, poolname, style, keyfile): + def __init__(self, vdevs, poolname, style, keyfile): self.poolname = poolname self.style = style self.keyfile = keyfile self.system_key = None + self.vdevs = vdevs def get_system_key(self): if self.system_key is None: @@ -88,24 +90,31 @@ class ZPoolEncryption: self.poolname, "keystore", {"encryption": "off"}, keystore_size, ) - # cryptsetup format and open this keystore - keystore_volume = f"/dev/zvol/{self.poolname}/keystore" - cmd = ["cryptsetup", "luksFormat", keystore_volume, self.keyfile] - util.subp(cmd) - dm_name = f"keystore-{self.poolname}" - cmd = [ - "cryptsetup", "open", "--type", "luks", keystore_volume, dm_name, - "--key-file", self.keyfile, - ] - util.subp(cmd) - - # format as ext4, mount it, move the previously-generated system key - dmpath = f"/dev/mapper/{dm_name}" - cmd = ["mke2fs", "-t", "ext4", dmpath, "-L", dm_name] - util.subp(cmd, capture=True) - - keystore_root = f"/run/keystore/{self.poolname}" - with util.mount(dmpath, keystore_root): + with ExitStack() as es: + for vdev in self.vdevs: + es.enter_context(util.FlockEx(vdev)) + + # cryptsetup format and open this keystore + keystore_volume = f"/dev/zvol/{self.poolname}/keystore" + cmd = ["cryptsetup", "luksFormat", keystore_volume, self.keyfile] + util.subp(cmd) + dm_name = f"keystore-{self.poolname}" + cmd = [ + "cryptsetup", "open", "--type", "luks", keystore_volume, + dm_name, "--key-file", self.keyfile, + ] + util.subp(cmd) + + with ExitStack() as es: + # format as ext4, mount it, move the previously-generated systemkey + dmpath = f"/dev/mapper/{dm_name}" + es.enter_context(util.FlockEx(dmpath)) + cmd = ["mke2fs", "-t", "ext4", dmpath, "-L", dm_name] + util.subp(cmd, capture=True) + + keystore_root = f"/run/keystore/{self.poolname}" + + es.enter_context(util.mount(dmpath, keystore_root)) ks_system_key = f"{keystore_root}/system.key" shutil.move(self.system_key, ks_system_key) Path(ks_system_key).chmod(0o400) @@ -256,7 +265,7 @@ def zpool_create(poolname, vdevs, storage_config=None, context=None, if zfs_properties: merge_config(zfs_cfg, zfs_properties) - encryption = ZPoolEncryption(poolname, encryption_style, keyfile) + encryption = ZPoolEncryption(vdevs, poolname, encryption_style, keyfile) encryption.validate() if encryption.in_use(): merge_config(zfs_cfg, encryption.dataset_properties()) diff --git a/tests/unittests/test_block_zfs.py b/tests/unittests/test_block_zfs.py index ef24b5d3..23dba50f 100644 --- a/tests/unittests/test_block_zfs.py +++ b/tests/unittests/test_block_zfs.py @@ -614,7 +614,7 @@ class TestZfsKeystore(CiTestCase): def test_create_system_key(self, m_token_bytes): m_token_bytes.return_value = key = self.random_string() m_open = mock.mock_open() - zpe = zfs.ZPoolEncryption(None, None, None) + zpe = zfs.ZPoolEncryption(None, None, None, None) with mock.patch("builtins.open", m_open): system_key = zpe.get_system_key() self.assertIsNotNone(system_key) @@ -622,7 +622,7 @@ class TestZfsKeystore(CiTestCase): m_open.return_value.write.assert_called_with(key) def test_validate_good(self): - zpe = zfs.ZPoolEncryption("pool1", "luks_keystore", self.keyfile) + zpe = zfs.ZPoolEncryption(None, "pool1", "luks_keystore", self.keyfile) try: zpe.validate() except Exception: @@ -630,22 +630,22 @@ class TestZfsKeystore(CiTestCase): self.assertTrue(zpe.in_use()) def test_validate_missing_pool(self): - zpe = zfs.ZPoolEncryption(None, "luks_keystore", self.keyfile) + zpe = zfs.ZPoolEncryption(None, None, "luks_keystore", self.keyfile) with self.assertRaises(ValueError): zpe.validate() def test_validate_missing_key(self): - zpe = zfs.ZPoolEncryption("pool1", "luks_keystore", None) + zpe = zfs.ZPoolEncryption(None, "pool1", "luks_keystore", None) with self.assertRaises(ValueError): zpe.validate() def test_validate_missing_key_file(self): - zpe = zfs.ZPoolEncryption("pool1", "luks_keystore", "not-exist") + zpe = zfs.ZPoolEncryption(None, "pool1", "luks_keystore", "not-exist") with self.assertRaises(ValueError): zpe.validate() def test_validate_unencrypted_ok(self): - zpe = zfs.ZPoolEncryption("pool1", None, None) + zpe = zfs.ZPoolEncryption(None, "pool1", None, None) try: zpe.validate() except Exception: @@ -653,7 +653,7 @@ class TestZfsKeystore(CiTestCase): self.assertFalse(zpe.in_use()) def test_dataset_properties(self): - zpe = zfs.ZPoolEncryption("pool1", "luks_keystore", self.keyfile) + zpe = zfs.ZPoolEncryption(None, "pool1", "luks_keystore", self.keyfile) keyloc = self.random_string() with mock.patch.object(zpe, "get_system_key", return_value=keyloc): props = zpe.dataset_properties() |