diff --git a/roles/configuration/tasks/encryption.yml b/roles/configuration/tasks/encryption.yml new file mode 100644 index 0000000..59aa257 --- /dev/null +++ b/roles/configuration/tasks/encryption.yml @@ -0,0 +1,365 @@ +--- +- name: Configure disk encryption + when: partitioning_luks_enabled | default(luks_enabled | default(false)) | bool + vars: + configuration_luks_passphrase_effective: >- + {{ (partitioning_luks_passphrase | default(luks_passphrase | default(''))) | string }} + block: + - name: Set LUKS configuration facts + vars: + configuration_luks_mapper_name_value: >- + {{ + partitioning_luks_mapper_name + | default(luks_mapper_name | default('SYSTEM_DECRYPTED')) + }} + configuration_luks_device_value: >- + {{ + partitioning_luks_device + | default( + install_drive + ~ (partitioning_main_partition_suffix | default(2) | string) + ) + }} + configuration_luks_tpm2_pcrs_raw: >- + {{ partitioning_luks_tpm2_pcrs | default(luks_tpm2_pcrs | default('')) }} + configuration_luks_tpm2_pcrs_effective_value: >- + {{ + ( + configuration_luks_tpm2_pcrs_raw + if configuration_luks_tpm2_pcrs_raw is string + else (configuration_luks_tpm2_pcrs_raw | map('string') | join('+')) + ) + | string + | replace(',', '+') + | regex_replace('\\s+', '') + | regex_replace('^\\+|\\+$', '') + }} + ansible.builtin.set_fact: + configuration_luks_mapper_name: "{{ configuration_luks_mapper_name_value }}" + configuration_luks_uuid: "{{ partitioning_luks_uuid | default('') }}" + configuration_luks_device: "{{ configuration_luks_device_value }}" + configuration_luks_options: >- + {{ partitioning_luks_options | default(luks_options | default('discard,tries=3')) }} + configuration_luks_auto_method: >- + {{ + (partitioning_luks_auto_decrypt | default(luks_auto_decrypt | default(true)) | bool) + | ternary( + partitioning_luks_auto_decrypt_method | default(luks_auto_decrypt_method | default('tpm2')), + 'manual' + ) + }} + configuration_luks_tpm2_device: >- + {{ partitioning_luks_tpm2_device | default(luks_tpm2_device | default('auto')) }} + configuration_luks_tpm2_pcrs: "{{ configuration_luks_tpm2_pcrs_raw }}" + configuration_luks_tpm2_pcrs_effective: "{{ configuration_luks_tpm2_pcrs_effective_value }}" + configuration_luks_keyfile_path: >- + /etc/cryptsetup-keys.d/{{ configuration_luks_mapper_name_value }}.key + changed_when: false + + - name: Validate LUKS UUID is available + ansible.builtin.assert: + that: + - configuration_luks_uuid | length > 0 + fail_msg: LUKS UUID not available. Ensure partitioning ran before configuration. + + - name: Validate LUKS passphrase for auto-decrypt + when: configuration_luks_auto_method in ['tpm2', 'keyfile'] + ansible.builtin.assert: + that: + - configuration_luks_passphrase_effective | length > 0 + fail_msg: luks_passphrase (or partitioning_luks_passphrase) must be set for LUKS auto-decrypt. + no_log: true + + - name: Enroll TPM2 for LUKS + when: configuration_luks_auto_method == 'tpm2' + ansible.builtin.include_tasks: encryption/tpm2.yml + + - name: Configure LUKS keyfile auto-decrypt + when: configuration_luks_auto_method == 'keyfile' + ansible.builtin.include_tasks: encryption/keyfile.yml + + - name: Build LUKS parameters + vars: + configuration_luks_keyfile_in_use_value: "{{ configuration_luks_auto_method == 'keyfile' }}" + configuration_luks_option_list_value: >- + {{ + (configuration_luks_options | trim).split(',') + if configuration_luks_options | trim | length > 0 + else [] + }} + configuration_luks_tpm2_option_list_value: >- + {{ + (configuration_luks_auto_method == 'tpm2') + | ternary( + ['tpm2-device=' + configuration_luks_tpm2_device] + + (['tpm2-pcrs=' + configuration_luks_tpm2_pcrs_effective] + if configuration_luks_tpm2_pcrs_effective | length > 0 else []), + [] + ) + }} + configuration_luks_crypttab_keyfile_value: >- + {{ configuration_luks_keyfile_path if configuration_luks_keyfile_in_use_value else 'none' }} + configuration_luks_crypttab_options_value: >- + {{ + (['luks'] + configuration_luks_option_list_value + configuration_luks_tpm2_option_list_value) + | join(',') + }} + configuration_luks_rd_options_value: >- + {{ (configuration_luks_option_list_value + configuration_luks_tpm2_option_list_value) | join(',') }} + configuration_luks_kernel_args_value: >- + {{ + ( + ['rd.luks.name=' + configuration_luks_uuid + '=' + configuration_luks_mapper_name] + + ( + ['rd.luks.options=' + configuration_luks_uuid + '=' + configuration_luks_rd_options_value] + if configuration_luks_rd_options_value | length > 0 else [] + ) + + ( + ['rd.luks.key=' + configuration_luks_uuid + '=' + configuration_luks_keyfile_path] + if configuration_luks_keyfile_in_use_value else [] + ) + ) | join(' ') + }} + ansible.builtin.set_fact: + configuration_luks_keyfile_in_use: "{{ configuration_luks_keyfile_in_use_value }}" + configuration_luks_option_list: "{{ configuration_luks_option_list_value }}" + configuration_luks_tpm2_option_list: "{{ configuration_luks_tpm2_option_list_value }}" + configuration_luks_crypttab_keyfile: "{{ configuration_luks_crypttab_keyfile_value }}" + configuration_luks_crypttab_options: "{{ configuration_luks_crypttab_options_value }}" + configuration_luks_rd_options: "{{ configuration_luks_rd_options_value }}" + configuration_luks_kernel_args: "{{ configuration_luks_kernel_args_value }}" + + - name: Remove LUKS keyfile if TPM2 auto-decrypt is active + when: configuration_luks_auto_method == 'tpm2' + ansible.builtin.file: + path: /mnt{{ configuration_luks_keyfile_path }} + state: absent + + - name: Write crypttab entry + ansible.builtin.lineinfile: + path: /mnt/etc/crypttab + regexp: "^{{ configuration_luks_mapper_name }}\\s" + line: >- + {{ configuration_luks_mapper_name }} UUID={{ configuration_luks_uuid }} + {{ configuration_luks_crypttab_keyfile }} {{ configuration_luks_crypttab_options }} + create: true + mode: "0600" + + - name: Ensure keyfile pattern for initramfs-tools + when: + - is_debian | default(false) + - configuration_luks_keyfile_in_use + ansible.builtin.lineinfile: + path: /mnt/etc/cryptsetup-initramfs/conf-hook + regexp: '^KEYFILE_PATTERN=' + line: 'KEYFILE_PATTERN=/etc/cryptsetup-keys.d/*.key' + create: true + mode: "0644" + + - name: Configure mkinitcpio hooks for LUKS + when: os | lower == 'archlinux' + ansible.builtin.lineinfile: + path: /mnt/etc/mkinitcpio.conf + regexp: '^HOOKS=' + line: >- + HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole + block sd-encrypt lvm2 filesystems fsck) + + - name: Read mkinitcpio configuration + when: os | lower == 'archlinux' + ansible.builtin.slurp: + src: /mnt/etc/mkinitcpio.conf + register: configuration_mkinitcpio_slurp + + - name: Build mkinitcpio FILES list + when: os | lower == 'archlinux' + vars: + configuration_mkinitcpio_files_list_value: >- + {{ + ( + configuration_mkinitcpio_slurp.content | b64decode + | regex_findall('^FILES=\\(([^)]*)\\)', multiline=True) + | default([]) + | first + | default('') + ).split() + }} + configuration_mkinitcpio_files_list_new_value: >- + {{ + ( + (configuration_mkinitcpio_files_list_value + [configuration_luks_keyfile_path]) + if configuration_luks_keyfile_in_use + else ( + configuration_mkinitcpio_files_list_value + | reject('equalto', configuration_luks_keyfile_path) + | list + ) + ) + | unique + }} + ansible.builtin.set_fact: + configuration_mkinitcpio_files_list_new: "{{ configuration_mkinitcpio_files_list_new_value }}" + + - name: Configure mkinitcpio FILES list + when: os | lower == 'archlinux' + ansible.builtin.lineinfile: + path: /mnt/etc/mkinitcpio.conf + regexp: '^FILES=' + line: >- + FILES=({{ + configuration_mkinitcpio_files_list_new | join(' ') + }}) + + - name: Ensure dracut config directory exists + when: is_rhel | default(false) + ansible.builtin.file: + path: /mnt/etc/dracut.conf.d + state: directory + mode: "0755" + + - name: Configure dracut for LUKS + when: is_rhel | default(false) + ansible.builtin.copy: + dest: /mnt/etc/dracut.conf.d/crypt.conf + content: | + add_dracutmodules+=" crypt " + {% if configuration_luks_keyfile_in_use %} + install_items+=" {{ configuration_luks_keyfile_path }} " + {% endif %} + mode: "0644" + + - name: Read kernel cmdline defaults + when: is_rhel | default(false) + ansible.builtin.slurp: + src: /mnt/etc/kernel/cmdline + register: configuration_kernel_cmdline_slurp + + - name: Build kernel cmdline with LUKS args + when: is_rhel | default(false) + vars: + configuration_kernel_cmdline_current_value: >- + {{ configuration_kernel_cmdline_slurp.content | b64decode | trim }} + configuration_kernel_cmdline_list_value: >- + {{ + configuration_kernel_cmdline_current_value.split() + if configuration_kernel_cmdline_current_value | length > 0 else [] + }} + configuration_kernel_cmdline_filtered_value: >- + {{ + configuration_kernel_cmdline_list_value + | reject('match', '^rd\\.luks\\.(name|options|key)=' ~ configuration_luks_uuid ~ '=') + | list + }} + configuration_kernel_cmdline_new_value: >- + {{ + (configuration_kernel_cmdline_filtered_value + configuration_luks_kernel_args.split()) + | unique + | join(' ') + }} + ansible.builtin.set_fact: + configuration_kernel_cmdline_new: "{{ configuration_kernel_cmdline_new_value }}" + changed_when: false + + - name: Write kernel cmdline with LUKS args + when: is_rhel | default(false) + ansible.builtin.copy: + dest: /mnt/etc/kernel/cmdline + mode: "0644" + content: "{{ configuration_kernel_cmdline_new }}\n" + + - name: Find BLS entries + when: is_rhel | default(false) + ansible.builtin.find: + paths: /mnt/boot/loader/entries + patterns: "*.conf" + register: configuration_kernel_bls_entries + changed_when: false + + - name: Update BLS options with LUKS args + when: + - is_rhel | default(false) + - configuration_kernel_bls_entries.files | length > 0 + ansible.builtin.lineinfile: + path: "{{ item.path }}" + regexp: '^options ' + line: "options {{ configuration_kernel_cmdline_new }}" + loop: "{{ configuration_kernel_bls_entries.files }}" + loop_control: + label: "{{ item.path }}" + + - name: Read grub defaults + when: not is_rhel | default(false) + ansible.builtin.slurp: + src: /mnt/etc/default/grub + register: configuration_grub_slurp + + - name: Build grub command lines with LUKS args + when: not is_rhel | default(false) + vars: + configuration_grub_content_value: "{{ configuration_grub_slurp.content | b64decode }}" + configuration_grub_cmdline_linux_value: >- + {{ + configuration_grub_content_value + | regex_findall('^GRUB_CMDLINE_LINUX=\"(.*)\"', multiline=True) + | default([]) + | first + | default('') + }} + configuration_grub_cmdline_default_value: >- + {{ + configuration_grub_content_value + | regex_findall('^GRUB_CMDLINE_LINUX_DEFAULT=\"(.*)\"', multiline=True) + | default([]) + | first + | default('') + }} + configuration_grub_cmdline_linux_list_value: >- + {{ + configuration_grub_cmdline_linux_value.split() + if configuration_grub_cmdline_linux_value | length > 0 else [] + }} + configuration_grub_cmdline_default_list_value: >- + {{ + configuration_grub_cmdline_default_value.split() + if configuration_grub_cmdline_default_value | length > 0 else [] + }} + configuration_luks_kernel_args_list_value: "{{ configuration_luks_kernel_args.split() }}" + configuration_grub_cmdline_linux_new_value: >- + {{ + ( + ( + configuration_grub_cmdline_linux_list_value + | reject('match', '^rd\\.luks\\.(name|options|key)=' ~ configuration_luks_uuid ~ '=') + | list + ) + + configuration_luks_kernel_args_list_value + ) + | unique + | join(' ') + }} + configuration_grub_cmdline_default_new_value: >- + {{ + ( + ( + configuration_grub_cmdline_default_list_value + | reject('match', '^rd\\.luks\\.(name|options|key)=' ~ configuration_luks_uuid ~ '=') + | list + ) + + configuration_luks_kernel_args_list_value + ) + | unique + | join(' ') + }} + ansible.builtin.set_fact: + configuration_grub_content: "{{ configuration_grub_content_value }}" + configuration_grub_cmdline_linux: "{{ configuration_grub_cmdline_linux_value }}" + configuration_grub_cmdline_default: "{{ configuration_grub_cmdline_default_value }}" + configuration_grub_cmdline_linux_new: "{{ configuration_grub_cmdline_linux_new_value }}" + configuration_grub_cmdline_default_new: "{{ configuration_grub_cmdline_default_new_value }}" + + - name: Update GRUB_CMDLINE_LINUX_DEFAULT for LUKS + when: not is_rhel | default(false) + ansible.builtin.lineinfile: + path: /mnt/etc/default/grub + regexp: '^GRUB_CMDLINE_LINUX_DEFAULT=' + line: 'GRUB_CMDLINE_LINUX_DEFAULT="{{ configuration_grub_cmdline_default_new }}"' diff --git a/roles/configuration/tasks/encryption/keyfile.yml b/roles/configuration/tasks/encryption/keyfile.yml new file mode 100644 index 0000000..599fe46 --- /dev/null +++ b/roles/configuration/tasks/encryption/keyfile.yml @@ -0,0 +1,110 @@ +--- +- name: Configure LUKS keyfile auto-decrypt + block: + - name: Ensure cryptsetup key directory exists + ansible.builtin.file: + path: /mnt/etc/cryptsetup-keys.d + state: directory + owner: root + group: root + mode: "0700" + + - name: Ensure LUKS keyfile exists + ansible.builtin.copy: + dest: /mnt{{ configuration_luks_keyfile_path }} + content: >- + {{ + lookup( + 'community.general.random_string', + length=(partitioning_luks_keyfile_size | default(luks_keyfile_size | default(64)) | int), + override_all='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' + ) + }} + owner: root + group: root + mode: "0600" + force: false + register: configuration_luks_keyfile_copy + no_log: true + + - name: Ensure keyfile permissions + ansible.builtin.file: + path: /mnt{{ configuration_luks_keyfile_path }} + owner: root + group: root + mode: "0600" + + - name: Check whether keyfile already unlocks the LUKS device + ansible.builtin.command: + argv: + - cryptsetup + - luksOpen + - --test-passphrase + - --key-file + - "/mnt{{ configuration_luks_keyfile_path }}" + - "{{ configuration_luks_device }}" + register: configuration_luks_keyfile_unlock_test + changed_when: false + failed_when: false + no_log: true + + - name: Add keyfile to LUKS header + when: configuration_luks_keyfile_unlock_test.rc != 0 + community.crypto.luks_device: + device: "{{ configuration_luks_device }}" + passphrase: "{{ configuration_luks_passphrase_effective }}" + new_keyfile: "/mnt{{ configuration_luks_keyfile_path }}" + register: configuration_luks_addkey_result + failed_when: false + no_log: true + + - name: Regenerate keyfile and retry adding to LUKS header + when: + - configuration_luks_keyfile_unlock_test.rc != 0 + - configuration_luks_keyfile_copy.changed | default(false) | bool + - configuration_luks_addkey_result is failed + block: + - name: Regenerate LUKS keyfile + ansible.builtin.copy: + dest: /mnt{{ configuration_luks_keyfile_path }} + content: >- + {{ + lookup( + 'community.general.random_string', + length=(partitioning_luks_keyfile_size | default(luks_keyfile_size | default(64)) | int), + override_all='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' + ) + }} + owner: root + group: root + mode: "0600" + force: true + no_log: true + + - name: Retry adding keyfile to LUKS header + community.crypto.luks_device: + device: "{{ configuration_luks_device }}" + passphrase: "{{ configuration_luks_passphrase_effective }}" + new_keyfile: "/mnt{{ configuration_luks_keyfile_path }}" + register: configuration_luks_addkey_retry + failed_when: false + no_log: true + + - name: Re-check whether keyfile unlocks the LUKS device + ansible.builtin.command: + argv: + - cryptsetup + - luksOpen + - --test-passphrase + - --key-file + - "/mnt{{ configuration_luks_keyfile_path }}" + - "{{ configuration_luks_device }}" + register: configuration_luks_keyfile_unlock_test_after + changed_when: false + failed_when: false + no_log: true + + - name: Fallback to manual LUKS unlock if keyfile enrollment failed + when: (configuration_luks_keyfile_unlock_test_after.rc | default(1)) != 0 + ansible.builtin.set_fact: + configuration_luks_auto_method: manual diff --git a/roles/configuration/tasks/encryption/tpm2.yml b/roles/configuration/tasks/encryption/tpm2.yml new file mode 100644 index 0000000..28668a8 --- /dev/null +++ b/roles/configuration/tasks/encryption/tpm2.yml @@ -0,0 +1,90 @@ +--- +- name: Enroll TPM2 for LUKS + block: + - name: Create temporary passphrase file for TPM2 enrollment + ansible.builtin.tempfile: + path: /mnt/tmp + prefix: luks-passphrase- + state: file + register: configuration_luks_tpm2_passphrase_tempfile + + - name: Write passphrase into temporary file for TPM2 enrollment + ansible.builtin.copy: + dest: "{{ configuration_luks_tpm2_passphrase_tempfile.path }}" + content: "{{ configuration_luks_passphrase_effective }}" + owner: root + group: root + mode: "0600" + no_log: true + + - name: Enroll TPM2 token + vars: + configuration_luks_enroll_args: >- + {{ + [ + '/usr/bin/systemd-cryptenroll', + '--tpm2-device=' + configuration_luks_tpm2_device, + '--tpm2-with-pin=false', + '--wipe-slot=tpm2', + '--unlock-key-file=' + ( + configuration_luks_tpm2_passphrase_tempfile.path + | regex_replace('^/mnt', '') + ) + ] + + (['--tpm2-pcrs=' + configuration_luks_tpm2_pcrs_effective] + if configuration_luks_tpm2_pcrs_effective | length > 0 else []) + + [configuration_luks_device] + }} + configuration_luks_enroll_chroot_args: "{{ ['arch-chroot', '/mnt'] + configuration_luks_enroll_args }}" + ansible.builtin.command: + argv: "{{ configuration_luks_enroll_chroot_args }}" + register: configuration_luks_tpm2_enroll_chroot + changed_when: configuration_luks_tpm2_enroll_chroot.rc == 0 + failed_when: false + + - name: Retry TPM2 enrollment in installer environment + when: + - (configuration_luks_tpm2_enroll_chroot.rc | default(1)) != 0 + vars: + configuration_luks_enroll_args: >- + {{ + [ + '/usr/bin/systemd-cryptenroll', + '--tpm2-device=' + configuration_luks_tpm2_device, + '--tpm2-with-pin=false', + '--wipe-slot=tpm2', + '--unlock-key-file=' + configuration_luks_tpm2_passphrase_tempfile.path + ] + + (['--tpm2-pcrs=' + configuration_luks_tpm2_pcrs_effective] + if configuration_luks_tpm2_pcrs_effective | length > 0 else []) + + [configuration_luks_device] + }} + ansible.builtin.command: + argv: "{{ configuration_luks_enroll_args }}" + register: configuration_luks_tpm2_enroll_host + changed_when: configuration_luks_tpm2_enroll_host.rc == 0 + failed_when: false + + - name: Validate TPM2 enrollment succeeded + ansible.builtin.assert: + that: + - >- + (configuration_luks_tpm2_enroll_chroot.rc | default(1)) == 0 + or (configuration_luks_tpm2_enroll_host.rc | default(1)) == 0 + fail_msg: >- + TPM2 enrollment failed. + chroot rc={{ configuration_luks_tpm2_enroll_chroot.rc | default('n/a') }}, + host rc={{ configuration_luks_tpm2_enroll_host.rc | default('n/a') }}, + chroot stderr={{ configuration_luks_tpm2_enroll_chroot.stderr | default('') }}, + host stderr={{ configuration_luks_tpm2_enroll_host.stderr | default('') }} + rescue: + - name: Fallback to keyfile auto-decrypt + ansible.builtin.set_fact: + configuration_luks_auto_method: keyfile + always: + - name: Remove TPM2 enrollment passphrase file + when: configuration_luks_tpm2_passphrase_tempfile.path is defined + ansible.builtin.file: + path: "{{ configuration_luks_tpm2_passphrase_tempfile.path }}" + state: absent + changed_when: false diff --git a/roles/configuration/tasks/grub.yml b/roles/configuration/tasks/grub.yml new file mode 100644 index 0000000..246a318 --- /dev/null +++ b/roles/configuration/tasks/grub.yml @@ -0,0 +1,109 @@ +--- +- name: Configure grub + when: not is_rhel | default(false) + block: + - name: Add commandline information to grub config + ansible.builtin.lineinfile: + dest: /mnt/etc/default/grub + regexp: ^GRUB_CMDLINE_LINUX_DEFAULT= + line: GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3" + + - name: Change Grub time + ansible.builtin.lineinfile: + dest: /mnt/etc/default/grub + regexp: ^GRUB_TIMEOUT= + line: GRUB_TIMEOUT=1 + +- name: Ensure grub defaults file exists for RHEL-based systems + when: is_rhel | default(false) + block: + - name: Build RHEL kernel command line defaults + vars: + configuration_grub_root_uuid_value: >- + {{ + ( + partitioning_main_uuid.stdout + if (filesystem | lower) == 'btrfs' + else (partitioning_uuid_root | default([]) | first | default('')) + ) + | default('') + | trim + }} + configuration_grub_lvm_args_value: >- + {{ + ['resume=/dev/mapper/sys-swap', 'rd.lvm.lv=sys/root', 'rd.lvm.lv=sys/swap'] + if (filesystem | lower) != 'btrfs' + else [] + }} + configuration_grub_root_flags_value: >- + {{ ['rootflags=subvol=@'] if (filesystem | lower) == 'btrfs' else [] }} + configuration_grub_cmdline_linux_base_value: >- + {{ + (['crashkernel=auto'] + configuration_grub_lvm_args_value) + | join(' ') + }} + configuration_grub_kernel_cmdline_base_value: >- + {{ + ( + (['root=UUID=' + configuration_grub_root_uuid_value] + if configuration_grub_root_uuid_value | length > 0 else []) + + ['ro', 'crashkernel=auto'] + + configuration_grub_lvm_args_value + + configuration_grub_root_flags_value + ) + | join(' ') + }} + ansible.builtin.set_fact: + configuration_grub_cmdline_linux_base: "{{ configuration_grub_cmdline_linux_base_value }}" + configuration_kernel_cmdline_base: "{{ configuration_grub_kernel_cmdline_base_value }}" + changed_when: false + + - name: Check if grub defaults file exists + ansible.builtin.stat: + path: /mnt/etc/default/grub + register: configuration_grub_defaults_stat + changed_when: false + + - name: Create default grub configuration + when: not configuration_grub_defaults_stat.stat.exists + ansible.builtin.copy: + dest: /mnt/etc/default/grub + mode: "0644" + content: | + GRUB_TIMEOUT=5 + GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)" + GRUB_DEFAULT=saved + GRUB_DISABLE_SUBMENU=true + GRUB_TERMINAL_OUTPUT="console" + GRUB_CMDLINE_LINUX="{{ configuration_grub_cmdline_linux_base }}" + GRUB_DISABLE_RECOVERY="true" + GRUB_ENABLE_BLSCFG=true + + - name: Ensure kernel cmdline directory exists + ansible.builtin.file: + path: /mnt/etc/kernel + state: directory + mode: "0755" + + - name: Write kernel cmdline defaults + ansible.builtin.copy: + dest: /mnt/etc/kernel/cmdline + mode: "0644" + content: "{{ configuration_kernel_cmdline_base }}\n" + + - name: Find BLS entries + ansible.builtin.find: + paths: /mnt/boot/loader/entries + patterns: "*.conf" + register: configuration_grub_bls_entries + changed_when: false + + - name: Update BLS options with kernel cmdline defaults + when: configuration_grub_bls_entries.files | length > 0 + ansible.builtin.lineinfile: + path: "{{ item.path }}" + regexp: '^options ' + line: "options {{ configuration_kernel_cmdline_base }}" + loop: "{{ configuration_grub_bls_entries.files }}" + loop_control: + label: "{{ item.path }}"