1
0
mirror of https://github.com/containers/bootc.git synced 2026-02-05 06:45:13 +01:00

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 https://github.com/bootc-dev/bcvk/pull/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>
This commit is contained in:
Colin Walters
2025-12-02 20:45:40 -05:00
parent 089dedcc1c
commit 6f69534f9b
34 changed files with 250 additions and 582 deletions

View File

@@ -65,19 +65,24 @@ runs:
- name: Install libvirt and virtualization stack
if: ${{ inputs.libvirt == 'true' }}
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
set -xeuo pipefail
export BCVK_VERSION=0.8.0
/bin/time -f '%E %C' sudo apt install -y libkrb5-dev pkg-config libvirt-dev genisoimage qemu-utils qemu-kvm virtiofsd libvirt-daemon-system
/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
# Something in the stack is overriding this, but we want session right now for bcvk
echo LIBVIRT_DEFAULT_URI=qemu:///session >> $GITHUB_ENV
td=$(mktemp -d)
cd $td
# Install bcvk
target=bcvk-$(arch)-unknown-linux-gnu
/bin/time -f '%E %C' curl -LO https://github.com/bootc-dev/bcvk/releases/download/v${BCVK_VERSION}/${target}.tar.gz
tar xzf ${target}.tar.gz
sudo install -T ${target} /usr/bin/bcvk
# Install bcvk from PR 172
gh run download 20107212783 --name bcvk-binary-tests --repo bootc-dev/bcvk
sudo install -m 755 bcvk /usr/bin/bcvk
# Install bcvk from release
# target=bcvk-$(arch)-unknown-linux-gnu
# /bin/time -f '%E %C' curl -LO https://github.com/bootc-dev/bcvk/releases/download/v${BCVK_VERSION}/${target}.tar.gz
# tar xzf ${target}.tar.gz
# sudo install -T ${target} /usr/bin/bcvk
cd -
rm -rf "$td"

View File

@@ -41,12 +41,28 @@ WORKDIR /src
# First we download all of our Rust dependencies
RUN --mount=type=cache,target=/src/target --mount=type=cache,target=/var/roothome cargo fetch
FROM buildroot as sdboot-content
# Writes to /out
RUN /src/contrib/packaging/configure-systemdboot download
# NOTE: Every RUN instruction past this point should use `--network=none`; we want to ensure
# all external dependencies are clearly delineated.
FROM buildroot as build
# Version for RPM build (optional, computed from git in Justfile)
ARG pkgversion
# Build RPM directly from source, using cached target directory
RUN --mount=type=cache,target=/src/target --mount=type=cache,target=/var/roothome --network=none RPM_VERSION="${pkgversion}" /src/contrib/packaging/build-rpm
FROM buildroot as sdboot-signed
# The secureboot key and cert are passed via Justfile
# We write the signed binary into /out
RUN --network=none \
--mount=type=bind,from=sdboot-content,target=/run/sdboot-package \
--mount=type=secret,id=secureboot_key \
--mount=type=secret,id=secureboot_cert \
/src/contrib/packaging/configure-systemdboot sign
# This "build" includes our unit tests
FROM build as units
# 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
FROM base
# See the Justfile for possible variants
ARG variant
RUN --mount=type=bind,from=packaging,target=/run/packaging /run/packaging/configure-variant "${variant}"
RUN --network=none --mount=type=bind,from=packaging,target=/run/packaging \
--mount=type=bind,from=sdboot-content,target=/run/sdboot-content \
--mount=type=bind,from=sdboot-signed,target=/run/sdboot-signed \
/run/packaging/configure-variant "${variant}"
# Support overriding the rootfs at build time conveniently
ARG rootfs
RUN --mount=type=bind,from=packaging,target=/run/packaging /run/packaging/configure-rootfs "${variant}" "${rootfs}"

View File

