Skip to content

Commit 17feb27

Browse files
committed
Rework sealed build process
Main goal is to reduce signing logic duplication between the systemd-boot and UKI generation. However, this quickly snowballed into wanting to actually verify by providing a custom secure boot keys to bcvk that things worked. This depends on bootc-dev/bcvk#170 Now as part of that, I ran into what I think are bugs in pesign; this cuts things back over to using sbsign. I'll file a tracker for that separately. Finally as part of this, just remove the TMT example that builds a sealed image but doesn't actually verify it works - it's already drifted from what we do outside here. Ultimately what we need is to shift some of this into the Fedora examples and we just fetch it here anyways. Assisted-by: Claude Code (Sonnet 4.5) Signed-off-by: Colin Walters <walters@verbum.org>
1 parent e5db66e commit 17feb27

34 files changed

+251
-583
lines changed

.github/actions/bootc-ubuntu-setup/action.yml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,24 @@ runs:
6565
- name: Install libvirt and virtualization stack
6666
if: ${{ inputs.libvirt == 'true' }}
6767
shell: bash
68+
env:
69+
GH_TOKEN: ${{ github.token }}
6870
run: |
6971
set -xeuo pipefail
7072
export BCVK_VERSION=0.8.0
71-
/bin/time -f '%E %C' sudo apt install -y libkrb5-dev pkg-config libvirt-dev genisoimage qemu-utils qemu-kvm virtiofsd libvirt-daemon-system
73+
/bin/time -f '%E %C' sudo apt install -y libkrb5-dev pkg-config libvirt-dev genisoimage qemu-utils qemu-kvm virtiofsd libvirt-daemon-system python3-virt-firmware
7274
# Something in the stack is overriding this, but we want session right now for bcvk
7375
echo LIBVIRT_DEFAULT_URI=qemu:///session >> $GITHUB_ENV
7476
td=$(mktemp -d)
7577
cd $td
76-
# Install bcvk
77-
target=bcvk-$(arch)-unknown-linux-gnu
78-
/bin/time -f '%E %C' curl -LO https://github.com/bootc-dev/bcvk/releases/download/v${BCVK_VERSION}/${target}.tar.gz
79-
tar xzf ${target}.tar.gz
80-
sudo install -T ${target} /usr/bin/bcvk
78+
# Install bcvk from PR 172
79+
gh run download 20107212783 --name bcvk-binary-tests --repo bootc-dev/bcvk
80+
sudo install -m 755 bcvk /usr/bin/bcvk
81+
# Install bcvk from release
82+
# target=bcvk-$(arch)-unknown-linux-gnu
83+
# /bin/time -f '%E %C' curl -LO https://github.com/bootc-dev/bcvk/releases/download/v${BCVK_VERSION}/${target}.tar.gz
84+
# tar xzf ${target}.tar.gz
85+
# sudo install -T ${target} /usr/bin/bcvk
8186
cd -
8287
rm -rf "$td"
8388

Dockerfile

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,28 @@ WORKDIR /src
4141
# First we download all of our Rust dependencies
4242
RUN --mount=type=cache,target=/src/target --mount=type=cache,target=/var/roothome cargo fetch
4343

44+
FROM buildroot as sdboot-content
45+
# Writes to /out
46+
RUN /src/contrib/packaging/configure-systemdboot download
47+
48+
# NOTE: Every RUN instruction past this point should use `--network=none`; we want to ensure
49+
# all external dependencies are clearly delineated.
50+
4451
FROM buildroot as build
4552
# Version for RPM build (optional, computed from git in Justfile)
4653
ARG pkgversion
4754
# Build RPM directly from source, using cached target directory
4855
RUN --mount=type=cache,target=/src/target --mount=type=cache,target=/var/roothome --network=none RPM_VERSION="${pkgversion}" /src/contrib/packaging/build-rpm
4956

57+
FROM buildroot as sdboot-signed
58+
# The secureboot key and cert are passed via Justfile
59+
# We write the signed binary into /out
60+
RUN --network=none \
61+
--mount=type=bind,from=sdboot-content,target=/run/sdboot-package \
62+
--mount=type=secret,id=secureboot_key \
63+
--mount=type=secret,id=secureboot_cert \
64+
/src/contrib/packaging/configure-systemdboot sign
65+
5066
# This "build" includes our unit tests
5167
FROM build as units
5268
# A place that we're more likely to be able to set xattrs
@@ -62,7 +78,10 @@ RUN --mount=type=cache,target=/src/target --mount=type=cache,target=/var/roothom
6278
FROM base
6379
# See the Justfile for possible variants
6480
ARG variant
65-
RUN --mount=type=bind,from=packaging,target=/run/packaging /run/packaging/configure-variant "${variant}"
81+
RUN --network=none --mount=type=bind,from=packaging,target=/run/packaging \
82+
--mount=type=bind,from=sdboot-content,target=/run/sdboot-content \
83+
--mount=type=bind,from=sdboot-signed,target=/run/sdboot-signed \
84+
/run/packaging/configure-variant "${variant}"
6685
# Support overriding the rootfs at build time conveniently
6786
ARG rootfs
6887
RUN --mount=type=bind,from=packaging,target=/run/packaging /run/packaging/configure-rootfs "${variant}" "${rootfs}"

