Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 88 additions & 27 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,79 @@ RUN --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp --mount=type=c
# local sources. We'll override it later.
# NOTE: All your base belong to me.
FROM $base as target-base

# SKIP_CONFIGS=1 skips LBIs, test kargs, and install configs (for FCOS testing)
ARG boot_type
ARG seal_state
ARG variant
ARG baseconfigs=""
ARG rootfs=""

# Handle version skew between base image and mirrors for CentOS Stream
# xref https://gitlab.com/redhat/centos-stream/containers/bootc/-/issues/1174
RUN --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=bind,from=packaging,src=/,target=/run/packaging \
/run/packaging/enable-compose-repos
RUN --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp /usr/libexec/bootc-base-imagectl build-rootfs --manifest=standard /target-rootfs

RUN --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp <<EOF
set -eux
/usr/libexec/bootc-base-imagectl build-rootfs --manifest=standard --no-initramfs /target-rootfs
EOF

RUN --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=bind,from=src,src=/src/hack,target=/run/hack \
--mount=type=bind,from=packages,src=/,target=/target-rootfs/run/packages \
--mount=type=bind,from=packaging,src=/usr-extras,target=/target-rootfs/run/usr-extras \
--mount=type=bind,from=packaging,src=/,target=/target-rootfs/run/packaging <<EOF
set -eux

/run/hack/downgrade-kernel.sh /target-rootfs

mount --bind /proc /target-rootfs/proc
mount --bind /dev /target-rootfs/dev

# All NON network-fetching operations inside the chroot
seal_state="${seal_state}" \
boot_type="${boot_type}" \
variant="${variant}" \
rootfs="${rootfs}" \
baseconfigs="${baseconfigs}" \
chroot /target-rootfs /bin/bash -c '
# Only need enough here to generate the initramfs
set -eux

# Configure the rootfs
/run/packaging/configure-rootfs "${variant}" "${rootfs}"

# Inject base configuration (e.g. transient-etc, transient-root) before dracut runs
/run/packaging/inject-baseconfig "${variant}" "${baseconfigs}"

# Override with our built package
/run/packaging/install-rpm-and-setup /run/packages

