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 four 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 (16.0) version.
The kernel is quite old (6.12.0), which means the ima policy file cannot have any comments. Fedora is running 6.15.9.
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.
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".
- Virt-manager does not automatically recognize openSUSE Leap 16, so manually select "openSUSE unknown".
- 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 /usr/local/bin/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/ima_pub_keys
build a new shimx64.efi
$ cd
$ git clone https://github.com/rhboot/shim.git
$ cd shim
$ 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 cp shimx64.efi /boot/efi/EFI/opensuse
$ sudo /usr/local/bin/sbctl sign --save /boot/efi/EFI/opensuse/shimx64.efi
III. Create and enroll our own sb keys:
- reboot into UEFI setup:
# efibootmgr -n 1
# reboot
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. Enroll the local UEFI keys (stored in /usr/share/secureboot):
# sbctl enroll-keys --tpm-eventlog
c. Secureboot sign all the efi 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. enroll the ima-ca key:
# mokutil --import /home/<user>/ima-evm-utils/examples/ima-local-ca.x509
f. reboot
g. 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).
h. 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
IV. Build UKI Image and sign it (as root):
a. Create a signed uki image with ukify - modify the paths and cmdline for your system.
For the cmdline use /proc/cmdline, deleting the entry before "root=" and adding
"ima_template=ima-sig" at the end.
Mine looked like:
ukify build \
--linux=/boot/vmlinuz \
--initrd=/boot/initrd \
--cmdline='root= ... ima_template=ima-sig' \
--secureboot-private-key=/var/lib/sbctl/keys/db/db.key \
--secureboot-certificate=/var/lib/sbctl/keys/db/db.pem
b. # cp vmlinuz...efi /boot/efi/EFI/opensuse
c. enroll the newshim and UKI
# kernel-bootcfg --add-uki /boot/efi/EFI/opensuse/vmlinuz.efi \
--boot-order 0 --title "Opensuse Leap 16 UKI" --shim /boot/efi/EFI/opensuse/shimx64.efi
d. reboot
The uki will boot without the annoying 70 second delay. YAY!
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.)
V. Provision TPM and enroll LUKS key
a. 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>
NOTE: it is ok if the evictcontrol fails - (someone already did this for us).
b. add " none tpm2-device=auto" to the end of the lines in /etc/crypttab
(If the line already has "none" in it, just add ",tpm2-device=auto" to the end.)
c. Rebuild initrd
# dracut --force
d Rebuild the uki (IV a, and b above)
e. reboot
f. 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
# reboot
This time, the encryption keys should be loaded automatically from the TPM
VI Create ima policy and Sign all executables
a. As root, cd to the ima-evm-utils/examples directory (where the local IMA keys were generated)
b. # 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
c. sign the new ima-policy:
# evmctl ima_sign -k privkey_ima.pem /etc/sysconfig/ima-policy
sign all executables:
# 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, and some benign find errors.
d. reboot
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).
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