Dockerfile.cfsuki

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,25 @@
11
# Override via --build-arg=base=<image> to use a different base
22
ARG base=localhost/bootc
3-
# This is where we get the tools to build the UKI
4-
ARG buildroot=quay.io/centos/centos:stream10
5-
63
FROM $base AS base
74

8-
FROM $buildroot as buildroot-base
5+
FROM base as kernel
96
RUN <<EORUN
107
set -xeuo pipefail
11-
12-
# systemd-udev is required for /usr/lib/systemd/systemd-measure which
13-
# is used by ukify as invoked with the `--measure` flag below. Not
14-
# strictly required, but nice to have the measured PCR values in the
15-
# output.
16-
dnf install -y systemd-ukify systemd-udev pesign openssl
17-
dnf clean all
8+
. /usr/lib/os-release
9+
case $ID in
10+
centos|rhel)
11+
dnf config-manager --set-enabled crb
12+
# Enable EPEL for sbsigntools
13+
dnf -y install epel-release
14+
;;
15+
esac
16+
dnf -y install systemd-ukify sbsigntools
1817
EORUN
19-
20-
FROM buildroot-base as kernel
2118
# Must be passed
2219
ARG COMPOSEFS_FSVERITY
23-
RUN --mount=type=secret,id=key \
24-
--mount=type=secret,id=cert \
20+
RUN --network=none \
21+
--mount=type=secret,id=secureboot_key \
22+
--mount=type=secret,id=secureboot_cert \
2523
--mount=type=bind,from=base,target=/target \
2624
<<EOF
2725
set -xeuo pipefail
@@ -31,30 +29,24 @@ RUN --mount=type=secret,id=key \
3129

3230
cmdline="composefs=${COMPOSEFS_FSVERITY} console=ttyS0,115200n8 console=hvc0 enforcing=0 rw"
3331

34-
# pesign uses NSS database so create it from input cert/key
35-
mkdir pesign
36-
certutil -N -d pesign --empty-password
37-
openssl pkcs12 -export -password 'pass:' -inkey /run/secrets/key -in /run/secrets/cert -out db.p12
38-
pk12util -i db.p12 -W '' -d pesign
39-
subject=$(openssl x509 -in /run/secrets/cert -subject | grep '^subject=CN=' | sed 's/^subject=CN=//')
40-
32+
# Use sbsign to re-sign the entire UKI with our key
4133
kver=$(cd /target/usr/lib/modules && echo *)
4234
ukify build \
4335
--linux "/target/usr/lib/modules/$kver/vmlinuz" \
4436
--initrd "/target/usr/lib/modules/$kver/initramfs.img" \
4537
--uname="${kver}" \
4638
--cmdline "${cmdline}" \
4739
--os-release "@/target/usr/lib/os-release" \
48-
--signtool pesign \
49-
--secureboot-certificate-dir "pesign" \
50-
--secureboot-certificate-name "${subject}" \
40+
--signtool sbsign \
41+
--secureboot-private-key "/run/secrets/secureboot_key" \
42+
--secureboot-certificate "/run/secrets/secureboot_cert" \
5143
--measure \
5244
--json pretty \
5345
--output "/boot/$kver.efi"
5446
EOF
5547

5648
FROM base as final
57-
RUN --mount=type=bind,from=kernel,target=/run/kernel <<EOF
49+
RUN --network=none --mount=type=bind,from=kernel,target=/run/kernel <<EOF
5850
set -xeuo pipefail
5951
kver=$(cd /usr/lib/modules && echo *)
6052
mkdir -p /boot/EFI/Linux

Dockerfile.sdboot

Lines changed: 0 additions & 50 deletions
This file was deleted.

Justfile

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ base := env("BOOTC_base", "quay.io/centos-bootc/centos-bootc:stream10")
2525
buildroot_base := env("BOOTC_buildroot_base", "quay.io/centos/centos:stream10")
2626

