From 5d46ab1444b5a30ba8e32a84985da7a7f50e9786 Mon Sep 17 00:00:00 2001 From: Arnaud SINAYS Date: Tue, 4 Aug 2020 21:36:07 +0200 Subject: [PATCH] Add cipher and hash options to luks_create --- ...device-add_encryption_option_on_create.yml | 2 + plugins/modules/luks_device.py | 36 ++++++++++++++- .../modules/crypto/test_luks_device.py | 45 ++++++++++--------- 3 files changed, 61 insertions(+), 22 deletions(-) create mode 100644 changelogs/fragments/luks_device-add_encryption_option_on_create.yml diff --git a/changelogs/fragments/luks_device-add_encryption_option_on_create.yml b/changelogs/fragments/luks_device-add_encryption_option_on_create.yml new file mode 100644 index 000000000..0e8447538 --- /dev/null +++ b/changelogs/fragments/luks_device-add_encryption_option_on_create.yml @@ -0,0 +1,2 @@ +minor_changes: + - "luks_device - add support for encryption options on container creation (https://github.com/ansible-collections/community.crypto/pull/97)." diff --git a/plugins/modules/luks_device.py b/plugins/modules/luks_device.py index bcba986d0..9dc3292bf 100644 --- a/plugins/modules/luks_device.py +++ b/plugins/modules/luks_device.py @@ -152,6 +152,22 @@ type: str choices: [luks1, luks2] version_added: '1.0.0' + cipher: + description: + - "This option allows the user to define the cipher specification + string for the LUKS container." + - "Will only be used on container creation." + - "For pre-2.6.10 kernels, use C(aes-plain) as they don't understand + the new cipher spec strings. To use ESSIV, use C(aes-cbc-essiv:sha256)." + type: str + version_added: '1.1.0' + hash: + description: + - "This option allows the user to specify the hash function used in LUKS + key setup scheme and volume key digest." + - "Will only be used on container creation." + type: str + version_added: '1.1.0' requirements: - "cryptsetup" @@ -176,6 +192,13 @@ state: "present" passphrase: "foo" +- name: Create LUKS container with specific encryption + community.crypto.luks_device: + device: "/dev/loop0" + state: "present" + cipher: "aes" + hash: "sha256" + - name: (Create and) open the LUKS container; name it "mycrypt" community.crypto.luks_device: device: "/dev/loop0" @@ -374,7 +397,7 @@ def is_luks(self, device): result = self._run_command([self._cryptsetup_bin, 'isLuks', device]) return result[RETURN_CODE] == 0 - def run_luks_create(self, device, keyfile, passphrase, keysize): + def run_luks_create(self, device, keyfile, passphrase, keysize, cipher, hash_): # create a new luks container; use batch mode to auto confirm luks_type = self._module.params['type'] label = self._module.params['label'] @@ -387,6 +410,10 @@ def run_luks_create(self, device, keyfile, passphrase, keysize): luks_type = 'luks2' if luks_type is not None: options.extend(['--type', luks_type]) + if cipher is not None: + options.extend(['--cipher', cipher]) + if hash_ is not None: + options.extend(['--hash', hash_]) args = [self._cryptsetup_bin, 'luksFormat'] args.extend(options) @@ -638,6 +665,8 @@ def run_module(): label=dict(type='str'), uuid=dict(type='str'), type=dict(type='str', choices=['luks1', 'luks2']), + cipher=dict(type='str'), + hash=dict(type='str'), ) mutually_exclusive = [ @@ -682,7 +711,10 @@ def run_module(): crypt.run_luks_create(conditions.device, module.params['keyfile'], module.params['passphrase'], - module.params['keysize']) + module.params['keysize'], + module.params['cipher'], + module.params['hash'], + ) except ValueError as e: module.fail_json(msg="luks_device error: %s" % e) result['changed'] = True diff --git a/tests/unit/plugins/modules/crypto/test_luks_device.py b/tests/unit/plugins/modules/crypto/test_luks_device.py index 835bba61e..7a12aaf59 100644 --- a/tests/unit/plugins/modules/crypto/test_luks_device.py +++ b/tests/unit/plugins/modules/crypto/test_luks_device.py @@ -64,24 +64,27 @@ def run_command_check(self, command): # ===== ConditionsHandler methods data and tests ===== -# device, key, passphrase, state, is_luks, label, expected +# device, key, passphrase, state, is_luks, label, cipher, hash, expected LUKS_CREATE_DATA = ( - ("dummy", "key", None, "present", False, None, True), - (None, "key", None, "present", False, None, False), - (None, "key", None, "present", False, "labelName", True), - ("dummy", None, None, "present", False, None, False), - ("dummy", "key", None, "absent", False, None, False), - ("dummy", "key", None, "opened", True, None, False), - ("dummy", "key", None, "closed", True, None, False), - ("dummy", "key", None, "present", True, None, False), - ("dummy", None, "foo", "present", False, None, True), - (None, None, "bar", "present", False, None, False), - (None, None, "baz", "present", False, "labelName", True), - ("dummy", None, None, "present", False, None, False), - ("dummy", None, "quz", "absent", False, None, False), - ("dummy", None, "qux", "opened", True, None, False), - ("dummy", None, "quux", "closed", True, None, False), - ("dummy", None, "corge", "present", True, None, False)) + ("dummy", "key", None, "present", False, None, "dummy", "dummy", True), + (None, "key", None, "present", False, None, "dummy", "dummy", False), + (None, "key", None, "present", False, "labelName", "dummy", "dummy", True), + ("dummy", None, None, "present", False, None, "dummy", "dummy", False), + ("dummy", "key", None, "absent", False, None, "dummy", "dummy", False), + ("dummy", "key", None, "opened", True, None, "dummy", "dummy", False), + ("dummy", "key", None, "closed", True, None, "dummy", "dummy", False), + ("dummy", "key", None, "present", True, None, "dummy", "dummy", False), + ("dummy", None, "foo", "present", False, None, "dummy", "dummy", True), + (None, None, "bar", "present", False, None, "dummy", "dummy", False), + (None, None, "baz", "present", False, "labelName", "dummy", "dummy", True), + ("dummy", None, None, "present", False, None, "dummy", "dummy", False), + ("dummy", None, "quz", "absent", False, None, "dummy", "dummy", False), + ("dummy", None, "qux", "opened", True, None, "dummy", "dummy", False), + ("dummy", None, "quux", "closed", True, None, "dummy", "dummy", False), + ("dummy", None, "corge", "present", True, None, "dummy", "dummy", False), + ("dummy", "key", None, "present", False, None, None, None, True), + ("dummy", "key", None, "present", False, None, None, "dummy", True), + ("dummy", "key", None, "present", False, None, "dummy", None, True)) # device, state, is_luks, expected LUKS_REMOVE_DATA = ( @@ -153,10 +156,10 @@ def run_command_check(self, command): @pytest.mark.parametrize("device, keyfile, passphrase, state, is_luks, " + - "label, expected", - ((d[0], d[1], d[2], d[3], d[4], d[5], d[6]) + "label, cipher, hash_, expected", + ((d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8]) for d in LUKS_CREATE_DATA)) -def test_luks_create(device, keyfile, passphrase, state, is_luks, label, +def test_luks_create(device, keyfile, passphrase, state, is_luks, label, cipher, hash_, expected, monkeypatch): module = DummyModule() @@ -165,6 +168,8 @@ def test_luks_create(device, keyfile, passphrase, state, is_luks, label, module.params["passphrase"] = passphrase module.params["state"] = state module.params["label"] = label + module.params["cipher"] = cipher + module.params["hash"] = hash_ monkeypatch.setattr(luks_device.CryptHandler, "is_luks", lambda x, y: is_luks)