luks_device: allow passphrases to contain newlines (#844)
* luks_device: allow passphrases to contain newlines This is useful when passing binary keyfiles from an ansible vault, as it removes the restriction that the binary data cannot contain newlines. The only exception is adding a new key to an existing container, as in that case the two passphrases are separated by a new line. * add integration tests and a changelog fragment * attempt to also make luks_add_key work with passphrases containing newlines * use a deterministic method to generate keyfile 3, improve changelog formatting * add licence and copyright to keyfile3.txt to satisfy CIpull/846/head
parent
cb6edf1a5f
commit
2433fdab98
|
@ -0,0 +1,2 @@
|
||||||
|
bugfixes:
|
||||||
|
- luks_device - allow passphrases to contain newlines (https://github.com/ansible-collections/community.crypto/pull/844).
|
|
@ -70,9 +70,6 @@ options:
|
||||||
passphrase_encoding:
|
passphrase_encoding:
|
||||||
description:
|
description:
|
||||||
- Determine how passphrases are provided to parameters such as O(passphrase), O(new_passphrase), and O(remove_passphrase).
|
- Determine how passphrases are provided to parameters such as O(passphrase), O(new_passphrase), and O(remove_passphrase).
|
||||||
- Please note that binary passphrases cannot contain all possible binary octets. For example, a newline (0x0A)
|
|
||||||
cannot be used since it indicates that the passphrase is over. If you want to use arbitrary binary data, you must
|
|
||||||
use keyfiles.
|
|
||||||
type: str
|
type: str
|
||||||
default: text
|
default: text
|
||||||
choices:
|
choices:
|
||||||
|
@ -488,8 +485,6 @@ class Handler(object):
|
||||||
self._module.fail_json("Error while base64-decoding '{parameter_name}': {exc}".format(parameter_name=parameter_name, exc=exc))
|
self._module.fail_json("Error while base64-decoding '{parameter_name}': {exc}".format(parameter_name=parameter_name, exc=exc))
|
||||||
|
|
||||||
def _run_command(self, command, data=None):
|
def _run_command(self, command, data=None):
|
||||||
if data is not None:
|
|
||||||
data += b'\n'
|
|
||||||
return self._module.run_command(command, data=data, binary_data=True)
|
return self._module.run_command(command, data=data, binary_data=True)
|
||||||
|
|
||||||
def get_device_by_uuid(self, uuid):
|
def get_device_by_uuid(self, uuid):
|
||||||
|
@ -635,6 +630,8 @@ class CryptHandler(Handler):
|
||||||
args.extend(['-q', device])
|
args.extend(['-q', device])
|
||||||
if keyfile:
|
if keyfile:
|
||||||
args.append(keyfile)
|
args.append(keyfile)
|
||||||
|
else:
|
||||||
|
args.append('-')
|
||||||
|
|
||||||
result = self._run_command(args, data=passphrase)
|
result = self._run_command(args, data=passphrase)
|
||||||
if result[RETURN_CODE] != 0:
|
if result[RETURN_CODE] != 0:
|
||||||
|
@ -646,6 +643,8 @@ class CryptHandler(Handler):
|
||||||
args = [self._cryptsetup_bin]
|
args = [self._cryptsetup_bin]
|
||||||
if keyfile:
|
if keyfile:
|
||||||
args.extend(['--key-file', keyfile])
|
args.extend(['--key-file', keyfile])
|
||||||
|
else:
|
||||||
|
args.extend(['--key-file', '-'])
|
||||||
if perf_same_cpu_crypt:
|
if perf_same_cpu_crypt:
|
||||||
args.extend(['--perf-same_cpu_crypt'])
|
args.extend(['--perf-same_cpu_crypt'])
|
||||||
if perf_submit_from_crypt_cpus:
|
if perf_submit_from_crypt_cpus:
|
||||||
|
@ -706,14 +705,16 @@ class CryptHandler(Handler):
|
||||||
if keyfile:
|
if keyfile:
|
||||||
args.extend(['--key-file', keyfile])
|
args.extend(['--key-file', keyfile])
|
||||||
else:
|
else:
|
||||||
|
args.extend(['--key-file', '-', '--keyfile-size', str(len(passphrase))])
|
||||||
data.append(passphrase)
|
data.append(passphrase)
|
||||||
|
|
||||||
if new_keyfile:
|
if new_keyfile:
|
||||||
args.append(new_keyfile)
|
args.append(new_keyfile)
|
||||||
else:
|
else:
|
||||||
data.extend([new_passphrase, new_passphrase])
|
args.append('-')
|
||||||
|
data.append(new_passphrase)
|
||||||
|
|
||||||
result = self._run_command(args, data=b'\n'.join(data) or None)
|
result = self._run_command(args, data=b''.join(data) or None)
|
||||||
if result[RETURN_CODE] != 0:
|
if result[RETURN_CODE] != 0:
|
||||||
raise ValueError('Error while adding new LUKS keyslot to %s: %s'
|
raise ValueError('Error while adding new LUKS keyslot to %s: %s'
|
||||||
% (device, result[STDERR]))
|
% (device, result[STDERR]))
|
||||||
|
@ -759,6 +760,8 @@ class CryptHandler(Handler):
|
||||||
args = [self._cryptsetup_bin, 'luksKillSlot', device, '-q', str(keyslot)]
|
args = [self._cryptsetup_bin, 'luksKillSlot', device, '-q', str(keyslot)]
|
||||||
if keyfile:
|
if keyfile:
|
||||||
args.extend(['--key-file', keyfile])
|
args.extend(['--key-file', keyfile])
|
||||||
|
else:
|
||||||
|
args.extend(['--key-file', '-'])
|
||||||
result = self._run_command(args, data=passphrase)
|
result = self._run_command(args, data=passphrase)
|
||||||
if result[RETURN_CODE] != 0:
|
if result[RETURN_CODE] != 0:
|
||||||
raise ValueError('Error while removing LUKS key from %s: %s'
|
raise ValueError('Error while removing LUKS key from %s: %s'
|
||||||
|
@ -774,6 +777,7 @@ class CryptHandler(Handler):
|
||||||
if keyfile:
|
if keyfile:
|
||||||
args.extend(['--key-file', keyfile])
|
args.extend(['--key-file', keyfile])
|
||||||
else:
|
else:
|
||||||
|
args.extend(['--key-file', '-'])
|
||||||
data = passphrase
|
data = passphrase
|
||||||
|
|
||||||
if keyslot is not None:
|
if keyslot is not None:
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
SPDX-FileCopyrightText: Ansible Project
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Copyright (c) Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
generated with:
|
||||||
|
|
||||||
|
dd if=/dev/zero of=/dev/stdout bs=1 count=4096 | openssl enc -aes-256-ctr -pass pass:1234 -nosalt
|
|
@ -0,0 +1,105 @@
|
||||||
|
---
|
||||||
|
# Copyright (c) Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
- name: Create with keyfile3
|
||||||
|
luks_device:
|
||||||
|
device: "{{ cryptfile_device }}"
|
||||||
|
state: closed
|
||||||
|
passphrase: "{{ keyfile3 }}"
|
||||||
|
passphrase_encoding: base64
|
||||||
|
type: luks2
|
||||||
|
pbkdf:
|
||||||
|
iteration_time: 0.1
|
||||||
|
algorithm: argon2i
|
||||||
|
memory: 1000
|
||||||
|
parallel: 1
|
||||||
|
sector_size: 1024
|
||||||
|
become: true
|
||||||
|
ignore_errors: true
|
||||||
|
register: create_passphrase_1
|
||||||
|
|
||||||
|
- name: Create with keyfile3 (without argon2i)
|
||||||
|
luks_device:
|
||||||
|
device: "{{ cryptfile_device }}"
|
||||||
|
state: closed
|
||||||
|
passphrase: "{{ keyfile3 }}"
|
||||||
|
passphrase_encoding: base64
|
||||||
|
pbkdf:
|
||||||
|
iteration_time: 0.1
|
||||||
|
become: true
|
||||||
|
when: create_passphrase_1 is failed
|
||||||
|
|
||||||
|
- name: Open with keyfile3
|
||||||
|
luks_device:
|
||||||
|
device: "{{ cryptfile_device }}"
|
||||||
|
state: opened
|
||||||
|
passphrase: "{{ keyfile3 }}"
|
||||||
|
passphrase_encoding: base64
|
||||||
|
become: true
|
||||||
|
ignore_errors: true
|
||||||
|
register: open_try
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- open_try is not failed
|
||||||
|
- name: Close
|
||||||
|
luks_device:
|
||||||
|
device: "{{ cryptfile_device }}"
|
||||||
|
state: closed
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Try to open with passphrase1
|
||||||
|
luks_device:
|
||||||
|
device: "{{ cryptfile_device }}"
|
||||||
|
state: opened
|
||||||
|
passphrase: "{{ cryptfile_passphrase1 }}"
|
||||||
|
become: true
|
||||||
|
ignore_errors: true
|
||||||
|
register: open_try
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- open_try is failed
|
||||||
|
|
||||||
|
- name: Give access to passphrase1
|
||||||
|
luks_device:
|
||||||
|
device: "{{ cryptfile_device }}"
|
||||||
|
state: closed
|
||||||
|
passphrase: "{{ keyfile3 }}"
|
||||||
|
passphrase_encoding: base64
|
||||||
|
new_passphrase: "{{ cryptfile_passphrase1 | b64encode }}"
|
||||||
|
pbkdf:
|
||||||
|
iteration_time: 0.1
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Remove access for keyfile3
|
||||||
|
luks_device:
|
||||||
|
device: "{{ cryptfile_device }}"
|
||||||
|
state: closed
|
||||||
|
remove_passphrase: "{{ keyfile3 }}"
|
||||||
|
passphrase_encoding: base64
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Try to open with keyfile3
|
||||||
|
luks_device:
|
||||||
|
device: "{{ cryptfile_device }}"
|
||||||
|
state: opened
|
||||||
|
passphrase: "{{ keyfile3 }}"
|
||||||
|
become: true
|
||||||
|
ignore_errors: true
|
||||||
|
register: open_try
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- open_try is failed
|
||||||
|
|
||||||
|
- name: Open with passphrase1
|
||||||
|
luks_device:
|
||||||
|
device: "{{ cryptfile_device }}"
|
||||||
|
state: opened
|
||||||
|
passphrase: "{{ cryptfile_passphrase1 }}"
|
||||||
|
become: true
|
||||||
|
ignore_errors: true
|
||||||
|
register: open_try
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- open_try is not failed
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
# Copyright (c) Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
keyfile3: "{{ lookup('ansible.builtin.file', 'keyfile3', lstrip=False, rstrip=False) | b64encode }}"
|
Loading…
Reference in New Issue