@@ -1,27 +1,25 @@
# Override via --build-arg=base=<image> to use a different base
ARG base=localhost/bootc
# This is where we get the tools to build the UKI
ARG buildroot=quay.io/centos/centos:stream10
FROM $base AS base
FROM $buildroot as buildroot-base
FROM base as kernel
RUN <<EORUN
set -xeuo pipefail
# systemd-udev is required for /usr/lib/systemd/systemd-measure which
# is used by ukify as invoked with the `--measure` flag below. Not
# strictly required, but nice to have the measured PCR values in the
# output.
dnf install -y systemd-ukify systemd-udev pesign openssl
dnf clean all
. /usr/lib/os-release
case $ID in
centos|rhel)
dnf config-manager --set-enabled crb
# Enable EPEL for sbsigntools
dnf -y install epel-release
;;
esac
dnf -y install systemd-ukify sbsigntools
EORUN
FROM buildroot-base as kernel
# Must be passed
ARG COMPOSEFS_FSVERITY
RUN --mount=type=secret,id=key \
--mount=type=secret,id=cert \
RUN --network=none \
--mount=type=secret,id=secureboot_key \
--mount=type=secret,id=secureboot_cert \
--mount=type=bind,from=base,target=/target \
<<EOF
set -xeuo pipefail
@@ -31,13 +29,7 @@ RUN --mount=type=secret,id=key \
cmdline="composefs=${COMPOSEFS_FSVERITY} console=ttyS0,115200n8 console=hvc0 enforcing=0 rw"
# pesign uses NSS database so create it from input cert/key
mkdir pesign
certutil -N -d pesign --empty-password
openssl pkcs12 -export -password 'pass:' -inkey /run/secrets/key -in /run/secrets/cert -out db.p12
pk12util -i db.p12 -W '' -d pesign
subject=$(openssl x509 -in /run/secrets/cert -subject | grep '^subject=CN=' | sed 's/^subject=CN=//')
# Use sbsign to re-sign the entire UKI with our key
kver=$(cd /target/usr/lib/modules && echo *)
ukify build \
--linux "/target/usr/lib/modules/$kver/vmlinuz" \
@@ -45,16 +37,16 @@ RUN --mount=type=secret,id=key \
--uname="${kver}" \
--cmdline "${cmdline}" \
--os-release "@/target/usr/lib/os-release" \
--signtool pesign \
--secureboot-certificate-dir "pesign" \
--secureboot-certificate-name "${subject}" \
--signtool sbsign \
--secureboot-private-key "/run/secrets/secureboot_key" \
--secureboot-certificate "/run/secrets/secureboot_cert" \
--measure \
--json pretty \
--output "/boot/$kver.efi"
EOF
FROM base as final
RUN --mount=type=bind,from=kernel,target=/run/kernel <<EOF
RUN --network=none --mount=type=bind,from=kernel,target=/run/kernel <<EOF
set -xeuo pipefail
kver=$(cd /usr/lib/modules && echo *)
mkdir -p /boot/EFI/Linux

View File

@@ -1,50 +0,0 @@
# Override via --build-arg=base=<image> to use a different base
ARG base=localhost/bootc
# Image to sign systemd-boot first, BEFORE, installing onto the image
ARG buildroot=quay.io/centos/centos:stream10
FROM $base AS base-unsigned
FROM $buildroot as buildroot-base
RUN <<EORUN
set -xeuo pipefail
dnf install -y pesign openssl
dnf clean all
EORUN
FROM buildroot-base as signer
# Sign sdboot and put it on the target first
RUN --mount=type=secret,id=key \
--mount=type=secret,id=cert \
--mount=type=bind,from=base-unsigned,target=/target \
<<EORUN
set -xeuo pipefail
# pesign uses NSS database so create it from input cert/key
mkdir pesign
certutil -N -d pesign --empty-password
openssl pkcs12 -export -password 'pass:' -inkey /run/secrets/key -in /run/secrets/cert -out db.p12
pk12util -i db.p12 -W '' -d pesign
subject=$(openssl x509 -in /run/secrets/cert -subject | grep '^subject=CN=' | sed 's/^subject=CN=//')
# Sign systemd-boot as well
sdboot="target/usr/lib/systemd/boot/efi/systemd-bootx64.efi"
sdboot_out="/sdboot.efi"
pesign \
--certdir "pesign" \
--certificate "${subject}" \
--in "${sdboot}" \
--out "${sdboot_out}" \
--sign
EORUN
FROM base-unsigned as final
RUN --mount=type=bind,from=signer,target=/run/sdboot \
<<EORUN
set -xeuo pipefail
sdboot=/usr/lib/systemd/boot/efi/systemd-bootx64.efi
# copy signed sdboot from buildroot
cp "/run/sdboot/sdboot.efi" ${sdboot}
EORUN

View File

