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:

  1. UEFI firmware verifies shim image (signed with the boot key)

  2. shim verifies grub image (signed with the shim key)

  3. 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.efi with the boot key and outputs bootx64.efi. The boot key’s public certificate must be enrolled in UEFI firmware — this is the root of the trust chain.

  • grub: signs grubx64.efi with the shim key and outputs grubx64.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 outputs mmx64.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.crt

The public key to be programmed into UEFI firmware to verify bootx64.efi (the signed shim image).

tis-shim.der

The public key used by shim to verify grubx64.efi (signed grub image) and mmx64.efi (signed shim tool image).

boot_pub_key

The public key used by grub to verify signed kernel images, initramfs images, and LockDown.efi.

TiBoot.crt

Same as tis-boot.crt in DER format. Installed as /CERTS/TiBoot.crt in the efi.img within the ISO image.

Creating Substitute Keys

  1. 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
    
  2. 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
    
  3. 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 \
           $UNSIGNEDFILE
    
  • For -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}