Configuring UEFI Secure Boot¶
Secure Boot is supported in UEFI installations only. It is not used when booting StarlingX as a legacy (Bios) boot target.
StarlingX currently does not support switching from legacy (Bios) to UEFI mode after a server has been installed. Doing so requires a reinstallation of the system. This also means that upgrading from a legacy (Bios) install to a secure boot install (UEFI) is not supported.
When upgrading a StarlingX server from a version which does not support secure boot to a version that does, do not enable secure boot in UEFI firmware until the upgrade is complete.
For each server that is going to use secure boot, do the following in accordance with the board manufacturer’s documentation:
Take Ownership of Secure Boot
you must insert the public key of a key pair, that your organization owns into the server’s UEFI Secure Boot KEK database.
this is required to enable future changes to the Secure Boot configuration from USER MODE while the server is running.
without this, changes would require taking the server out of service and entering SETUP mode.
specifically, you must
Create a KEK Key Pair
generate your own Secure Boot KEK certificate (public key) and private key.
use the same KEK key pair across all servers and StarlingX systems that your organization owns.
this key pair should serve as your company’s StarlingX Secure Boot KEK key pair.
Populate the KEK Database
add your company’s Secure Boot KEK certificate (public key) to the server’s Secure Boot KEK database.
securely store the corresponding private key so it can be used in the future to update Secure Boot configurations across your StarlingX servers.
Populate the Authorized Database
insert the StarlingX’s certificate (public key) into the server’s Secure Boot database (authorized database).
You may need to work with your hardware vendor to have the KEK and database certificates installed.
There is often an option in the UEFI setup utility which allows a user to browse to a file containing a certificate to be loaded in the authorized database. This option may be hidden in the UEFI setup utility unless UEFI mode is enabled, and secure boot is enabled.
Many motherboards ship with Microsoft secure boot certificates pre-programmed in the UEFI certificate database. These certificates may be required to boot UEFI drivers for video cards, RAID controllers, or NICs (for example, the PXE boot software for a NIC may have been signed by a Microsoft certificate). While certificates can usually be removed from the certificate database (again, this is UEFI implementation specific) it may be required that you keep the Microsoft certificates to allow for complete system operation.
Mixed combinations of secure boot and non-secure boot nodes are supported. For example, a controller node may secure boot, while a worker node may not. Secure boot must be enabled in the UEFI firmware of each node for that node to be protected.
Build Considerations for Signing Packages for UEFI Secure Boot¶
The StarlingX build environment has provisions for calling out to a signing server for purposes of creating a secure boot load. At this time StarlingX does not include an implementation of the signing server. The following describes how the signing process is intended to work in the context of a Debian build. You may find it helpful in implementing your own signing server.
The secure boot verification chain for StarlingX Debian is:
UEFI firmware verifies shim image (signed with the boot key)
shim verifies grub image (signed with the shim key)
grub verifies kernel images, initramfs, and LockDown.efi (signed with the grub GPG key)
Prerequisites
The following environment variables must be set before requesting secure boot signing:
export SIGNING_SERVER="<signing-server-hostname-or-ip>"
export SIGNING_USER="<username-with-ssh-access-to-signing-server>"
export SIGNING_KEY_NAME="<key-name>" # optional, defaults to 'default'
SSH key-based authentication to the signing server must be configured. Use stx control keys-add --key-type=signing-server --key=<key-file> to provide the SSH private key to the build environment.
Build sequence with signing
stx shell
downloader
build-pkgs
export SIGNING_SERVER="signing_user@signing_server_ip"
export SIGNING_USER="signing_user"
sign-secure-boot_debian
build-image
The sign-secure-boot_debian script performs signing in three phases:
Phase 1: Sign shim and grub packages (before build-image)
The shim and grub EFI binaries are extracted from their built packages, sent to the signing server, signed, and the packages are repacked with the signed binaries and re-uploaded to the local build repository.
Phase 2 & 3: Prepare LAT hooks for kernel/initramfs signing
The signing scripts for kernel and initramfs are inserted into the LAT
configuration file (base-<codename>.yaml) as hook scripts. These
hooks execute during build-image at the appropriate points
in the image assembly process.
Complete Signing Request Table¶
The following table lists all signing requests made during a complete build, in the order they occur:
# |
Sign Type |
File |
When |
|---|---|---|---|
1 |
shim |
shimx64.efi |
sign-secure-boot_debian |
2 |
shimtool |
mmx64.efi |
sign-secure-boot_debian |
3 |
grub |
grubx64.efi |
sign-secure-boot_debian |
4 |
grub-gpg |
LockDown.efi |
build-image (rootfs hook) |
5 |
grub-gpg |
vmlinuz-<version>-rt-amd64 |
build-image (rootfs hook) |
6 |
grub-gpg |
vmlinuz-<version>-amd64 |
build-image (rootfs hook) |
7 |
grub-gpg |
starlingx-initramfs-ostree-image-…cpio.gz |
build-image (initramfs hook) |
8 |
grub-gpg |
initrd-mini |
build-image (initramfs hook) |
Note
The sign types shim, shimtool, and grub all use sbsign
for EFI binary signing but differ in the keys and output file names
that are used:
shim: signs
shimx64.efiwith the boot key and outputsbootx64.efi. The boot key’s public certificate must be enrolled in UEFI firmware — this is the root of the trust chain.grub: signs
grubx64.efiwith the shim key and outputsgrubx64.efi(replaced in-place). Grub is the second-stage bootloader, verified by shim.shimtool: signs
mmx64.efi(MokManager — the shim key management tool) with the shim key and outputsmmx64.efi.signed. MokManager allows users to enroll additional keys at boot time; it is also verified by shim.
In summary: the boot key signs shim (verified by firmware), and the shim key signs both grub and MokManager (verified by shim).
The grub-gpg type is fundamentally different — it produces a
detached |GPG| signature (.sig file) rather than an embedded
EFI signature. The GPG public key is embedded in grub, enabling grub
to verify kernels, initramfs, and LockDown.efi before executing them.
Signing Server Interface¶
All signing requests use the following protocol via SSH:
# 1. Request an upload directory on the signing server
REQUEST=$(ssh ${SIGNING_USER}@${SIGNING_SERVER} \
sudo /opt/signing/sign-debian.sh -r)
UPLOAD_PATH=${REQUEST#*Upload: }
# 2. Upload the file to be signed
scp <file> ${SIGNING_USER}@${SIGNING_SERVER}:${UPLOAD_PATH}
# 3. Request signing
ssh ${SIGNING_USER}@${SIGNING_SERVER} \
sudo /opt/signing/sign-debian.sh \
-i ${UPLOAD_PATH}/<filename> \
-t <sign-type> \
-k <key-name>
# 4. Download the signed result
scp ${SIGNING_USER}@${SIGNING_SERVER}:${UPLOAD_PATH}/<output-file> ./
The sign-debian.sh interface on the signing server:
Usage:
sign-debian.sh [options]
[-i <file>] - input unsigned file
[-t <type>] - type of signing to do
[-k <name>] - signing key name (default: 'default')
[-r] - request an upload path
Sign types:
-t shim - signs a shim EFI binary with the boot key
(output: bootx64.efi)
-t grub - signs a GRUB EFI binary with the shim key
(output: grubx64.efi)
-t shimtool - signs a shim tool EFI binary with the shim key
(output: <filename>.signed)
-t grub-gpg - signs a kernel/initrd/LockDown with the grub GPG key
(output: <filename>.sig detached signature)
Dual Signing for Key Rotation¶
When replacing a secure boot key (e.g. due to expiry or compromise),
there is a transition period where deployed systems may have either the
old or the new public key enrolled in firmware. To support this, the
signing server accepts a comma-separated list of key names via the
-k option:
ssh ${SIGNING_USER}@${SIGNING_SERVER} \
sudo /opt/signing/sign-debian.sh \
-i ${UPLOAD_PATH}/shimx64.efi \
-t shim \
-k old-key,new-key
When multiple key names are provided, the signing server signs the binary iteratively with each key, appending the previous key’s certificate to the signature. The resulting binary can be verified by firmware that trusts either key, allowing a gradual rollout of the new certificate to the fleet without breaking boot on systems that have not yet been updated.
Set SIGNING_KEY_NAME to a comma-separated list in the build
environment to enable dual signing:
export SIGNING_KEY_NAME="production-2024,production-2026"
Note
Dual signing only applies to EFI binary signing (-t shim,
-t grub, -t shimtool). GPG-based signing (-t grub-gpg)
does not support multiple keys — grub validates against a single
embedded GPG public key.
Signing Keys¶
Three key types are used in the signing process:
Key |
Type |
Purpose |
|---|---|---|
boot |
X.509 (RSA 2048) |
Signs shim; public key enrolled in UEFI firmware Secure Boot database |
shim |
X.509 (RSA 2048) |
Signs grub and shim tools; public key is embedded in the shim binary |
grub-gpg |
GPG (RSA 4096) |
Signs kernels, initramfs, LockDown.efi; public key is embedded in grub |
Keys Management¶
Upstream stx public keys repo: https://opendev.org/starlingx/public-keys
The keys under cgcs-root/public-keys are the public keys used in
the verification process of secure boot for StarlingX Debian.
Note
To use your own signing keys in a private build, create your own
fork of the upstream starlingx/public-keys repository containing
your organization’s public keys, and modify your repo manifest to
reference your fork instead of the upstream repository. This ensures
that your boot images embed your certificates without modifying the
core StarlingX source.
Public Key Files¶
tis-boot.crtThe public key to be programmed into UEFI firmware to verify
bootx64.efi(the signed shim image).tis-shim.derThe public key used by shim to verify
grubx64.efi(signed grub image) andmmx64.efi(signed shim tool image).boot_pub_keyThe public key used by grub to verify signed kernel images, initramfs images, and LockDown.efi.
TiBoot.crtSame as
tis-boot.crtin DER format. Installed as/CERTS/TiBoot.crtin theefi.imgwithin the ISO image.
Creating Substitute Keys¶
Create boot key pair (
tis-boot.crt/TiBoot.crt):openssl req -new -x509 -newkey rsa:2048 -keyout BOOT.priv \ -outform DER -out BOOT.der -days 36500 \ -subj "/CN=My Boot/" -nodes openssl x509 -inform der -in BOOT.der -out BOOT.pem cp BOOT.pem tis-boot.crt cp BOOT.priv tis-boot.key cp BOOT.der TiBoot.crt
Create shim key pair (same method, different CN):
openssl req -new -x509 -newkey rsa:2048 -keyout SHIM.priv \ -outform DER -out SHIM.der -days 36500 \ -subj "/CN=My Shim/" -nodes openssl x509 -inform der -in SHIM.der -out tis-shim.der cp SHIM.priv tis-shim.key
Create grub GPG key pair (
boot_pub_key):#!/bin/bash key_dir="./" priv_key="${key_dir}/BOOT-GPG-PRIVKEY-SecureBootCore" pub_key="${key_dir}/BOOT-GPG-KEY-SecureBootCore" name_real="SecureBootCore" pw="PASSWORD" USE_PW="Passphrase: PASSWORD" cat >"${key_dir}/gen_keyring" <<EOF Key-Type: RSA Key-Length: 4096 Name-Real: ${name_real} Name-Comment: EXAMPLE Name-Email: a@b.com Expire-Date: 0 ${USE_PW} %commit %echo keyring ${name_real} created EOF gpg --homedir "${key_dir}" --batch --yes --gen-key \ "${key_dir}/gen_keyring" gpg --homedir "${key_dir}" --export "${name_real}" \ > ${key_dir}/boot_pub_key gpg --homedir "${key_dir}" --export-secret-keys \ --pinentry-mode=loopback --passphrase "${pw}" \ --armor "${name_real}" > "${priv_key}"
Signing Commands (on the Signing Server)¶
For
-t shim,-t grub,-t shimtool(EFI binary signing):sbsign --key $KEYPATH/$KEYNAME.key \ --cert $KEYPATH/$KEYNAME.crt \ --output $SIGNEDFILE \ $UNSIGNEDFILEFor
-t grub-gpg(GPG detached signature):gpg2 --batch \ --homedir ${GPGHOME} \ --passphrase PASSWORD \ --import ${KEYPATH}/${BOOT_GPG_PRI_KEY} echo 'PASSWORD' | \ gpg2 --pinentry-mode loopback \ --batch \ --homedir ${GPGHOME} \ -u SecureBootCore \ --detach-sign \ --passphrase-fd 0 \ ${FILEIN}