install -D -m 0644 -t /usr/lib/bootc/kargs.d /run/usr-extras/lib/bootc/kargs.d/*.toml

/run/packaging/cleanup'

umount /target-rootfs/proc
umount /target-rootfs/dev

bootc container lint --fatal-warnings --rootfs /target-rootfs
EOF

# Inject some other configuration
COPY --from=packaging /usr-extras/ /target-rootfs/usr/

RUN --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp <<EOF
set -eux

# create this regardless else bind mounts down the line fail for non-uki builds
mkdir -p /kernel

if [[ "${boot_type}" == "uki" ]]; then
/target-rootfs/usr/bin/bootc container split-kernel-and-rootfs --rootfs /target-rootfs --output /kernel
fi
EOF

FROM scratch as fetch
COPY --from=target-base /target-rootfs/ /
Expand Down Expand Up @@ -135,7 +202,10 @@ ARG pkgversion
ARG SOURCE_DATE_EPOCH
ENV SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH}
# Build RPM directly from source, using cached target directory
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp --mount=type=cache,target=/src/target --mount=type=cache,target=/var/roothome RPM_VERSION="${pkgversion}" /src/contrib/packaging/build-rpm
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=cache,target=/src/target \
--mount=type=cache,target=/var/roothome \
RPM_VERSION="${pkgversion}" /src/contrib/packaging/build-rpm

# Build a systemd-sysext containing just the bootc binary.
# Skips RPM machinery entirely for fast incremental rebuilds.
Expand Down Expand Up @@ -247,27 +317,6 @@ rm -rf /var/cache
rm -rf /run/rhsm

EORUN
# Configure the rootfs
ARG rootfs=""
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=bind,from=packaging,src=/,target=/run/packaging \
/run/packaging/configure-rootfs "${variant}" "${rootfs}"
# Inject base configuration (e.g. transient-etc, transient-root) before dracut runs
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=bind,from=packaging,src=/,target=/run/packaging \
/run/packaging/inject-baseconfig "${variant}" "${baseconfigs}"
# Override with our built package
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=bind,from=packaging,src=/,target=/run/packaging \
--mount=type=bind,from=packages,src=/,target=/run/packages \
/run/packaging/install-rpm-and-setup /run/packages
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=bind,from=packaging,src=/usr-extras,target=/run/usr-extras \
install -D -m 0644 -t /usr/lib/bootc/kargs.d /run/usr-extras/lib/bootc/kargs.d/*.toml
# Clean up package manager caches
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=bind,from=packaging,src=/,target=/run/packaging \
/run/packaging/cleanup

# Generate the sealed UKI in a separate stage
# This computes the composefs digest from base-penultimate and creates a signed UKI
Expand All @@ -284,18 +333,27 @@ RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=secret,id=secureboot_key \
--mount=type=secret,id=secureboot_cert \
--mount=type=bind,from=target-base,src=/kernel,target=/run/kernel \
--mount=type=bind,from=packaging,src=/,target=/run/packaging \
--mount=type=bind,from=base-penultimate,src=/,target=/run/target <<EORUN
set -xeuo pipefail

allow_missing_verity=false
allow_missing_verity=()

if [[ $filesystem == "xfs" ]]; then
allow_missing_verity=true
allow_missing_verity=(--allow-missing-verity)
fi

if test "${boot_type}" = "uki"; then
/run/packaging/seal-uki /run/target /out /run/secrets $allow_missing_verity $seal_state
kver=$(ls /run/kernel)

/run/packaging/seal-uki \
--target /run/target \
--output /out \
--secrets /run/secrets \
"${allow_missing_verity[@]}" \
--kernel-dir "/run/kernel/$kver" \
--seal-state $seal_state
fi
EORUN

Expand All @@ -306,10 +364,13 @@ ARG boot_type
# Copy the sealed UKI and finalize the image (remove raw kernel, create symlinks)
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=bind,from=packaging,src=/,target=/run/packaging \
--mount=type=bind,from=target-base,src=/kernel,target=/run/kernel \
--mount=type=bind,from=sealed-uki,src=/,target=/run/sealed-uki <<EORUN
set -xeuo pipefail

if test "${boot_type}" = "uki"; then
/run/packaging/finalize-uki /run/sealed-uki/out
kver=$(ls /run/kernel)
/run/packaging/finalize-uki /run/sealed-uki/out "$kver"
fi
EORUN
# And finally, test our linting
Expand Down
7 changes: 5 additions & 2 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ build: package _keygen && _pull-lbi-images
# The retry parameters can be overridden via environment variables:
# BOOTC_CI_RETRIES=10 BOOTC_CI_DELAY=60 just build-fetch
[group('core')]
build-fetch: _keygen
build-fetch: _keygen package
#!/bin/bash
set -euo pipefail
retries=${BOOTC_CI_RETRIES:-3}
Expand Down Expand Up @@ -131,12 +131,15 @@ build-fetch: _keygen
for img in {{lbi_images}}; do
retry podman pull -q "$img"
done

pkg_path=$(realpath target/packages)

# Build the network-heavy fetch stage of the main image. If this
# succeeds, `just build` will get a cache hit on the fetch layer and
# run entirely offline.
# Note: buildargs (not base_buildargs) is needed here because the
# target-base stage requires --cap-add/--security-opt for bwrap.
retry podman build {{_nocache_arg}} --target=fetch {{buildargs}} .
retry podman build {{_nocache_arg}} --build-context "packages=${pkg_path}" --target=fetch {{buildargs}} .
# Same for the upgrade-source image used by test-upgrade.
retry podman build {{_nocache_arg}} --build-arg=base={{base}} \
--target=fetch -f tmt/tests/Dockerfile.upgrade-source .
Expand Down
15 changes: 2 additions & 13 deletions contrib/packaging/finalize-uki
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,8 @@ set -xeuo pipefail
# Path to directory containing the generated UKI
uki_src=$1
shift

# Find the kernel version from the current system
kver=$(bootc container inspect --json | jq -r '.kernel.version')
if [ -z "$kver" ] || [ "$kver" = "null" ]; then
echo "Error: No kernel found" >&2
exit 1
fi
kver=$1
shift

# Create the EFI directory structure
mkdir -p /boot/EFI/Linux
Expand All @@ -36,12 +31,6 @@ mkdir -p /boot/EFI/Linux
target=/boot/EFI/Linux/${kver}.efi
cp "${uki_src}/${kver}.efi" "${target}"

# Remove the raw kernel and initramfs since we're using a UKI now.
# NOTE: We intentionally keep these for now until bcvk is updated to extract
# kernel/initramfs from UKIs in subdirectories. Once bcvk PR #144 is fixed
# to look for .efi files in /usr/lib/modules/<kver>/, we can uncomment this.
# rm -v "/usr/lib/modules/${kver}/vmlinuz" "/usr/lib/modules/${kver}/initramfs.img"

# NOTE: We used to create a symlink from /usr/lib/modules/${kver}/${kver}.efi to the UKI
# for tooling compatibility. However, composefs-boot's find_uki_components() doesn't
# handle symlinks correctly and fails with "is not a regular file". The UKI is already
Expand Down
86 changes: 59 additions & 27 deletions contrib/packaging/seal-uki
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,70 @@
# Generate a sealed UKI with embedded composefs digest
set -xeuo pipefail

# Path to the desired root filesystem
target=$1
shift
# Write to this directory
output=$1
shift
# Path to secrets directory
secrets=$1
shift
allow_missing_verity=$1
shift
seal_state=$1
shift

if [[ $seal_state == "sealed" && $allow_missing_verity == "true" ]]; then
missing_verity=()

while [ ! -z "${1:-}" ]; do
case "$1" in
# Path to the desired root filesystem
"--target")
target="$2"
shift
shift
;;

# Write to this directory
"--output")
output="$2"
shift
shift
;;

# Path to secrets directory
"--secrets")
secrets="$2"
shift
shift
;;

"--allow-missing-verity")
missing_verity=(--allow-missing-verity)
shift
;;

"--seal-state")
seal_state="$2"
shift
shift
;;

# Path to the directory containing kernel and initramfs
"--kernel-dir")
kernel_dir="$2"
shift
shift
;;

* )
echo "Argument $1 not understood"
exit 1
;;
esac
done

if [[ $seal_state == "sealed" && ${#missing_verity[@]} -gt 0 ]]; then
echo "Cannot have missing verity with sealed UKI" >&2
exit 1
fi

# Find the kernel version (needed for output filename)
kver=$(bootc container inspect --rootfs "${target}" --json | jq -r '.kernel.version')
if [ -z "$kver" ] || [ "$kver" = "null" ]; then
echo "Error: No kernel found" >&2
exit 1
if [[ -z $kernel_dir ]]; then
echo "kernel dir is required" >&2
exit 1
fi

kernel_params=(--kernel-dir "$kernel_dir")

kver=$(basename "$kernel_dir")

mkdir -p "${output}"

# Baseline ukify options
Expand All @@ -45,12 +83,6 @@ fi
# Baseline container ukify options
containerukifyargs=(--rootfs "${target}")

missing_verity=()

if [[ $allow_missing_verity == "true" ]]; then
missing_verity+=(--allow-missing-verity)
fi

# Build the UKI using bootc container ukify
# This computes the composefs digest, reads kargs from kargs.d, and invokes ukify
bootc container ukify "${containerukifyargs[@]}" "${missing_verity[@]}" -- "${ukifyargs[@]}"
bootc container ukify "${containerukifyargs[@]}" "${kernel_params[@]}" "${missing_verity[@]}" -- "${ukifyargs[@]}"
Loading
Loading