2727
testimage_label := "bootc.testimage=1"
28+
# Images used by hack/lbi; keep in sync
29+
lbi_images := "quay.io/curl/curl:latest quay.io/curl/curl-base:latest registry.access.redhat.com/ubi9/podman:latest"
2830
# We used to have --jobs=4 here but sometimes that'd hit this
2931
# ```
3032
# [2/3] STEP 2/2: RUN --mount=type=bind,from=context,target=/run/context <<EORUN (set -xeuo pipefail...)
@@ -34,21 +36,23 @@ testimage_label := "bootc.testimage=1"
3436
# /bin/sh: line 3: cd: /run/context/: Permission denied
3537
# ```
3638
# TODO: Gather more info and file a buildah bug
37-
base_buildargs := ""
38-
buildargs := "--build-arg=base=" + base + " --build-arg=variant=" + variant
39-
40-
# Build the container image from current sources.
39+
generic_buildargs := ""
40+
# Args for package building (no secrets needed, just builds RPMs)
41+
base_buildargs := generic_buildargs + " --build-arg=base=" + base + " --build-arg=variant=" + variant
42+
buildargs := base_buildargs + " --secret=id=secureboot_key,src=target/test-secureboot/db.key --secret=id=secureboot_cert,src=target/test-secureboot/db.crt"
43+
# Args for build-sealed (no base arg, it sets that itself)
44+
sealed_buildargs := "--build-arg=variant=" + variant + " --secret=id=secureboot_key,src=target/test-secureboot/db.key --secret=id=secureboot_cert,src=target/test-secureboot/db.crt"
45+
46+
# The default target: build the container image from current sources.
4147
# Note commonly you might want to override the base image via e.g.
4248
# `just build --build-arg=base=quay.io/fedora/fedora-bootc:42`
43-
build: package
49+
build: package _keygen
4450
podman build {{base_buildargs}} -t {{base_img}}-bin {{buildargs}} .
45-
./tests/build-sealed {{variant}} {{base_img}}-bin {{base_img}} {{buildroot_base}}
51+
./hack/build-sealed {{variant}} {{base_img}}-bin {{base_img}} {{sealed_buildargs}}
4652

47-
# Build the container image using pre-existing packages from PATH
48-
build-from-package PATH:
49-
# @just copy-packages-from {{PATH}}
50-
podman build {{base_buildargs}} -t {{base_img}}-bin {{buildargs}} .
51-
./tests/build-sealed {{variant}} {{base_img}}-bin {{base_img}} {{buildroot_base}}
53+
# Generate Secure Boot keys (only for our own CI/testing)
54+
_keygen:
55+
./hack/generate-secureboot-keys
5256

5357
# Build a sealed image from current sources.
5458
build-sealed:
@@ -69,7 +73,7 @@ _packagecontainer:
6973
VERSION="${TIMESTAMP}.g${COMMIT}"
7074
fi
7175
echo "Building RPM with version: ${VERSION}"
72-
podman build {{base_buildargs}} {{buildargs}} --build-arg=pkgversion=${VERSION} -t localhost/bootc-pkg --target=build .
76+
podman build {{base_buildargs}} --build-arg=pkgversion=${VERSION} -t localhost/bootc-pkg --target=build .
7377

