OpenSUSE Leap 16 and Systemd/UKI
OpenSUSE Leap 16 offers basically the same NLTB features as Fedora 42, including:
Secure boot of a signed UKI kernel+initrd+cmdline
no more appraisal gap in the initrd
enhanced measurements in PCRs 11 and 15
Simplified Management of all secure boot keys
Measurement, appraisal, and attestation of all files
Use of the TPM to unlock all encrypted partitions at boot
TPM provisioning for backup and restore of all stored keys across TPM failure
There are three main differences from Fedora 42:
The shim is version 15.8, which is old, and does not have NX support and page zero handling. Current versions of edk2/ovmf for virt-manager/Qemu on Fedora 42 refuse to boot it in a VM. A current workaround for Fedora 42 (as the VM host) is:
dnf upgrade --enablerepo=updates-testing --refresh --advisory=FEDORA-2025-7e2a69db6b
Also, this shim does not work for booting a UKI, so we have to build a current version.
The rpms are not signed, and there is no rpm-plugin-ima to add IMA signatures to all files as they are installed. So we will install everything first, and then manually sign all files in place with evmctl.
Zypper is used in place of dnf, and there are some differences in the packages, which are noted in the following detailed installation instructions. There are some subtle differences in the actual commands, so read carefully.
The kernel is compiled with "# CONFIG_IMA_WRITE_POLICY is not set", which seems to mean that we can't load a new policy, at least with the normal dracut support. UPDATE - actually this may be an selinux denial....
Detailed Installation Instructions
These instructions are for installation in a virt-manager VM running on a current Linux. You should be able to install it on other systems or even on bare metal, but that has not yet been tested.
In the instructions, a '$' prompt indicates the command is run as a user. If
the prompt is '#', it is run as root. You can get a root shell by running "sudo -i".
Note that these instructions involve rebooting frequently. Normally the installation would be fully scripted with yast, requiring only one reboot. Here we reboot frequently as a way of testing each step, so that we can test and discover any problems quickly.
I. Install the base Leap 16:
a. Download the installation Release Candidate (RC) image from
https://get.opensuse.org/leap/16.0/#download
I used Leap-16.0-offline-installer-x86_64.install.iso
b. Create the VM with virt-manager. To create a VM:
- Start virt-manager as a user:
$ virt-manager
- Click the icon to create a new VM.
- Select "local install media" (which should be the default), then click "forward".
- Browse to find and select the Live iso you downloaded, and click "forward".
- Set CPU parameters (I used 4096 RAM, 4 threads), and click "forward".
- Set the disk size (I set 42GB), then click "forward".
- In the "Create a new virtual machine" window, select
"Customize configuration before install", then click "Finish".
- In the Installation window, first
- set "Firmware" to "UEFI x86_64:/usr/share/edk2/ovmf/OVMF_CODE_4M.secboot.qcow2",
and click "Apply".
- Click the "Add Hardware" button.
- In the "Add New Virtual Hardware" window, click on "TPM", then click "Finish"
- Back in the Installation window, click on the "Begin Installation" button.
c. Install openSUSE Leap in the VM:
Normal install
click on "Storage"
- click on "Installation Devices" - "Details" and "Add or use partition"
to add /opt and /data partitions (ext4 fixed 10GB)
- turn on encryption
click on "Software" - "edit" and click to add Gnome
click on "Authentication" - define the first user
IMPORTANT NOTE: With the encrypted root partition, TianoCore (the virtual
uefi bios) will ask for the "passphrase for hd0.gpt2", then wait for
around 70 seconds. (I don't know why). Then the grub menu will appear,
and once booted, the initrd will again ask for the passphrase.
UKI will fix this later in the instructions.
II. Install additional needed packages
Update the system
# zypper update
Install some more needed packages for the latest kernel
# zypper install -t pattern devel_C_C++
# zypper install libopenssl-devel hostname
# zypper install ima-evm-utils dracut-ima tpm2-0-tss-devel
# zypper install pesign sbsigntools golang asciidoc
# zypper install systemd-experimental systemd-boot systemd-devel
# zypper install virt-firmware pcsc-lite-devel
Add your user to the tss group:
# usermod -a -G tss <username>
build and install sbctl
$ cd
$ git clone https://github.com/foxboron/sbctl.git
$ cd sbctl
$ sudo make install
$ sudo sbctl create-keys
build and install cel_util
$ cd
$ git clone https://github.com/safforddr/cel_util.git
$ cd cel_util
$ make
Now we need to add our own local IMA signing key, so that we can sign all
executables and a new policy:
$ cd
$ git clone https://github.com/linux-integrity/ima-evm-utils.git
$ cd ima-evm-utils/examples
$ ./ima-gen-local-ca.sh
$ ./ima-genkey.sh
$ sudo cp x509_ima.der /etc/keys/ima
$ cp x509_ima.der ../../cel_util
build a new shimx64.efi
$ cd
$ git clone https://github.com/rhboot/shim.git
$ git submodule update --init --recursive
$ sudo cp /var/lib/sbctl/keys/db/db.pem .
$ sudo chmod 444 db.pem
$ openssl x509 -in db.pem -outform DER -out db.der
$ make VENDOR_CERT_FILE=db.der
$ sudo copy shimx64.efi /boot/efi/EFI/opensuse
$ sudo sbctl sign --save /boot/efi/EFI/opensuse/shimx64.efi
reboot
III. Create and enroll our own sb keys, and sign grub and the traditional kernel:
- reboot and press ESC repeatedly to enter UEFI setup mode, and force
secure boot setup mode. (Note: if you miss the setup window,
just wait for the grub menu, and select the "UEFI Firmware Settings" menu entry).
Then:
- Use arrows to select "Device Manager" and press Enter.
- Select "Secure Boot Configuration" and press Enter.
- Select "Reset Secure Boot Keys", and respond yes to confirm.
This puts secure boot in "setup" mode.
- Press F10 to save, and press ESC to return to the top menu.
- Select "Continue" to boot to the Grub boot menu.
a. Log in the the booted VM
b. Create local UEFI keys (stored in /usr/share/secureboot):
# sbctl enroll-keys --tpm-eventlog
c. Sign all the files
run "sbctl verify" which will list all files that need to be signed.
Sign all the files with sbctl sign --save <filename>
d. Check that everything is signed:
# sbctl verify
Verifying file database and EFI images in /boot/efi...
✓ /boot/efi/EFI/fedora/grubx64.efi is signed
✓ /boot/efi/EFI/fedora/mmx64.efi is signed
✓ /boot/efi/EFI/fedora/shim.efi is signed
✓ /boot/efi/EFI/fedora/shimx64.efi is signed
✓ /boot/efi/EFI/BOOT/BOOTX64.EFI is signed
✓ /boot/efi/EFI/BOOT/fbx64.efi is signed
e. ??? use new shimx64.efi??? then reboot
f. Use keyctl show to check the keyrings:
# keyctl show %:.platform
# keyctl show %:.machine
# keyctl show %:.ima
The .machine key ring should have the new IMA-CA key, and the .ima
keyring should have the local IMA signing key ("localhost-live: dave signing key",
where "dave" is replaced with whatever username you used).
IV. Provision TPM and enroll LUKS key
a. check that secure boot is running correctly with the new keys:
# sbctl status
Installed: ✓ sbctl is installed
Owner GUID: e3593590-f537-4f3f-b6e0-c37a10f2837f
Setup Mode: ✓ Disabled
Secure Boot: ✓ Enabled
Vendor Keys: tpm-eventlog
b. Set TPM owner password, and create a persistent SRK at 0x81000001:
In the following command, replace <my_owner_password> with yours, and remember it.
$ tpm2_changeauth -c owner <my_owner_password>
$ echo "SRK" | tpm2_createprimary -c primary.ctx -P <my_owner_password> -u -
$ tpm2_evictcontrol -C o -c primary.ctx 0x81000001 -P <my_owner_password>
c. As root, enroll the LUKS key in the TPM for /, swap, /opt, and /data:
# systemd-cryptenroll /dev/vda2 --tpm2-device=auto --tpm2-seal-key-handle=0x81000001
# systemd-cryptenroll /dev/vda3 --tpm2-device=auto --tpm2-seal-key-handle=0x81000001
# systemd-cryptenroll /dev/vda4 --tpm2-device=auto --tpm2-seal-key-handle=0x81000001
# systemd-cryptenroll /dev/vda5 --tpm2-device=auto --tpm2-seal-key-handle=0x81000001
d. add " none tpm2-device=auto" to the end of the lines in /etc/crypttab
e. Rebuild initrd
# dracut --force --add integrity
f. reboot
This time, the encryption keys should be obtained from the TPM automatically!
V Sign all executables
# cd /home/<use>/ima-evm-utils/examples
# find / -fstype btrfs -type f -executable -print -exec evmctl -a sha256 ima_sign -k privkey_ima.pem {} \;
Note you will get a harmless warning of a find loop on /.snapshot.
VI Set new IMA policy and Fix IMA appraisal labels
At this point we are measuring everything, and saving the fedora signatures on all files in the Event Log for later attestation, but we are not using IMA Appraisal to enforce the signatures during run-time. To do that we have to first run ima_appraise=fix with secureboot turned off, and boot the system to make sure everything is properly labeled. (Everything installed from fedora rpms should have signatures, but many as described in an earlier "comment", some scripts are generated and installed, particularly by dracut, that are not signed.)
a. reboot into UEFI, (pressing ESC as tianocore is booting) and turn off secure boot
b. boot into the grub menu, and press 'e' to edit the kernel command line, adding "ima_appraise=fix ima_policy=appraise_tcb"
c. continue the boot, so that everything gets labeled properly
a. As root, cd to the ima-evm-utils/examples directory (where the local IMA keys were generated)
# vi /etc/sysconfig/ima-policy to contain the lines:
dont_measure fsmagic=0x9fa0
dont_measure fsmagic=0x62656572
dont_measure fsmagic=0x64626720
dont_measure fsmagic=0x1021994
dont_measure fsmagic=0x1cd1
dont_measure fsmagic=0x42494e4d
dont_measure fsmagic=0x73636673
dont_measure fsmagic=0xf97cff8c
dont_measure fsmagic=0x43415d53
dont_measure fsmagic=0x27e0eb
dont_measure fsmagic=0x63677270
dont_measure fsmagic=0x6e736673
dont_measure fsmagic=0xde5e81e4
measure func=MMAP_CHECK mask=MAY_EXEC
measure func=BPRM_CHECK mask=MAY_EXEC
measure func=MODULE_CHECK
measure func=FIRMWARE_CHECK
measure func=POLICY_CHECK
dont_appraise fsmagic=0x9fa0
dont_appraise fsmagic=0x62656572
dont_appraise fsmagic=0x64626720
dont_appraise fsmagic=0x1021994
dont_appraise fsmagic=0x858458f6
dont_appraise fsmagic=0x1cd1
dont_appraise fsmagic=0x42494e4d
dont_appraise fsmagic=0x73636673
dont_appraise fsmagic=0xf97cff8c
dont_appraise fsmagic=0x43415d53
dont_appraise fsmagic=0x6e736673
dont_appraise fsmagic=0x27e0eb
dont_appraise fsmagic=0x63677270
appraise func=POLICY_CHECK appraise_type=imasig
appraise func=BPRM_CHECK mask=MAY_EXEC appraise_type=imasig
# evmctl ima_sign -k privkey_ima.pem /etc/sysconfig/ima-policy
Reboot, turning secure boot back on and setting adding
"ima_template=ima-sig ima_policy=tcb"
to the kernel command line in grub.
IMPORTANT NOTE: currently the new policy is failing to load, possibly due to the kernel config. This means that we are stuck with the policy selected in the kernel command line ("tcb"), which does not do appraise, and which measures everything, including log files, which will cause problems with the verifier, or possibly "appraise_tcb", which again causes failures due to unsigned log files. NOPE - upon further review, opensuse was using an older kernel (6.12.0) vs Fedora's 6.15.9, which didn't handle comments in rules. The above has had the comments removed to work under 6.12.0.
Check that you are getting the right things in
/sys/kernel/security/ima/ascii_runtime_measurements
and /sys/kernel/security/ima/policy
Try creating and running a new test script (which should fail, even if root)
VII. Build UKI Image and sign it (as root):
a. Create a signed uki image with ukify - modify the paths and cmdline for your system.
Mine looked like:
ukify build \
--linux=/boot/vmlinuz... \
--initrd=/boot/initrd-... \
--cmdline='... ima_template=ima-sig ima_policy=tcb' \
--secureboot-private-key=/var/lib/sbctl/keys/db/db.key \
--secureboot-certificate=/var/lib/sbctl/keys/db/db.pem
# cp vmlinuz...efi /boot/efi/EFI/opensuse
d. enroll the newshim and UKI
# kernel-bootcfg --add-uki /boot/efi/EFI/opensuse/vmlinuz-6.14.11-300.signed.efi \
--boot-order 0 --title "Opensuse Leap 16 UKI" --shim /boot/efi/EFI/opensuse/shimx64.efi
d. reboot
(The UKI will now be the default UEFI boot. You can see the UEFI boot menu if you press
F8 at boot. The new UKI boot option will be the default at the top of the UEFI boot menu.)
Note that you will need to enter the LUKS password, since the PCRs have changed.
e. reenroll the LUKS key for vda3, vda4, and vda5 as in:
# systemd-cryptenroll /dev/vda3 --tpm2-device=auto --tpm2-seal-key-handle=0x81000001
reboot
VIII. Run verify
WHEW!
Now that everything is installed and configured, you can check things out:
Check out the keyrings with
# keyctl show %:.platform
# keyctl show %:.machine
# keyctl show %:.ima
Test the attestation verification with:
# cd /home/dave/cel_util
# ./verify
This should yield the following attestation verification summary:
Some things to note in the summary:
IMA events are ongoing, and getting the PCR values from the TPM and getting teh event log from the kernel are not synchronized. In the example verifier, the PCR values are retrieved first, and then the IMA event log. This way there may be events at the end of the event log that were not yet extended into PCR-10 when the PCR value was read. The verifier checks after each event in the log to see if the PCR-10 matches. In this example case the result "MATCHED EARLIER" indicates that there were events in the log after the PCR-10 value matched. This is normal.
"verfified by ima-sig" indicates that the signatures in the ima-sig template have successfully been verified against one of the Fedora signing key certificates or the local IMA certificate.
The early IMA events are not verified by ima-sig, as they were in the initramfs, which does not have signed files. The entire UKI file is signed to protect against changes.
IX. Clean Up
Once Everything is tested and working, you may want to move the secure boot and IMA private signing keys off of the platform (to somewhere safe), so that attackers cannot use them to sign malicious efi images with sbctl or malicious executables or policies with evmctl. The sensitive private keys are:
/var/lib/sbctl/PK/PK.key
/var/lib/sbctl/KEK/KEK.key
/var/lib/sbctl/db/db.key
~/ima-evm-utils/examples/ima-local-ca.priv
~/ima-evm-utils/examples/privkey_ima.pem