From 2acfa0e08cf27400282f87e6b1b1cfdbcbc103a3 Mon Sep 17 00:00:00 2001 From: Hans Jerry Illikainen Date: Sat, 30 Nov 2019 19:50:30 +0000 Subject: [PATCH] Add passphrase support for luks_device (#65050) * Elevate privileges for luks_device integration tests Several tests in `key-management.yml` don't `become` before executing, despite needing elevated privileges. This commit fixes that. * Add passphrase support for luks_device Previously, the luks_device module only worked with keyfiles. The implication was that the key had to be written to disk before the module could be used. This commit implements support for opening, adding and removing passphrases supplied as strings to the module. Closes #52408 --- changelogs/fragments/52408-luks-device.yaml | 2 + lib/ansible/modules/crypto/luks_device.py | 175 +++++++++++++---- .../targets/luks_device/tasks/main.yml | 3 + .../tasks/tests/key-management.yml | 6 + .../luks_device/tasks/tests/options.yml | 10 + .../luks_device/tasks/tests/passphrase.yml | 181 ++++++++++++++++++ test/units/modules/crypto/test_luks_device.py | 129 ++++++++----- 7 files changed, 421 insertions(+), 85 deletions(-) create mode 100644 changelogs/fragments/52408-luks-device.yaml create mode 100644 test/integration/targets/luks_device/tasks/tests/passphrase.yml diff --git a/changelogs/fragments/52408-luks-device.yaml b/changelogs/fragments/52408-luks-device.yaml new file mode 100644 index 0000000000..3ab3b8d6a3 --- /dev/null +++ b/changelogs/fragments/52408-luks-device.yaml @@ -0,0 +1,2 @@ +minor_changes: + - luks_device - accept ``passphrase``, ``new_passphrase`` and ``remove_passphrase``. diff --git a/lib/ansible/modules/crypto/luks_device.py b/lib/ansible/modules/crypto/luks_device.py index d5a2190471..3b895db757 100644 --- a/lib/ansible/modules/crypto/luks_device.py +++ b/lib/ansible/modules/crypto/luks_device.py @@ -20,7 +20,7 @@ version_added: "2.8" description: - "Module manages L(LUKS,https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup) on given device. Supports creating, destroying, opening and closing of - LUKS container and adding or removing new keys." + LUKS container and adding or removing new keys and passphrases." options: device: @@ -34,19 +34,22 @@ options: - "Desired state of the LUKS container. Based on its value creates, destroys, opens or closes the LUKS container on a given device." - "I(present) will create LUKS container unless already present. - Requires I(device) and I(keyfile) options to be provided." + Requires I(device) and either I(keyfile) or I(passphrase) options + to be provided." - "I(absent) will remove existing LUKS container if it exists. Requires I(device) or I(name) to be specified." - "I(opened) will unlock the LUKS container. If it does not exist it will be created first. - Requires I(device) and I(keyfile) to be specified. Use - the I(name) option to set the name of the opened container. - Otherwise the name will be generated automatically and returned - as a part of the result." + Requires I(device) and either I(keyfile) or I(passphrase) + to be specified. Use the I(name) option to set the name of + the opened container. Otherwise the name will be + generated automatically and returned as a part of the + result." - "I(closed) will lock the LUKS container. However if the container does not exist it will be created. - Requires I(device) and I(keyfile) options to be provided. If - container does already exist I(device) or I(name) will suffice." + Requires I(device) and either I(keyfile) or I(passphrase) + options to be provided. If container does already exist + I(device) or I(name) will suffice." type: str default: present choices: [present, absent, opened, closed] @@ -58,12 +61,19 @@ options: type: str keyfile: description: - - "Used to unlock the container and needed for most - of the operations. Parameter value is the path - to the keyfile with the passphrase." + - "Used to unlock the container. Either a I(keyfile) or a + I(passphrase) is needed for most of the operations. Parameter + value is the path to the keyfile with the passphrase." - "BEWARE that working with keyfiles in plaintext is dangerous. Make sure that they are protected." type: path + passphrase: + description: + - "Used to unlock the container. Either a I(passphrase) or a + I(keyfile) is needed for most of the operations. Parameter + value is a string with the passphrase." + type: str + version_added: '2.10' keysize: description: - "Sets the key size only if LUKS container does not exist." @@ -72,27 +82,50 @@ options: new_keyfile: description: - "Adds additional key to given container on I(device). - Needs I(keyfile) option for authorization. LUKS container - supports up to 8 keys. Parameter value is the path - to the keyfile with the passphrase." - - "NOTE that adding additional keys is I(not idempotent). + Needs I(keyfile) or I(passphrase) option for authorization. + LUKS container supports up to 8 keyslots. Parameter value + is the path to the keyfile with the passphrase." + - "NOTE that adding additional keys is *not idempotent*. A new keyslot will be used even if another keyslot already exists for this keyfile." - "BEWARE that working with keyfiles in plaintext is dangerous. Make sure that they are protected." type: path + new_passphrase: + description: + - "Adds additional passphrase to given container on I(device). + Needs I(keyfile) or I(passphrase) option for authorization. LUKS + container supports up to 8 keyslots. Parameter value is a string + with the new passphrase." + - "NOTE that adding additional passphrase is *not idempotent*. A + new keyslot will be used even if another keyslot already exists + for this passphrase." + type: str + version_added: '2.10' remove_keyfile: description: - "Removes given key from the container on I(device). Does not remove the keyfile from filesystem. Parameter value is the path to the keyfile with the passphrase." - - "NOTE that removing keys is I(not idempotent). Trying to remove + - "NOTE that removing keys is *not idempotent*. Trying to remove a key which no longer exists results in an error." - "NOTE that to remove the last key from a LUKS container, the I(force_remove_last_key) option must be set to C(yes)." - "BEWARE that working with keyfiles in plaintext is dangerous. Make sure that they are protected." type: path + remove_passphrase: + description: + - "Removes given passphrase from the container on I(device). + Parameter value is a string with the passphrase to remove." + - "NOTE that removing passphrases is I(not + idempotent). Trying to remove a passphrase which no longer + exists results in an error." + - "NOTE that to remove the last keyslot from a LUKS + container, the I(force_remove_last_key) option must be set + to C(yes)." + type: str + version_added: '2.10' force_remove_last_key: description: - "If set to C(yes), allows removing the last key from a container." @@ -143,6 +176,12 @@ EXAMPLES = ''' state: "present" keyfile: "/vault/keyfile" +- name: create LUKS container with a passphrase + luks_device: + device: "/dev/loop0" + state: "present" + passphrase: "foo" + - name: (create and) open the LUKS container; name it "mycrypt" luks_device: device: "/dev/loop0" @@ -174,11 +213,22 @@ EXAMPLES = ''' keyfile: "/vault/keyfile" new_keyfile: "/vault/keyfile2" -- name: remove existing key from the LUKS container +- name: add new passphrase to the LUKS container + luks_device: + device: "/dev/loop0" + keyfile: "/vault/keyfile" + new_passphrase: "foo" + +- name: remove existing keyfile from the LUKS container luks_device: device: "/dev/loop0" remove_keyfile: "/vault/keyfile2" +- name: remove existing passphrase from the LUKS container + luks_device: + device: "/dev/loop0" + remove_passphrase: "foo" + - name: completely remove the LUKS container and its contents luks_device: device: "/dev/loop0" @@ -246,8 +296,8 @@ class Handler(object): self._module = module self._lsblk_bin = self._module.get_bin_path('lsblk', True) - def _run_command(self, command): - return self._module.run_command(command) + def _run_command(self, command, data=None): + return self._module.run_command(command, data=data) def get_device_by_uuid(self, uuid): ''' Returns the device that holds UUID passed by user @@ -330,7 +380,7 @@ class CryptHandler(Handler): result = self._run_command([self._cryptsetup_bin, 'isLuks', device]) return result[RETURN_CODE] == 0 - def run_luks_create(self, device, keyfile, keysize): + def run_luks_create(self, device, keyfile, passphrase, keysize): # create a new luks container; use batch mode to auto confirm luks_type = self._module.params['type'] label = self._module.params['label'] @@ -346,16 +396,22 @@ class CryptHandler(Handler): args = [self._cryptsetup_bin, 'luksFormat'] args.extend(options) - args.extend(['-q', device, keyfile]) + args.extend(['-q', device]) + if keyfile: + args.append(keyfile) - result = self._run_command(args) + result = self._run_command(args, data=passphrase) if result[RETURN_CODE] != 0: raise ValueError('Error while creating LUKS on %s: %s' % (device, result[STDERR])) - def run_luks_open(self, device, keyfile, name): - result = self._run_command([self._cryptsetup_bin, '--key-file', keyfile, - 'open', '--type', 'luks', device, name]) + def run_luks_open(self, device, keyfile, passphrase, name): + args = [self._cryptsetup_bin] + if keyfile: + args.extend(['--key-file', keyfile]) + args.extend(['open', '--type', 'luks', device, name]) + + result = self._run_command(args, data=passphrase) if result[RETURN_CODE] != 0: raise ValueError('Error while opening LUKS container on %s: %s' % (device, result[STDERR])) @@ -376,17 +432,32 @@ class CryptHandler(Handler): raise ValueError('Error while wiping luks container %s: %s' % (device, result[STDERR])) - def run_luks_add_key(self, device, keyfile, new_keyfile): - ''' Add new key to given 'device'; authentication done using 'keyfile' - Raises ValueError when command fails + def run_luks_add_key(self, device, keyfile, passphrase, new_keyfile, + new_passphrase): + ''' Add new key from a keyfile or passphrase to given 'device'; + authentication done using 'keyfile' or 'passphrase'. + Raises ValueError when command fails. ''' - result = self._run_command([self._cryptsetup_bin, 'luksAddKey', device, - new_keyfile, '--key-file', keyfile]) + data = [] + args = [self._cryptsetup_bin, 'luksAddKey', device] + + if keyfile: + args.extend(['--key-file', keyfile]) + else: + data.append(passphrase) + + if new_keyfile: + args.append(new_keyfile) + else: + data.extend([new_passphrase, new_passphrase]) + + result = self._run_command(args, data='\n'.join(data) or None) if result[RETURN_CODE] != 0: - raise ValueError('Error while adding new LUKS key to %s: %s' + raise ValueError('Error while adding new LUKS keyslot to %s: %s' % (device, result[STDERR])) - def run_luks_remove_key(self, device, keyfile, force_remove_last_key=False): + def run_luks_remove_key(self, device, keyfile, passphrase, + force_remove_last_key=False): ''' Remove key from given device Raises ValueError when command fails ''' @@ -420,8 +491,10 @@ class CryptHandler(Handler): "To be able to remove a key, please set " "`force_remove_last_key` to `yes`." % device) - result = self._run_command([self._cryptsetup_bin, 'luksRemoveKey', device, - '-q', '--key-file', keyfile]) + args = [self._cryptsetup_bin, 'luksRemoveKey', device, '-q'] + if keyfile: + args.extend(['--key-file', keyfile]) + result = self._run_command(args, data=passphrase) if result[RETURN_CODE] != 0: raise ValueError('Error while removing LUKS key from %s: %s' % (device, result[STDERR])) @@ -451,7 +524,8 @@ class ConditionsHandler(Handler): def luks_create(self): return (self.device is not None and - self._module.params['keyfile'] is not None and + (self._module.params['keyfile'] is not None or + self._module.params['passphrase'] is not None) and self._module.params['state'] in ('present', 'opened', 'closed') and @@ -487,7 +561,8 @@ class ConditionsHandler(Handler): return name def luks_open(self): - if (self._module.params['keyfile'] is None or + if ((self._module.params['keyfile'] is None and + self._module.params['passphrase'] is None) or self.device is None or self._module.params['state'] != 'opened'): # conditions for open not fulfilled @@ -520,8 +595,10 @@ class ConditionsHandler(Handler): def luks_add_key(self): if (self.device is None or - self._module.params['keyfile'] is None or - self._module.params['new_keyfile'] is None): + (self._module.params['keyfile'] is None and + self._module.params['passphrase'] is None) or + (self._module.params['new_keyfile'] is None and + self._module.params['new_passphrase'] is None)): # conditions for adding a key not fulfilled return False @@ -533,7 +610,8 @@ class ConditionsHandler(Handler): def luks_remove_key(self): if (self.device is None or - self._module.params['remove_keyfile'] is None): + (self._module.params['remove_keyfile'] is None and + self._module.params['remove_passphrase'] is None)): # conditions for removing a key not fulfilled return False @@ -558,6 +636,9 @@ def run_module(): keyfile=dict(type='path'), new_keyfile=dict(type='path'), remove_keyfile=dict(type='path'), + passphrase=dict(type='str', no_log=True), + new_passphrase=dict(type='str', no_log=True), + remove_passphrase=dict(type='str', no_log=True), force_remove_last_key=dict(type='bool', default=False), keysize=dict(type='int'), label=dict(type='str'), @@ -565,6 +646,12 @@ def run_module(): type=dict(type='str', choices=['luks1', 'luks2']), ) + mutually_exclusive = [ + ('keyfile', 'passphrase'), + ('new_keyfile', 'new_passphrase'), + ('remove_keyfile', 'remove_passphrase') + ] + # seed the result dict in the object result = dict( changed=False, @@ -572,7 +659,8 @@ def run_module(): ) module = AnsibleModule(argument_spec=module_args, - supports_check_mode=True) + supports_check_mode=True, + mutually_exclusive=mutually_exclusive) if module.params['device'] is not None: try: @@ -599,6 +687,7 @@ def run_module(): try: crypt.run_luks_create(conditions.device, module.params['keyfile'], + module.params['passphrase'], module.params['keysize']) except ValueError as e: module.fail_json(msg="luks_device error: %s" % e) @@ -623,6 +712,7 @@ def run_module(): try: crypt.run_luks_open(conditions.device, module.params['keyfile'], + module.params['passphrase'], name) except ValueError as e: module.fail_json(msg="luks_device error: %s" % e) @@ -657,7 +747,9 @@ def run_module(): try: crypt.run_luks_add_key(conditions.device, module.params['keyfile'], - module.params['new_keyfile']) + module.params['passphrase'], + module.params['new_keyfile'], + module.params['new_passphrase']) except ValueError as e: module.fail_json(msg="luks_device error: %s" % e) result['changed'] = True @@ -671,6 +763,7 @@ def run_module(): last_key = module.params['force_remove_last_key'] crypt.run_luks_remove_key(conditions.device, module.params['remove_keyfile'], + module.params['remove_passphrase'], force_remove_last_key=last_key) except ValueError as e: module.fail_json(msg="luks_device error: %s" % e) diff --git a/test/integration/targets/luks_device/tasks/main.yml b/test/integration/targets/luks_device/tasks/main.yml index 9793704581..d3ca75b637 100644 --- a/test/integration/targets/luks_device/tasks/main.yml +++ b/test/integration/targets/luks_device/tasks/main.yml @@ -15,6 +15,9 @@ register: cryptfile_device_output - set_fact: cryptfile_device: "{{ cryptfile_device_output.stdout_lines[1] }}" + cryptfile_passphrase1: "uNiJ9vKG2mUOEWDiQVuBHJlfMHE" + cryptfile_passphrase2: "HW4Ak2HtE2vvne0qjJMPTtmbV4M" + cryptfile_passphrase3: "qQJqsjabO9pItV792k90VvX84MM" - block: - include_tasks: run-test.yml with_fileglob: diff --git a/test/integration/targets/luks_device/tasks/tests/key-management.yml b/test/integration/targets/luks_device/tasks/tests/key-management.yml index 1866a46dbc..b89d505fa6 100644 --- a/test/integration/targets/luks_device/tasks/tests/key-management.yml +++ b/test/integration/targets/luks_device/tasks/tests/key-management.yml @@ -23,6 +23,7 @@ luks_device: device: "{{ cryptfile_device }}" state: closed + become: yes - name: Try to open with keyfile2 luks_device: @@ -61,9 +62,11 @@ luks_device: device: "{{ cryptfile_device }}" state: closed + become: yes - name: Dump LUKS header command: "cryptsetup luksDump {{ cryptfile_device }}" + become: yes - name: Remove access from keyfile1 luks_device: @@ -102,9 +105,11 @@ luks_device: device: "{{ cryptfile_device }}" state: closed + become: yes - name: Dump LUKS header command: "cryptsetup luksDump {{ cryptfile_device }}" + become: yes - name: Remove access from keyfile2 luks_device: @@ -137,6 +142,7 @@ luks_device: device: "{{ cryptfile_device }}" state: closed + become: yes - name: Remove access from keyfile2 luks_device: diff --git a/test/integration/targets/luks_device/tasks/tests/options.yml b/test/integration/targets/luks_device/tasks/tests/options.yml index 31d16d3b8d..afee6667d6 100644 --- a/test/integration/targets/luks_device/tasks/tests/options.yml +++ b/test/integration/targets/luks_device/tasks/tests/options.yml @@ -23,9 +23,19 @@ keysize: 512 become: yes register: create_idem_with_diff_keysize +- name: Create with ambiguous arguments + luks_device: + device: "{{ cryptfile_device }}" + state: present + keyfile: "{{ role_path }}/files/keyfile1" + passphrase: "{{ cryptfile_passphrase1 }}" + ignore_errors: yes + become: yes + register: create_with_ambiguous - assert: that: - create_with_keysize is changed - create_idem_with_keysize is not changed - create_idem_with_diff_keysize is not changed + - create_with_ambiguous is failed diff --git a/test/integration/targets/luks_device/tasks/tests/passphrase.yml b/test/integration/targets/luks_device/tasks/tests/passphrase.yml new file mode 100644 index 0000000000..560915252f --- /dev/null +++ b/test/integration/targets/luks_device/tasks/tests/passphrase.yml @@ -0,0 +1,181 @@ +--- +- name: Create with passphrase1 + luks_device: + device: "{{ cryptfile_device }}" + state: closed + passphrase: "{{ cryptfile_passphrase1 }}" + become: yes + +- name: Open with passphrase1 + luks_device: + device: "{{ cryptfile_device }}" + state: opened + passphrase: "{{ cryptfile_passphrase1 }}" + become: yes + ignore_errors: yes + register: open_try +- assert: + that: + - open_try is not failed +- name: Close + luks_device: + device: "{{ cryptfile_device }}" + state: closed + become: yes + +- name: Give access with ambiguous new_ arguments + luks_device: + device: "{{ cryptfile_device }}" + state: closed + passphrase: "{{ cryptfile_passphrase1 }}" + new_passphrase: "{{ cryptfile_passphrase2 }}" + new_keyfile: "{{ role_path }}/files/keyfile1" + become: yes + ignore_errors: yes + register: new_try +- assert: + that: + - new_try is failed + +- name: Try to open with passphrase2 + luks_device: + device: "{{ cryptfile_device }}" + state: opened + passphrase: "{{ cryptfile_passphrase2 }}" + become: yes + ignore_errors: yes + register: open_try +- assert: + that: + - open_try is failed + +- name: Give access to passphrase2 + luks_device: + device: "{{ cryptfile_device }}" + state: closed + passphrase: "{{ cryptfile_passphrase1 }}" + new_passphrase: "{{ cryptfile_passphrase2 }}" + become: yes + +- name: Open with passphrase2 + luks_device: + device: "{{ cryptfile_device }}" + state: opened + passphrase: "{{ cryptfile_passphrase2 }}" + become: yes + ignore_errors: yes + register: open_try +- assert: + that: + - open_try is not failed +- name: Close + luks_device: + device: "{{ cryptfile_device }}" + state: closed + become: yes + +- name: Try to open with keyfile1 + luks_device: + device: "{{ cryptfile_device }}" + state: opened + keyfile: "{{ role_path }}/files/keyfile1" + become: yes + ignore_errors: yes + register: open_try +- assert: + that: + - open_try is failed + +- name: Give access to keyfile1 from passphrase1 + luks_device: + device: "{{ cryptfile_device }}" + state: closed + passphrase: "{{ cryptfile_passphrase1 }}" + new_keyfile: "{{ role_path }}/files/keyfile1" + become: yes + +- name: Remove access with ambiguous remove_ arguments + luks_device: + device: "{{ cryptfile_device }}" + state: closed + remove_keyfile: "{{ role_path }}/files/keyfile1" + remove_passphrase: "{{ cryptfile_passphrase1 }}" + become: yes + ignore_errors: yes + register: remove_try +- assert: + that: + - remove_try is failed + +- name: Open with keyfile1 + luks_device: + device: "{{ cryptfile_device }}" + state: opened + keyfile: "{{ role_path }}/files/keyfile1" + become: yes + ignore_errors: yes + register: open_try +- assert: + that: + - open_try is not failed +- name: Close + luks_device: + device: "{{ cryptfile_device }}" + state: closed + become: yes + +- name: Remove access for passphrase1 + luks_device: + device: "{{ cryptfile_device }}" + state: closed + remove_passphrase: "{{ cryptfile_passphrase1 }}" + become: yes + +- name: Try to open with passphrase1 + luks_device: + device: "{{ cryptfile_device }}" + state: opened + passphrase: "{{ cryptfile_passphrase1 }}" + become: yes + ignore_errors: yes + register: open_try +- assert: + that: + - open_try is failed + +- name: Try to open with passphrase3 + luks_device: + device: "{{ cryptfile_device }}" + state: opened + passphrase: "{{ cryptfile_passphrase3 }}" + become: yes + ignore_errors: yes + register: open_try +- assert: + that: + - open_try is failed + +- name: Give access to passphrase3 from keyfile1 + luks_device: + device: "{{ cryptfile_device }}" + state: closed + keyfile: "{{ role_path }}/files/keyfile1" + new_passphrase: "{{ cryptfile_passphrase3 }}" + become: yes + +- name: Open with passphrase3 + luks_device: + device: "{{ cryptfile_device }}" + state: opened + passphrase: "{{ cryptfile_passphrase3 }}" + become: yes + ignore_errors: yes + register: open_try +- assert: + that: + - open_try is not failed +- name: Close + luks_device: + device: "{{ cryptfile_device }}" + state: closed + become: yes diff --git a/test/units/modules/crypto/test_luks_device.py b/test/units/modules/crypto/test_luks_device.py index 025b0d1a3c..e6449814a0 100644 --- a/test/units/modules/crypto/test_luks_device.py +++ b/test/units/modules/crypto/test_luks_device.py @@ -64,16 +64,24 @@ def test_run_luks_remove(monkeypatch): # ===== ConditionsHandler methods data and tests ===== -# device, key, state, is_luks, label, expected +# device, key, passphrase, state, is_luks, label, expected LUKS_CREATE_DATA = ( - ("dummy", "key", "present", False, None, True), - (None, "key", "present", False, None, False), - (None, "key", "present", False, "labelName", True), - ("dummy", None, "present", False, None, False), - ("dummy", "key", "absent", False, None, False), - ("dummy", "key", "opened", True, None, False), - ("dummy", "key", "closed", True, None, False), - ("dummy", "key", "present", True, None, False)) + ("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)) # device, state, is_luks, expected LUKS_REMOVE_DATA = ( @@ -82,16 +90,24 @@ LUKS_REMOVE_DATA = ( ("dummy", "present", True, False), ("dummy", "absent", False, False)) -# device, key, state, name, name_by_dev, expected +# device, key, passphrase, state, name, name_by_dev, expected LUKS_OPEN_DATA = ( - ("dummy", "key", "present", "name", None, False), - ("dummy", "key", "absent", "name", None, False), - ("dummy", "key", "closed", "name", None, False), - ("dummy", "key", "opened", "name", None, True), - (None, "key", "opened", "name", None, False), - ("dummy", None, "opened", "name", None, False), - ("dummy", "key", "opened", "name", "name", False), - ("dummy", "key", "opened", "beer", "name", "exception")) + ("dummy", "key", None, "present", "name", None, False), + ("dummy", "key", None, "absent", "name", None, False), + ("dummy", "key", None, "closed", "name", None, False), + ("dummy", "key", None, "opened", "name", None, True), + (None, "key", None, "opened", "name", None, False), + ("dummy", None, None, "opened", "name", None, False), + ("dummy", "key", None, "opened", "name", "name", False), + ("dummy", "key", None, "opened", "beer", "name", "exception"), + ("dummy", None, "foo", "present", "name", None, False), + ("dummy", None, "bar", "absent", "name", None, False), + ("dummy", None, "baz", "closed", "name", None, False), + ("dummy", None, "qux", "opened", "name", None, True), + (None, None, "quux", "opened", "name", None, False), + ("dummy", None, None, "opened", "name", None, False), + ("dummy", None, "quuz", "opened", "name", "name", False), + ("dummy", None, "corge", "opened", "beer", "name", "exception")) # device, dev_by_name, name, name_by_dev, state, label, expected LUKS_CLOSE_DATA = ( @@ -103,33 +119,50 @@ LUKS_CLOSE_DATA = ( ("dummy", "dummy", None, "name", "closed", None, True), (None, "dummy", None, "name", "closed", None, False)) -# device, key, new_key, state, label, expected +# device, key, passphrase, new_key, new_passphrase, state, label, expected LUKS_ADD_KEY_DATA = ( - ("dummy", "key", "new_key", "present", None, True), - (None, "key", "new_key", "present", "labelName", True), - (None, "key", "new_key", "present", None, False), - ("dummy", None, "new_key", "present", None, False), - ("dummy", "key", None, "present", None, False), - ("dummy", "key", "new_key", "absent", None, "exception")) + ("dummy", "key", None, "new_key", None, "present", None, True), + (None, "key", None, "new_key", None, "present", "labelName", True), + (None, "key", None, "new_key", None, "present", None, False), + ("dummy", None, None, "new_key", None, "present", None, False), + ("dummy", "key", None, None, None, "present", None, False), + ("dummy", "key", None, "new_key", None, "absent", None, "exception"), + ("dummy", None, "pass", "new_key", None, "present", None, True), + (None, None, "pass", "new_key", None, "present", "labelName", True), + ("dummy", "key", None, None, "new_pass", "present", None, True), + (None, "key", None, None, "new_pass", "present", "labelName", True), + (None, "key", None, None, "new_pass", "present", None, False), + ("dummy", None, None, None, "new_pass", "present", None, False), + ("dummy", "key", None, None, None, "present", None, False), + ("dummy", "key", None, None, "new_pass", "absent", None, "exception"), + ("dummy", None, "pass", None, "new_pass", "present", None, True), + (None, None, "pass", None, "new_pass", "present", "labelName", True)) -# device, remove_key, state, label, expected +# device, remove_key, remove_passphrase, state, label, expected LUKS_REMOVE_KEY_DATA = ( - ("dummy", "key", "present", None, True), - (None, "key", "present", None, False), - (None, "key", "present", "labelName", True), - ("dummy", None, "present", None, False), - ("dummy", "key", "absent", None, "exception")) + ("dummy", "key", None, "present", None, True), + (None, "key", None, "present", None, False), + (None, "key", None, "present", "labelName", True), + ("dummy", None, None, "present", None, False), + ("dummy", "key", None, "absent", None, "exception"), + ("dummy", None, "foo", "present", None, True), + (None, None, "foo", "present", None, False), + (None, None, "foo", "present", "labelName", True), + ("dummy", None, None, "present", None, False), + ("dummy", None, "foo", "absent", None, "exception")) -@pytest.mark.parametrize("device, keyfile, state, is_luks, label, expected", - ((d[0], d[1], d[2], d[3], d[4], d[5]) +@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]) for d in LUKS_CREATE_DATA)) -def test_luks_create(device, keyfile, state, is_luks, label, expected, - monkeypatch): +def test_luks_create(device, keyfile, passphrase, state, is_luks, label, + expected, monkeypatch): module = DummyModule() module.params["device"] = device module.params["keyfile"] = keyfile + module.params["passphrase"] = passphrase module.params["state"] = state module.params["label"] = label @@ -165,15 +198,16 @@ def test_luks_remove(device, state, is_luks, expected, monkeypatch): assert expected == "exception" -@pytest.mark.parametrize("device, keyfile, state, name, " +@pytest.mark.parametrize("device, keyfile, passphrase, state, name, " "name_by_dev, expected", - ((d[0], d[1], d[2], d[3], d[4], d[5]) + ((d[0], d[1], d[2], d[3], d[4], d[5], d[6]) for d in LUKS_OPEN_DATA)) -def test_luks_open(device, keyfile, state, name, name_by_dev, +def test_luks_open(device, keyfile, passphrase, state, name, name_by_dev, expected, monkeypatch): module = DummyModule() module.params["device"] = device module.params["keyfile"] = keyfile + module.params["passphrase"] = passphrase module.params["state"] = state module.params["name"] = name @@ -219,14 +253,18 @@ def test_luks_close(device, dev_by_name, name, name_by_dev, state, assert expected == "exception" -@pytest.mark.parametrize("device, keyfile, new_keyfile, state, label, expected", - ((d[0], d[1], d[2], d[3], d[4], d[5]) +@pytest.mark.parametrize("device, keyfile, passphrase, new_keyfile, " + + "new_passphrase, state, label, expected", + ((d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7]) for d in LUKS_ADD_KEY_DATA)) -def test_luks_add_key(device, keyfile, new_keyfile, state, label, expected, monkeypatch): +def test_luks_add_key(device, keyfile, passphrase, new_keyfile, new_passphrase, + state, label, expected, monkeypatch): module = DummyModule() module.params["device"] = device module.params["keyfile"] = keyfile + module.params["passphrase"] = passphrase module.params["new_keyfile"] = new_keyfile + module.params["new_passphrase"] = new_passphrase module.params["state"] = state module.params["label"] = label @@ -240,14 +278,17 @@ def test_luks_add_key(device, keyfile, new_keyfile, state, label, expected, monk assert expected == "exception" -@pytest.mark.parametrize("device, remove_keyfile, state, label, expected", - ((d[0], d[1], d[2], d[3], d[4]) +@pytest.mark.parametrize("device, remove_keyfile, remove_passphrase, state, " + + "label, expected", + ((d[0], d[1], d[2], d[3], d[4], d[5]) for d in LUKS_REMOVE_KEY_DATA)) -def test_luks_remove_key(device, remove_keyfile, state, label, expected, monkeypatch): +def test_luks_remove_key(device, remove_keyfile, remove_passphrase, state, + label, expected, monkeypatch): module = DummyModule() module.params["device"] = device module.params["remove_keyfile"] = remove_keyfile + module.params["remove_passphrase"] = remove_passphrase module.params["state"] = state module.params["label"] = label