7478
# Build packages (e.g. RPM) into target/packages/
7579
# Any old packages will be removed.
@@ -96,20 +100,28 @@ copy-packages-from PATH:
96100
chmod a+rx target target/packages
97101
chmod a+r target/packages/*.rpm
98102

103+
# Build the container image using pre-existing packages from PATH
104+
# Note: The Dockerfile reads from target/packages/, so copy the packages there first
105+
# if they're in a different location.
106+
build-from-package PATH: _keygen
107+
@if [ "{{PATH}}" != "target/packages" ]; then just copy-packages-from {{PATH}}; fi
108+
podman build {{base_buildargs}} -t {{base_img}}-bin {{buildargs}} .
109+
./hack/build-sealed {{variant}} {{base_img}}-bin {{base_img}} {{sealed_buildargs}}
110+
111+
# Pull images used by hack/lbi
112+
_pull-lbi-images:
113+
podman pull -q --retry 5 --retry-delay 5s {{lbi_images}}
114+
99115
# This container image has additional testing content and utilities
100-
build-integration-test-image: build
116+
build-integration-test-image: build _pull-lbi-images
101117
cd hack && podman build {{base_buildargs}} -t {{integration_img}}-bin -f Containerfile .
102-
./tests/build-sealed {{variant}} {{integration_img}}-bin {{integration_img}} {{buildroot_base}}
103-
# Keep these in sync with what's used in hack/lbi
104-
podman pull -q --retry 5 --retry-delay 5s quay.io/curl/curl:latest quay.io/curl/curl-base:latest registry.access.redhat.com/ubi9/podman:latest
118+
./hack/build-sealed {{variant}} {{integration_img}}-bin {{integration_img}} {{sealed_buildargs}}
105119

106120
# Build integration test image using pre-existing packages from PATH
107-
build-integration-test-image-from-package PATH:
121+
build-integration-test-image-from-package PATH: _pull-lbi-images
108122
@just build-from-package {{PATH}}
109123
cd hack && podman build {{base_buildargs}} -t {{integration_img}}-bin -f Containerfile .
110-
./tests/build-sealed {{variant}} {{integration_img}}-bin {{integration_img}} {{buildroot_base}}
111-
# Keep these in sync with what's used in hack/lbi
112-
podman pull -q --retry 5 --retry-delay 5s quay.io/curl/curl:latest quay.io/curl/curl-base:latest registry.access.redhat.com/ubi9/podman:latest
124+
./hack/build-sealed {{variant}} {{integration_img}}-bin {{integration_img}} {{sealed_buildargs}}
113125

114126
# Build+test using the `composefs-sealeduki-sdboot` variant.
115127
test-composefs:
@@ -146,7 +158,7 @@ test-tmt *ARGS: build-integration-test-image _build-upgrade-image
146158
# Generate a local synthetic upgrade
147159
_build-upgrade-image:
148160
cat tmt/tests/Dockerfile.upgrade | podman build -t {{integration_upgrade_img}}-bin --from={{integration_img}}-bin -
149-
./tests/build-sealed {{variant}} {{integration_upgrade_img}}-bin {{integration_upgrade_img}} {{buildroot_base}}
161+
./hack/build-sealed {{variant}} {{integration_upgrade_img}}-bin {{integration_upgrade_img}} {{sealed_buildargs}}
150162

151163
# Assume the localhost/bootc-integration image is up to date, and just run tests.
152164
# Useful for iterating on tests quickly.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/bin/bash
2+
# Helper for signing and re-injecting systemd-boot
3+
set -euo pipefail
4+
op=$1
5+
shift
6+
7+
sdboot="usr/lib/systemd/boot/efi/systemd-bootx64.efi"
8+
sdboot_bn=$(basename ${sdboot})
9+
10+
case $op in
11+
download)
12+
mkdir -p /out
13+
cd /out
14+
dnf -y download systemd-boot-unsigned
15+
;;
16+
sign)
17+
mkdir -p /out
18+
rpm -Uvh /run/sdboot-package/out/*.rpm
19+
# Sign with sbsign using db certificate and key
20+
sbsign \
21+
--key /run/secrets/secureboot_key \
22+
--cert /run/secrets/secureboot_cert \
23+
--output /out/${sdboot_bn} \
24+
/${sdboot}
25+
ls -al /out/${sdboot_bn}
26+
;;
27+
*) echo "Unknown operation $op" 1>&2; exit 1
28+
;;
29+
esac

contrib/packaging/configure-variant

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
# Configure system for a specific bootc variant
33
set -xeuo pipefail
44

5+
dn=$(dirname $0)
6+
57
VARIANT="${1:-}"
68

79
if [ -z "$VARIANT" ]; then
@@ -12,8 +14,14 @@ fi
1214
# Handle variant-specific configuration
1315
case "${VARIANT}" in
1416
*-sdboot)
15-
# Install systemd-boot and remove bootupd
16-
dnf -y install systemd-boot-unsigned
17+
# Install systemd-boot and remove bootupd;
18+
# We downloaded this in an earlier phase
19+
sdboot="usr/lib/systemd/boot/efi/systemd-bootx64.efi"
20+
sdboot_bn=$(basename ${sdboot})
21+
rpm -Uvh /run/sdboot-content/out/*.rpm
22+
# And override with our signed binary
23+
install -m 0644 /run/sdboot-signed/out/${sdboot_bn} /${sdboot}
24+
1725
# Uninstall bootupd
1826
rpm -e bootupd
1927
rm -rf /usr/lib/bootupd/updates

contrib/packaging/fedora-extra.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ git-core
77
jq
88
# We now always build a package in the container build
99
rpm-build
10+
# Used for signing
11+
sbsigntools
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# This file defines the package name for systemd-boot
2+
systemd-boot-unsigned

contrib/packaging/install-buildroot

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ set -xeuo pipefail
44
cd $(dirname $0)
55
. /usr/lib/os-release
66
case $ID in
7-
centos|rhel) dnf config-manager --set-enabled crb;;
7+
centos|rhel)
8+
dnf config-manager --set-enabled crb
9+
# Enable EPEL for sbsigntools
10+
dnf -y install epel-release
11+
;;
812
fedora) dnf -y install dnf-utils 'dnf5-command(builddep)';;
913
esac
1014
# Handle version skew, xref https://gitlab.com/redhat/centos-stream/containers/bootc/-/issues/1174

0 commit comments

Comments
 (0)