@@ -25,6 +25,8 @@ base := env("BOOTC_base", "quay.io/centos-bootc/centos-bootc:stream10")
buildroot_base := env("BOOTC_buildroot_base", "quay.io/centos/centos:stream10")
testimage_label := "bootc.testimage=1"
# Images used by hack/lbi; keep in sync
lbi_images := "quay.io/curl/curl:latest quay.io/curl/curl-base:latest registry.access.redhat.com/ubi9/podman:latest"
# We used to have --jobs=4 here but sometimes that'd hit this
# ```
# [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"
# /bin/sh: line 3: cd: /run/context/: Permission denied
# ```
# TODO: Gather more info and file a buildah bug
base_buildargs := ""
buildargs := "--build-arg=base=" + base + " --build-arg=variant=" + variant
generic_buildargs := ""
# Args for package building (no secrets needed, just builds RPMs)
base_buildargs := generic_buildargs + " --build-arg=base=" + base + " --build-arg=variant=" + variant
buildargs := base_buildargs + " --secret=id=secureboot_key,src=target/test-secureboot/db.key --secret=id=secureboot_cert,src=target/test-secureboot/db.crt"
# Args for build-sealed (no base arg, it sets that itself)
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"
# Build the container image from current sources.
# The default target: build the container image from current sources.
# Note commonly you might want to override the base image via e.g.
# `just build --build-arg=base=quay.io/fedora/fedora-bootc:42`
build: package
build: package _keygen
podman build {{base_buildargs}} -t {{base_img}}-bin {{buildargs}} .
./tests/build-sealed {{variant}} {{base_img}}-bin {{base_img}} {{buildroot_base}}
./hack/build-sealed {{variant}} {{base_img}}-bin {{base_img}} {{sealed_buildargs}}
# Build the container image using pre-existing packages from PATH
build-from-package PATH:
# @just copy-packages-from {{PATH}}
podman build {{base_buildargs}} -t {{base_img}}-bin {{buildargs}} .
./tests/build-sealed {{variant}} {{base_img}}-bin {{base_img}} {{buildroot_base}}
# Generate Secure Boot keys (only for our own CI/testing)
_keygen:
./hack/generate-secureboot-keys
# Build a sealed image from current sources.
build-sealed:
@@ -69,7 +73,7 @@ _packagecontainer:
VERSION="${TIMESTAMP}.g${COMMIT}"
fi
echo "Building RPM with version: ${VERSION}"
podman build {{base_buildargs}} {{buildargs}} --build-arg=pkgversion=${VERSION} -t localhost/bootc-pkg --target=build .
podman build {{base_buildargs}} --build-arg=pkgversion=${VERSION} -t localhost/bootc-pkg --target=build .
# Build packages (e.g. RPM) into target/packages/
# Any old packages will be removed.
@@ -96,20 +100,28 @@ copy-packages-from PATH:
chmod a+rx target target/packages
chmod a+r target/packages/*.rpm
# Build the container image using pre-existing packages from PATH
# Note: The Dockerfile reads from target/packages/, so copy the packages there first
# if they're in a different location.
build-from-package PATH: _keygen
@if [ "{{PATH}}" != "target/packages" ]; then just copy-packages-from {{PATH}}; fi
podman build {{base_buildargs}} -t {{base_img}}-bin {{buildargs}} .
./hack/build-sealed {{variant}} {{base_img}}-bin {{base_img}} {{sealed_buildargs}}
# Pull images used by hack/lbi
_pull-lbi-images:
podman pull -q --retry 5 --retry-delay 5s {{lbi_images}}
# This container image has additional testing content and utilities
build-integration-test-image: build
build-integration-test-image: build _pull-lbi-images
cd hack && podman build {{base_buildargs}} -t {{integration_img}}-bin -f Containerfile .
./tests/build-sealed {{variant}} {{integration_img}}-bin {{integration_img}} {{buildroot_base}}
# Keep these in sync with what's used in hack/lbi
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
./hack/build-sealed {{variant}} {{integration_img}}-bin {{integration_img}} {{sealed_buildargs}}
# Build integration test image using pre-existing packages from PATH
build-integration-test-image-from-package PATH:
build-integration-test-image-from-package PATH: _pull-lbi-images
@just build-from-package {{PATH}}
cd hack && podman build {{base_buildargs}} -t {{integration_img}}-bin -f Containerfile .
./tests/build-sealed {{variant}} {{integration_img}}-bin {{integration_img}} {{buildroot_base}}
# Keep these in sync with what's used in hack/lbi
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
./hack/build-sealed {{variant}} {{integration_img}}-bin {{integration_img}} {{sealed_buildargs}}
# Build+test using the `composefs-sealeduki-sdboot` variant.
test-composefs:
@@ -146,7 +158,7 @@ test-tmt *ARGS: build-integration-test-image _build-upgrade-image
# Generate a local synthetic upgrade
_build-upgrade-image:
cat tmt/tests/Dockerfile.upgrade | podman build -t {{integration_upgrade_img}}-bin --from={{integration_img}}-bin -
./tests/build-sealed {{variant}} {{integration_upgrade_img}}-bin {{integration_upgrade_img}} {{buildroot_base}}
./hack/build-sealed {{variant}} {{integration_upgrade_img}}-bin {{integration_upgrade_img}} {{sealed_buildargs}}
# Assume the localhost/bootc-integration image is up to date, and just run tests.
# Useful for iterating on tests quickly.

View File

@@ -0,0 +1,29 @@
#!/bin/bash
# Helper for signing and re-injecting systemd-boot
set -euo pipefail
op=$1
shift
sdboot="usr/lib/systemd/boot/efi/systemd-bootx64.efi"
sdboot_bn=$(basename ${sdboot})
case $op in
download)
mkdir -p /out
cd /out
dnf -y download systemd-boot-unsigned
;;
sign)
mkdir -p /out
rpm -Uvh /run/sdboot-package/out/*.rpm
# Sign with sbsign using db certificate and key
sbsign \
--key /run/secrets/secureboot_key \
--cert /run/secrets/secureboot_cert \
--output /out/${sdboot_bn} \
/${sdboot}
ls -al /out/${sdboot_bn}
;;
*) echo "Unknown operation $op" 1>&2; exit 1
;;
esac

View File

@@ -2,6 +2,8 @@
# Configure system for a specific bootc variant
set -xeuo pipefail
dn=$(dirname $0)
VARIANT="${1:-}"
if [ -z "$VARIANT" ]; then
@@ -12,8 +14,14 @@ fi
# Handle variant-specific configuration
case "${VARIANT}" in
*-sdboot)
# Install systemd-boot and remove bootupd
dnf -y install systemd-boot-unsigned
# Install systemd-boot and remove bootupd;
# We downloaded this in an earlier phase
sdboot="usr/lib/systemd/boot/efi/systemd-bootx64.efi"
sdboot_bn=$(basename ${sdboot})
rpm -Uvh /run/sdboot-content/out/*.rpm
# And override with our signed binary
install -m 0644 /run/sdboot-signed/out/${sdboot_bn} /${sdboot}
# Uninstall bootupd
rpm -e bootupd
rm -rf /usr/lib/bootupd/updates

View File

@@ -7,3 +7,5 @@ git-core
jq
# We now always build a package in the container build
rpm-build
# Used for signing
sbsigntools

View File

@@ -0,0 +1,2 @@
# This file defines the package name for systemd-boot
systemd-boot-unsigned

View File

@@ -4,7 +4,11 @@ set -xeuo pipefail
cd $(dirname $0)
. /usr/lib/os-release
case $ID in
centos|rhel) dnf config-manager --set-enabled crb;;
centos|rhel)
dnf config-manager --set-enabled crb
# Enable EPEL for sbsigntools
dnf -y install epel-release
;;
fedora) dnf -y install dnf-utils 'dnf5-command(builddep)';;
esac
# Handle version skew, xref https://gitlab.com/redhat/centos-stream/containers/bootc/-/issues/1174

View File

@@ -22,4 +22,4 @@ env DRACUT_NO_XATTR=1 dracut --add bootc -vf /usr/lib/modules/$kver/initramfs.im
touch /usr/lib/.bootc-dev-stamp
# Workaround for https://github.com/bootc-dev/bootc/issues/1546
rm -rf /root/buildinfo
rm -rf /root/buildinfo /var/roothome/buildinfo

View File

@@ -14,11 +14,8 @@ const VM_READY_TIMEOUT_SECS: u64 = 60;
const SSH_CONNECTIVITY_MAX_ATTEMPTS: u32 = 60;
const SSH_CONNECTIVITY_RETRY_DELAY_SECS: u64 = 3;
const COMMON_INST_ARGS: &[&str] = &[
// TODO: Pass down the Secure Boot keys for tests if present
"--firmware=uefi-insecure",
"--label=bootc.test=1",
];
// Base args - firmware type will be added dynamically based on secure boot key availability
const COMMON_INST_ARGS: &[&str] = &["--label=bootc.test=1"];
// Metadata field names
const FIELD_TRY_BIND_STORAGE: &str = "try_bind_storage";
@@ -95,6 +92,51 @@ fn detect_distro_from_image(sh: &Shell, image: &str) -> Result<String> {
Ok(distro.to_string())
}
/// Detect if image is a sealed image by checking for /boot/EFI
/// Sealed images have EFI boot components, non-sealed images don't
/// TODO: Have `bootc container status` expose this in a nice way instead of running podman
#[context("Detecting if image is sealed")]
fn is_sealed_image(sh: &Shell, image: &str) -> Result<bool> {
let result = cmd!(sh, "podman run --rm {image} ls /boot").read()?;
Ok(!result.is_empty())
}
/// Default path where secure boot keys are generated for testing
const DEFAULT_SB_KEYS_DIR: &str = "target/test-secureboot";
/// Build firmware arguments for bcvk based on whether the image is sealed
/// and whether secure boot keys are available.
///
/// For sealed images, secure boot keys must be present or an error is returned.
#[context("Building firmware arguments")]
fn build_firmware_args(sh: &Shell, image: &str) -> Result<Vec<String>> {
let is_sealed = is_sealed_image(sh, image)?;
let sb_keys_dir = Utf8Path::new(DEFAULT_SB_KEYS_DIR);
let r = if is_sealed {
if sb_keys_dir.try_exists()? {
let sb_keys_dir = sb_keys_dir.canonicalize_utf8()?;
println!(
"Sealed image detected, using secure boot with keys from: {}",
sb_keys_dir
);
vec![
"--firmware=uefi-secure".to_string(),
format!("--secure-boot-keys={}", sb_keys_dir),
]
} else {
anyhow::bail!(
"Sealed image detected but no secure boot keys found at {}. \
Run 'just generate-secureboot-keys' to generate them.",
sb_keys_dir
);
}
} else {
Vec::new()
};
Ok(r)
}
/// Check if a distro supports --bind-storage-ro
/// CentOS 9 lacks systemd.extra-unit.* support required for bind-storage-ro
fn distro_supports_bind_storage_ro(distro: &str) -> bool {
@@ -240,6 +282,8 @@ pub(crate) fn run_tmt(sh: &Shell, args: &RunTmtArgs) -> Result<()> {
println!("Using bcvk image: {}", image);
println!("Detected distro: {}", distro);
let firmware_args = build_firmware_args(sh, image)?;
// Create tmt-workdir and copy tmt bits to it
// This works around https://github.com/teemtee/tmt/issues/4062
let workdir = Utf8Path::new("target/tmt-workdir");
@@ -348,9 +392,10 @@ pub(crate) fn run_tmt(sh: &Shell, args: &RunTmtArgs) -> Result<()> {
};
// Launch VM with bcvk
let firmware_args_slice = firmware_args.as_slice();
let launch_result = cmd!(
sh,
"bcvk libvirt run --name {vm_name} --detach {COMMON_INST_ARGS...} {plan_bcvk_opts...} {image}"
"bcvk libvirt run --name {vm_name} --detach {firmware_args_slice...} {COMMON_INST_ARGS...} {plan_bcvk_opts...} {image}"
)
.run()
.context("Launching VM with bcvk");
@@ -597,11 +642,14 @@ pub(crate) fn tmt_provision(sh: &Shell, args: &TmtProvisionArgs) -> Result<()> {
println!(" Image: {}", image);
println!(" VM name: {}\n", vm_name);
let firmware_args = build_firmware_args(sh, image)?;
// Launch VM with bcvk
// Use ds=iid-datasource-none to disable cloud-init for faster boot
let firmware_args_slice = firmware_args.as_slice();
cmd!(
sh,
"bcvk libvirt run --name {vm_name} --detach {COMMON_INST_ARGS...} {image}"
"bcvk libvirt run --name {vm_name} --detach {firmware_args_slice...} {COMMON_INST_ARGS...} {image}"
)
.run()
.context("Launching VM with bcvk")?;

37
hack/build-sealed Executable file
View File

@@ -0,0 +1,37 @@
#!/bin/bash
set -euo pipefail
# This should turn into https://github.com/bootc-dev/bootc/issues/1498
dn=$(cd $(dirname $0) && pwd)
variant=$1
shift
# The un-sealed container image we want to use
input_image=$1
shift
# The output container image
output_image=$1
shift
runv() {
set -x
"$@"
}
case $variant in
ostree)
# Nothing to do
echo "Not building a sealed image; forwarding tag"
runv podman tag $input_image $output_image
exit 0
;;
composefs-sealeduki*)
;;
*)
echo "Unknown variant=$variant" 1>&2; exit 1
;;
esac
cfs_digest=$(${dn}/compute-composefs-digest $input_image)
runv podman build -t $output_image \
--build-arg=COMPOSEFS_FSVERITY=${cfs_digest} --build-arg=base=${input_image} "$@" -f Dockerfile.cfsuki .

11
hack/compute-composefs-digest Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/bash
set -euo pipefail
# This just runs `bootc container compute-composefs-digest` in a provided container image
image=$1
shift
# Find the container storage
graphroot=$(podman system info -f '{{.Store.GraphRoot}}')
# --pull=never because we don't want to pollute the output with progress and most use cases
# for this really should be operating on pre-pulled images.
exec podman run --pull=never --quiet --rm --privileged --read-only --security-opt=label=disable -v /sys:/sys:ro --net=none \
-v ${graphroot}:/run/host-container-storage:ro --tmpfs /var "$image" bootc container compute-composefs-digest

17
hack/generate-secureboot-keys Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
set -euo pipefail
# Generate Secure Boot keys, only intended to be used for our CI pipeline.
d=target/test-secureboot
# This file existing signals completion
if test -f "${d}/.done"; then exit 0; fi
mkdir -p "$d"
cd "$d"
systemd-id128 new -u > GUID.txt
openssl req -quiet -newkey rsa:4096 -nodes -keyout PK.key -new -x509 -sha256 -days 3650 -subj '/CN=Test Platform Key/' -out PK.crt
openssl x509 -outform DER -in PK.crt -out PK.cer
openssl req -quiet -newkey rsa:4096 -nodes -keyout KEK.key -new -x509 -sha256 -days 3650 -subj '/CN=Test Key Exchange Key/' -out KEK.crt
openssl x509 -outform DER -in KEK.crt -out KEK.cer
openssl req -quiet -newkey rsa:4096 -nodes -keyout db.key -new -x509 -sha256 -days 3650 -subj '/CN=Test Signature Database key/' -out db.crt
openssl x509 -outform DER -in db.crt -out db.cer
touch .done
echo "Generated Secure Boot keys in ${d}"

View File

@@ -1,78 +0,0 @@
#!/bin/bash
set -euo pipefail
# This should turn into https://github.com/bootc-dev/bootc/issues/1498
variant=$1
shift
# The un-sealed container image we want to use
input_image=$1
shift
# The output container image
output_image=$1
shift
# Buildroot base image for UKI build environment
buildroot_base=$1
shift
# Optional directory with secure boot keys; if none are provided, then we'll
# generate some under target/
secureboot=${1:-}
runv() {
set -x
"$@"
}
case $variant in
ostree)
# Nothing to do
echo "Not building a sealed image; forwarding tag"
runv podman tag $input_image $output_image
exit 0
;;
composefs-sealeduki*)
;;
*)
echo "Unknown variant=$variant" 1>&2; exit 1
;;
esac
if test -z "${secureboot}"; then
secureboot=$(pwd)/target/test-secureboot
mkdir -p ${secureboot}
cd $secureboot
if test '!' -f db.cer; then
echo "Generating test Secure Boot keys"
systemd-id128 new -u > GUID.txt
openssl req -quiet -newkey rsa:4096 -nodes -keyout PK.key -new -x509 -sha256 -days 3650 -subj '/CN=Test Platform Key/' -out PK.crt
openssl x509 -outform DER -in PK.crt -out PK.cer
openssl req -quiet -newkey rsa:4096 -nodes -keyout KEK.key -new -x509 -sha256 -days 3650 -subj '/CN=Test Key Exchange Key/' -out KEK.crt
openssl x509 -outform DER -in KEK.crt -out KEK.cer
openssl req -quiet -newkey rsa:4096 -nodes -keyout db.key -new -x509 -sha256 -days 3650 -subj '/CN=Test Signature Database key/' -out db.crt
openssl x509 -outform DER -in db.crt -out db.cer
else
echo "Reusing Secure Boot keys in ${secureboot}"
fi
cd -
fi
# handle sdboot signing before building the sealed UKI
sdboot_signed="${input_image}_signed"
runv podman build -t $sdboot_signed \
--build-arg=base=${input_image} \
--build-arg=buildroot=${buildroot_base} \
--secret=id=key,src=${secureboot}/db.key \
--secret=id=cert,src=${secureboot}/db.crt \
-f Dockerfile.sdboot .
graphroot=$(podman system info -f '{{.Store.GraphRoot}}')
echo "Computing composefs digest..."
cfs_digest=$(podman run --rm --privileged --read-only --security-opt=label=disable -v /sys:/sys:ro --net=none \
-v ${graphroot}:/run/host-container-storage:ro --tmpfs /var "$sdboot_signed" bootc container compute-composefs-digest)
runv podman build -t $output_image \
--build-arg=COMPOSEFS_FSVERITY=${cfs_digest} \
--build-arg=base=${sdboot_signed} \
--secret=id=key,src=${secureboot}/db.key \
--secret=id=cert,src=${secureboot}/db.crt \
-f Dockerfile.cfsuki .

View File

@@ -102,17 +102,6 @@ execute:
test:
- /tmt/tests/tests/test-25-download-only-upgrade
/plan-26-examples-build:
summary: Test bootc examples build scripts
discover:
how: fmf
test:
- /tmt/tests/tests/test-26-examples-build
adjust:
- when: running_env != image_mode
enabled: false
because: packit tests use RPM bootc and does not install /usr/lib/bootc/initramfs-setup
/plan-27-custom-selinux-policy:
summary: Execute custom selinux policy test
discover:

View File

@@ -1,24 +0,0 @@
# number: 26
# tmt:
# summary: Test bootc examples build scripts
# duration: 45m
# adjust:
# - when: running_env != image_mode
# enabled: false
# because: packit tests use RPM bootc and does not install /usr/lib/bootc/initramfs-setup
#
#!/bin/bash
set -eux
# Test bootc-bls example
echo "Testing bootc-bls example..."
cd examples/bootc-bls
./build
# Test bootc-uki example
echo "Testing bootc-uki example..."
cd ../bootc-uki
./build.base
./build.final
echo "All example builds completed successfully"

View File

@@ -1,10 +0,0 @@
FROM quay.io/fedora/fedora-bootc:42
COPY extra /
COPY bootc /usr/bin
RUN passwd -d root
# need to have bootc-initramfs-setup in the initramfs so we need this
RUN set -x; \
kver=$(cd /usr/lib/modules && echo *); \
dracut -vf --install "/etc/passwd /etc/group" /usr/lib/modules/$kver/initramfs.img $kver;

View File

@@ -1,16 +0,0 @@
#!/bin/bash
set -eux
cd "${0%/*}"
cp /usr/bin/bootc .
cp /usr/lib/bootc/initramfs-setup extra/usr/lib/dracut/modules.d/37bootc/bootc-initramfs-setup
mkdir -p tmp
podman build \
-t quay.io/fedora/fedora-bootc-bls:42 \
-f Containerfile \
--iidfile=tmp/iid \
.

View File

@@ -1,3 +0,0 @@
# we need to force these in via the initramfs because we don't have modules in
# the base image
force_drivers+=" virtio_net vfat "

View File

@@ -1,34 +0,0 @@
# Copyright (C) 2013 Colin Walters <walters@verbum.org>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <https://www.gnu.org/licenses/>.
[Unit]
DefaultDependencies=no
ConditionKernelCommandLine=composefs
ConditionPathExists=/etc/initrd-release
After=sysroot.mount
Requires=sysroot.mount
Before=initrd-root-fs.target
Before=initrd-switch-root.target
OnFailure=emergency.target
OnFailureJobMode=isolate
[Service]
Type=oneshot
ExecStart=/usr/bin/bootc-initramfs-setup
StandardInput=null
StandardOutput=journal
StandardError=journal+console
RemainAfterExit=yes

View File

@@ -1,20 +0,0 @@
#!/usr/bin/bash
check() {
return 0
}
depends() {
return 0
}
install() {
inst \
"${moddir}/bootc-initramfs-setup" /usr/bin/bootc-initramfs-setup
inst \
"${moddir}/bootc-initramfs-setup.service" \
"${systemdsystemunitdir}/bootc-initramfs-setup.service"
$SYSTEMCTL -q --root "${initdir}" add-wants \
'initrd-root-fs.target' 'bootc-initramfs-setup.service'
}

View File

@@ -1,10 +0,0 @@
FROM quay.io/fedora/fedora-bootc:42
COPY extra /
COPY bootc /usr/bin
RUN passwd -d root
# need to have composefs setup root in the initramfs so we need this
RUN set -x; \
kver=$(cd /usr/lib/modules && echo *); \
dracut -vf --install "/etc/passwd /etc/group" /usr/lib/modules/$kver/initramfs.img $kver;

View File

@@ -1,46 +0,0 @@
FROM quay.io/fedora/fedora-bootc-base-uki:42 AS base
FROM base as kernel
ARG COMPOSEFS_FSVERITY
RUN --mount=type=secret,id=key \
--mount=type=secret,id=cert <<EOF
set -eux
mkdir -p /etc/kernel /etc/dracut.conf.d
echo "console=ttyS0,115200 composefs=${COMPOSEFS_FSVERITY} selinux=1 enforcing=0 systemd.debug_shell=1 root=UUID=6523f8ae-3eb1-4e2a-a05a-18b695ae656f rw" > /etc/kernel/cmdline
dnf install -y systemd-ukify sbsigntools systemd-boot-unsigned
kver=$(cd /usr/lib/modules && echo *)
ukify build \
--linux "/usr/lib/modules/$kver/vmlinuz" \
--initrd "/usr/lib/modules/$kver/initramfs.img" \
--uname="${kver}" \
--cmdline "@/etc/kernel/cmdline" \
--os-release "@/etc/os-release" \
--signtool sbsign \
--secureboot-private-key "/run/secrets/key" \
--secureboot-certificate "/run/secrets/cert" \
--measure \
--json pretty \
--output "/boot/$kver.efi"
sbsign \
--key "/run/secrets/key" \
--cert "/run/secrets/cert" \
"/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \
--output "/boot/systemd-bootx64.efi"
EOF
FROM base as final
RUN --mount=type=bind,from=kernel,target=/_mount/kernel <<EOF
kver=$(cd /usr/lib/modules && echo *)
mkdir -p /boot/EFI/Linux
# We put the UKI in /boot for now due to composefs verity not being the
# same due to mtime of /usr/lib/modules being changed
cp /_mount/kernel/boot/$kver.efi /boot/EFI/Linux/$kver.efi
EOF
FROM base as final-final
COPY --from=final /boot /boot

View File

@@ -1,16 +0,0 @@
#!/bin/bash
set -eux
cd "${0%/*}"
cp /usr/bin/bootc .
cp /usr/lib/bootc/initramfs-setup extra/usr/lib/dracut/modules.d/37bootc/bootc-initramfs-setup
mkdir -p tmp
podman build \
-t quay.io/fedora/fedora-bootc-base-uki:42 \
-f Containerfile.stage1 \
--iidfile=tmp/iid \
.

View File

@@ -1,40 +0,0 @@
#!/bin/bash
set -eux
cd "${0%/*}"
cp /usr/bin/bootc .
rm -rf tmp/sysroot
mkdir -p tmp/sysroot/composefs
# TODO port this over to container compute-composefs-digest
IMAGE_ID="$(sed s/sha256:// tmp/iid)"
./bootc internals cfs --repo tmp/sysroot/composefs --insecure oci pull containers-storage:"${IMAGE_ID}"
COMPOSEFS_FSVERITY="$(./bootc internals cfs --repo tmp/sysroot/composefs --insecure oci compute-id --bootable "${IMAGE_ID}")"
# See: https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot
# Alternative to generate keys for testing: `sbctl create-keys`
if [[ ! -d "secureboot" ]]; then
echo "Generating test Secure Boot keys"
mkdir secureboot
pushd secureboot > /dev/null
systemd-id128 new -u > GUID.txt
openssl req -newkey rsa:4096 -nodes -keyout PK.key -new -x509 -sha256 -days 3650 -subj "/CN=Test Platform Key/" -out PK.crt
openssl x509 -outform DER -in PK.crt -out PK.cer
openssl req -newkey rsa:4096 -nodes -keyout KEK.key -new -x509 -sha256 -days 3650 -subj "/CN=Test Key Exchange Key/" -out KEK.crt
openssl x509 -outform DER -in KEK.crt -out KEK.cer
openssl req -newkey rsa:4096 -nodes -keyout db.key -new -x509 -sha256 -days 3650 -subj "/CN=Test Signature Database key/" -out db.crt
openssl x509 -outform DER -in db.crt -out db.cer
popd > /dev/null
fi
# For debugging, add --no-cache to podman command
sudo podman build \
-t quay.io/fedora/fedora-bootc-uki:42 \
--build-arg=COMPOSEFS_FSVERITY="${COMPOSEFS_FSVERITY}" \
-f Containerfile.stage2 \
--secret=id=key,src=secureboot/db.key \
--secret=id=cert,src=secureboot/db.crt \
--iidfile=tmp/iid2

View File

@@ -1,20 +0,0 @@
#!/bin/bash
set -eux
cd "${0%/*}"
if [[ ! -d "secureboot" ]]; then
echo "fail"
exit 1
fi
# See: https://github.com/rhuefi/qemu-ovmf-secureboot
# $ dnf install -y python3-virt-firmware
GUID=$(cat secureboot/GUID.txt)
virt-fw-vars --input "/usr/share/edk2/ovmf/OVMF_VARS_4M.secboot.qcow2" \
--secure-boot \
--set-pk $GUID "secureboot/PK.crt" \
--add-kek $GUID "secureboot/KEK.crt" \
--add-db $GUID "secureboot/db.crt" \
-o "VARS_CUSTOM.secboot.qcow2.template"

View File

@@ -1,3 +0,0 @@
# we need to force these in via the initramfs because we don't have modules in
# the base image
force_drivers+=" virtio_net vfat "

View File

@@ -1,34 +0,0 @@
# Copyright (C) 2013 Colin Walters <walters@verbum.org>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <https://www.gnu.org/licenses/>.
[Unit]
DefaultDependencies=no
ConditionKernelCommandLine=composefs
ConditionPathExists=/etc/initrd-release
After=sysroot.mount
Requires=sysroot.mount
Before=initrd-root-fs.target
Before=initrd-switch-root.target
OnFailure=emergency.target
OnFailureJobMode=isolate
[Service]
Type=oneshot
ExecStart=/usr/bin/bootc-initramfs-setup
StandardInput=null
StandardOutput=journal
StandardError=journal+console
RemainAfterExit=yes

View File

@@ -1,20 +0,0 @@
#!/usr/bin/bash
check() {
return 0
}
depends() {
return 0
}
install() {
inst \
"${moddir}/bootc-initramfs-setup" /usr/bin/bootc-initramfs-setup
inst \
"${moddir}/bootc-initramfs-setup.service" \
"${systemdsystemunitdir}/bootc-initramfs-setup.service"
$SYSTEMCTL -q --root "${initdir}" add-wants \
'initrd-root-fs.target' 'bootc-initramfs-setup.service'
}

View File

@@ -1,29 +0,0 @@
#!/bin/bash
set -eux
curl http://192.168.122.1:8000/bootc -o bootc
chmod +x bootc
IMAGE=quay.io/fedora/fedora-bootc-uki:42
# --env RUST_LOG=debug \
# --env RUST_BACKTRACE=1 \
podman run \
--rm --privileged \
--pid=host \
-v /dev:/dev \
-v /var/lib/containers:/var/lib/containers \
-v /srv/bootc:/usr/bin/bootc:ro,Z \
-v /var/tmp:/var/tmp \
--security-opt label=type:unconfined_t \
"${IMAGE}" \
bootc install to-disk \
--composefs-backend \
--boot=uki \
--source-imgref="containers-storage:${IMAGE}" \
--target-imgref="${IMAGE}" \
--target-transport="docker" \
/dev/vdb \
--filesystem=ext4 \
--wipe

View File

@@ -1,45 +0,0 @@
#!/bin/bash
set -eux
curl http://192.168.122.1:8000/bootc -o bootc
chmod +x bootc
IMAGE=quay.io/fedora/fedora-bootc-uki:42
if [[ ! -f /srv/systemd-bootx64.efi ]]; then
echo "Needs /srv/systemd-bootx64.efi to exists for now"
exit 1
fi
# --env RUST_LOG=debug \
# --env RUST_BACKTRACE=1 \
podman run \
--rm --privileged \
--pid=host \
-v /dev:/dev \
-v /var/lib/containers:/var/lib/containers \
-v /srv/bootc:/usr/bin/bootc:ro,Z \
-v /var/tmp:/var/tmp \
--security-opt label=type:unconfined_t \
"${IMAGE}" \
bootc install to-disk \
--composefs-backend \
--boot=uki \
--source-imgref="containers-storage:${IMAGE}" \
--target-imgref="${IMAGE}" \
--target-transport="docker" \
/dev/vdb \
--filesystem=ext4 \
--wipe
mkdir -p efi
mount /dev/vdb2 /srv/efi
# Manual systemd-boot installation
cp /srv/systemd-bootx64.efi /srv/efi/EFI/fedora/grubx64.efi
mkdir -p /srv/efi/loader
echo "timeout 5" > /srv/efi/loader/loader.conf
rm -rf /srv/efi/EFI/fedora/grub.cfg
umount efi

View File

@@ -46,15 +46,6 @@
duration: 40m
test: nu booted/test-25-download-only-upgrade.nu
/test-26-examples-build:
summary: Test bootc examples build scripts
duration: 45m
adjust:
- when: running_env != image_mode
enabled: false
because: packit tests use RPM bootc and does not install /usr/lib/bootc/initramfs-setup
test: bash booted/test-26-examples-build.sh
/test-27-custom-selinux-policy:
summary: Execute custom selinux policy test
duration: 30m