Compare commits
7 Commits
b11d65a6f3
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| ce79728744 | |||
| b31a5a2580 | |||
| 2055863673 | |||
| ceb11852ec | |||
| 57417514e3 | |||
| 0928588c1f | |||
| 6d622f2db4 |
@@ -222,6 +222,7 @@ bootstrap_debian:
|
||||
+ (['software-properties-common'] if (os_version | string) not in ['13', 'unstable'] else [])
|
||||
+ (['systemd-zram-generator'] if (os_version | string) not in ['10', '11'] else [])
|
||||
+ (['tldr'] if (os_version | string) not in ['13', 'unstable'] else [])
|
||||
+ (['shim-signed'] if system_cfg.features.secure_boot.enabled | bool else [])
|
||||
+ bootstrap_common_conditional
|
||||
}}
|
||||
|
||||
@@ -285,6 +286,7 @@ bootstrap_ubuntu:
|
||||
conditional: >-
|
||||
{{
|
||||
(['tldr'] if (os_version | default('') | string | length) > 0 else [])
|
||||
+ (['shim-signed'] if system_cfg.features.secure_boot.enabled | bool else [])
|
||||
+ bootstrap_common_conditional
|
||||
}}
|
||||
|
||||
@@ -323,6 +325,7 @@ bootstrap_archlinux:
|
||||
{{
|
||||
(['openssh'] if system_cfg.features.ssh.enabled | bool else [])
|
||||
+ (['iptables-nft'] if system_cfg.features.firewall.toolkit == 'nftables' and system_cfg.features.firewall.enabled | bool else [])
|
||||
+ (['sbctl'] if system_cfg.features.secure_boot.enabled | bool else [])
|
||||
+ (bootstrap_common_conditional | reject('equalto', 'nftables') | list)
|
||||
}}
|
||||
|
||||
|
||||
@@ -94,6 +94,35 @@
|
||||
state: destroyed
|
||||
failed_when: false
|
||||
|
||||
- name: Enroll Secure Boot keys in VM NVRAM
|
||||
when:
|
||||
- system_cfg.features.secure_boot.enabled | default(false) | bool
|
||||
- os != 'archlinux'
|
||||
block:
|
||||
- name: Find VM NVRAM file path
|
||||
ansible.builtin.shell:
|
||||
cmd: >-
|
||||
set -o pipefail &&
|
||||
virsh -c {{ libvirt_uri | default('qemu:///system') }} dumpxml {{ hostname }}
|
||||
| grep -oP '<nvram[^>]*>\K[^<]+'
|
||||
executable: /bin/bash
|
||||
register: _sb_nvram_path
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Enroll Secure Boot keys via virt-fw-vars
|
||||
when: _sb_nvram_path.stdout | default('') | length > 0
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- virt-fw-vars
|
||||
- --inplace
|
||||
- "{{ _sb_nvram_path.stdout | trim }}"
|
||||
- --enroll-redhat
|
||||
- --secure-boot
|
||||
register: _sb_enroll_result
|
||||
changed_when: _sb_enroll_result.rc == 0
|
||||
failed_when: false
|
||||
|
||||
- name: Start the VM
|
||||
community.libvirt.virt:
|
||||
name: "{{ hostname }}"
|
||||
|
||||
@@ -14,3 +14,12 @@
|
||||
- name: Set platform configuration
|
||||
ansible.builtin.set_fact:
|
||||
_configuration_platform: "{{ configuration_platform_config[os_family] }}"
|
||||
|
||||
- name: Override EFI loader to shim for Secure Boot
|
||||
when:
|
||||
- system_cfg.features.secure_boot.enabled | bool
|
||||
- _configuration_platform.efi_loader != 'shimx64.efi'
|
||||
- os != 'archlinux'
|
||||
ansible.builtin.set_fact:
|
||||
_configuration_platform: >-
|
||||
{{ _configuration_platform | combine({'efi_loader': 'shimx64.efi'}) }}
|
||||
|
||||
@@ -103,3 +103,17 @@
|
||||
ansible.builtin.command: "{{ chroot_command }} /usr/sbin/grub-mkconfig -o /boot/grub/grub.cfg"
|
||||
register: configuration_grub_result
|
||||
changed_when: configuration_grub_result.rc == 0
|
||||
|
||||
- name: Rebuild GRUB as standalone EFI for Secure Boot
|
||||
when:
|
||||
- system_cfg.features.secure_boot.enabled | default(false) | bool
|
||||
- os == 'archlinux'
|
||||
ansible.builtin.command: >-
|
||||
{{ chroot_command }} grub-mkstandalone
|
||||
-d /usr/lib/grub/x86_64-efi
|
||||
-O x86_64-efi
|
||||
--disable-shim-lock
|
||||
-o {{ partitioning_efi_mountpoint }}/EFI/{{ _efi_vendor }}/grubx64.efi
|
||||
boot/grub/grub.cfg=/boot/grub/grub.cfg
|
||||
register: _grub_standalone_result
|
||||
changed_when: _grub_standalone_result.rc == 0
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
block:
|
||||
- name: Set LUKS configuration facts
|
||||
vars:
|
||||
luks_tpm2_pcrs: >-
|
||||
_raw_pcrs: >-
|
||||
{{
|
||||
(
|
||||
system_cfg.luks.tpm2.pcrs
|
||||
@@ -20,6 +20,17 @@
|
||||
| regex_replace('\\s+', '')
|
||||
| regex_replace('^\\+|\\+$', '')
|
||||
}}
|
||||
_sb_pcr7_safe: >-
|
||||
{{
|
||||
system_cfg.features.secure_boot.enabled | bool
|
||||
and system_cfg.type | default('virtual') != 'virtual'
|
||||
}}
|
||||
luks_tpm2_pcrs: >-
|
||||
{{
|
||||
_raw_pcrs
|
||||
if _raw_pcrs | length > 0
|
||||
else ('7' if (_sb_pcr7_safe | bool) else '')
|
||||
}}
|
||||
ansible.builtin.set_fact:
|
||||
configuration_luks_mapper_name: "{{ system_cfg.luks.mapper }}"
|
||||
configuration_luks_uuid: "{{ partitioning_luks_uuid | default('') }}"
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
- file: encryption.yml
|
||||
when: "{{ system_cfg.luks.enabled | bool }}"
|
||||
- file: bootloader.yml
|
||||
- file: secure_boot.yml
|
||||
when: "{{ system_cfg.features.secure_boot.enabled | bool }}"
|
||||
- file: extras.yml
|
||||
- file: network.yml
|
||||
- file: users.yml
|
||||
|
||||
8
roles/configuration/tasks/secure_boot.yml
Normal file
8
roles/configuration/tasks/secure_boot.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
- name: Configure shim-based Secure Boot
|
||||
when: os != 'archlinux'
|
||||
ansible.builtin.include_tasks: secure_boot/shim.yml
|
||||
|
||||
- name: Configure sbctl Secure Boot
|
||||
when: os == 'archlinux'
|
||||
ansible.builtin.include_tasks: secure_boot/sbctl.yml
|
||||
115
roles/configuration/tasks/secure_boot/sbctl.yml
Normal file
115
roles/configuration/tasks/secure_boot/sbctl.yml
Normal file
@@ -0,0 +1,115 @@
|
||||
---
|
||||
- name: Configure sbctl Secure Boot
|
||||
block:
|
||||
- name: Create Secure Boot signing keys
|
||||
ansible.builtin.command: "{{ chroot_command }} sbctl create-keys"
|
||||
register: _sbctl_create_keys
|
||||
changed_when: _sbctl_create_keys.rc == 0
|
||||
failed_when:
|
||||
- _sbctl_create_keys.rc != 0
|
||||
- "'already exists' not in (_sbctl_create_keys.stderr | default(''))"
|
||||
|
||||
- name: Enroll Secure Boot keys in firmware
|
||||
ansible.builtin.command: "{{ chroot_command }} sbctl enroll-keys --microsoft"
|
||||
register: _sbctl_enroll
|
||||
changed_when: _sbctl_enroll.rc == 0
|
||||
failed_when: false
|
||||
|
||||
- name: Install first-boot enrollment service if chroot enrollment failed
|
||||
when: _sbctl_enroll.rc | default(1) != 0
|
||||
block:
|
||||
- name: Create first-boot sbctl enrollment service
|
||||
ansible.builtin.copy:
|
||||
dest: /mnt/etc/systemd/system/sbctl-enroll.service
|
||||
mode: "0644"
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Enroll Secure Boot keys via sbctl
|
||||
ConditionPathExists=!/var/lib/sbctl/.enrolled
|
||||
After=local-fs.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/sbctl enroll-keys --microsoft
|
||||
ExecStartPost=/usr/bin/touch /var/lib/sbctl/.enrolled
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
- name: Enable first-boot enrollment service
|
||||
ansible.builtin.command: "{{ chroot_command }} systemctl enable sbctl-enroll.service"
|
||||
register: _sbctl_service_enable
|
||||
changed_when: _sbctl_service_enable.rc == 0
|
||||
|
||||
- name: Find kernel images to sign
|
||||
ansible.builtin.find:
|
||||
paths: /mnt/boot
|
||||
patterns: "vmlinuz-*"
|
||||
file_type: file
|
||||
register: _sbctl_kernel_images
|
||||
|
||||
- name: Sign kernel images
|
||||
ansible.builtin.command: >-
|
||||
{{ chroot_command }} sbctl sign -s {{ item.path | regex_replace('^/mnt', '') }}
|
||||
loop: "{{ _sbctl_kernel_images.files }}"
|
||||
loop_control:
|
||||
label: "{{ item.path | basename }}"
|
||||
register: _sbctl_sign_kernel
|
||||
changed_when: _sbctl_sign_kernel.rc == 0
|
||||
failed_when: false
|
||||
|
||||
- name: Sign GRUB EFI binary
|
||||
vars:
|
||||
_grub_efi_path: "{{ partitioning_efi_mountpoint }}/EFI/archlinux/grubx64.efi"
|
||||
ansible.builtin.command: >-
|
||||
{{ chroot_command }} sbctl sign -s {{ _grub_efi_path }}
|
||||
register: _sbctl_sign_grub
|
||||
changed_when: _sbctl_sign_grub.rc == 0
|
||||
failed_when: false
|
||||
|
||||
- name: Ensure pacman hooks directory exists
|
||||
ansible.builtin.file:
|
||||
path: /mnt/etc/pacman.d/hooks
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Install sbctl auto-signing pacman hook
|
||||
ansible.builtin.copy:
|
||||
dest: /mnt/etc/pacman.d/hooks/99-sbctl-sign.hook
|
||||
mode: "0644"
|
||||
content: |
|
||||
[Trigger]
|
||||
Operation = Install
|
||||
Operation = Upgrade
|
||||
Type = Path
|
||||
Target = boot/vmlinuz-*
|
||||
Target = usr/lib/modules/*/vmlinuz
|
||||
|
||||
[Action]
|
||||
Description = Signing kernel images for Secure Boot...
|
||||
When = PostTransaction
|
||||
Exec = /usr/bin/sbctl sign-all
|
||||
Depends = sbctl
|
||||
|
||||
- name: Verify sbctl signing status
|
||||
ansible.builtin.command: "{{ chroot_command }} sbctl verify"
|
||||
register: _sbctl_verify
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Report sbctl Secure Boot status
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
Secure Boot (sbctl):
|
||||
Enrollment={{ 'done' if (_sbctl_enroll.rc | default(1)) == 0 else 'deferred to first boot' }}.
|
||||
{{ _sbctl_verify.stdout | default('Verify not available') }}
|
||||
|
||||
rescue:
|
||||
- name: Secure Boot setup failed
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
sbctl Secure Boot setup failed.
|
||||
On VMs make sure the OVMF firmware is in Setup Mode (fresh NVRAM).
|
||||
On bare metal enter the firmware setup and switch to Setup Mode first.
|
||||
To recover manually: sbctl create-keys && sbctl enroll-keys --microsoft && sbctl sign-all
|
||||
45
roles/configuration/tasks/secure_boot/shim.yml
Normal file
45
roles/configuration/tasks/secure_boot/shim.yml
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
- name: Configure shim-based Secure Boot
|
||||
vars:
|
||||
_efi_vendor: >-
|
||||
{{
|
||||
"redhat" if os == "rhel"
|
||||
else ("ubuntu" if os in ["ubuntu", "ubuntu-lts"] else os)
|
||||
}}
|
||||
block:
|
||||
- name: Find shim binary in target system
|
||||
ansible.builtin.shell:
|
||||
cmd: >-
|
||||
set -o pipefail &&
|
||||
{{ chroot_command }} find /usr/lib/shim /boot/efi/EFI
|
||||
\( -name 'shimx64.efi.signed.latest' -o -name 'shimx64.efi.dualsigned'
|
||||
-o -name 'shimx64.efi.signed' -o -name 'shimx64.efi' \)
|
||||
-type f | sort -r | head -1
|
||||
executable: /bin/bash
|
||||
register: _shim_find_result
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Copy shim to EFI vendor directory
|
||||
when:
|
||||
- _shim_find_result.stdout | default('') | length > 0
|
||||
- _configuration_platform.grub_install | bool
|
||||
ansible.builtin.command: >-
|
||||
cp /mnt{{ _shim_find_result.stdout_lines | first }}
|
||||
/mnt{{ partitioning_efi_mountpoint }}/EFI/{{ _efi_vendor }}/shimx64.efi
|
||||
register: _shim_copy_result
|
||||
changed_when: _shim_copy_result.rc == 0
|
||||
|
||||
- name: Verify shim is present
|
||||
ansible.builtin.stat:
|
||||
path: "/mnt{{ partitioning_efi_mountpoint }}/EFI/{{ _efi_vendor }}/shimx64.efi"
|
||||
register: _shim_stat
|
||||
|
||||
- name: Report Secure Boot status
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
Secure Boot (shim): {{
|
||||
'shimx64.efi installed at ' ~ partitioning_efi_mountpoint ~ '/EFI/' ~ _efi_vendor
|
||||
if (_shim_stat.stat.exists | default(false))
|
||||
else 'shimx64.efi not found, shim package may handle placement on first boot'
|
||||
}}
|
||||
@@ -141,6 +141,9 @@ system_defaults:
|
||||
enabled: false
|
||||
environment: "" # gnome|kde|xfce|sway|hyprland|cinnamon|mate|lxqt|budgie
|
||||
display_manager: "" # auto from environment when empty; override: gdm|sddm|lightdm|greetd
|
||||
secure_boot:
|
||||
enabled: false
|
||||
method: "" # arch only: sbctl (default) or uki; ignored for other distros
|
||||
|
||||
# Per-hypervisor required fields — drives data-driven validation.
|
||||
# All virtual types additionally require network bridge or interfaces.
|
||||
|
||||
@@ -150,6 +150,9 @@
|
||||
enabled: "{{ system_raw.features.desktop.enabled | bool }}"
|
||||
environment: "{{ system_raw.features.desktop.environment | default('') | string | lower }}"
|
||||
display_manager: "{{ system_raw.features.desktop.display_manager | default('') | string | lower }}"
|
||||
secure_boot:
|
||||
enabled: "{{ system_raw.features.secure_boot.enabled | bool }}"
|
||||
method: "{{ system_raw.features.secure_boot.method | default('') | string | lower }}"
|
||||
hostname: "{{ system_name }}"
|
||||
os: "{{ system_os_input if system_os_input | length > 0 else (physical_default_os if system_type == 'physical' else '') }}"
|
||||
os_version: "{{ system_raw.version | default('') | string }}"
|
||||
|
||||
@@ -22,10 +22,10 @@ virtualization_libvirt_ovmf_vars: /usr/share/edk2/x64/OVMF_VARS.4m.fd
|
||||
|
||||
virtualization_tpm2_enabled: >-
|
||||
{{
|
||||
(system_cfg.luks.enabled | bool)
|
||||
and (system_cfg.luks.auto | bool)
|
||||
and (
|
||||
(system_cfg.luks.method | lower)
|
||||
== 'tpm2'
|
||||
(
|
||||
(system_cfg.luks.enabled | bool)
|
||||
and (system_cfg.luks.auto | bool)
|
||||
and (system_cfg.luks.method | lower == 'tpm2')
|
||||
)
|
||||
or (system_cfg.features.secure_boot.enabled | default(false) | bool)
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user