Experimental features are subject to change or removal. Please do provide feedback on them.
The composefs backend is an experimental alternative storage backend that uses composefs-rs instead of ostree for storing and managing bootc system deployments.
Status: Experimental. The composefs backend is under active development and not yet suitable for production use. The feature is always compiled in as of bootc v1.10.1.
A key goal is custom "sealed" images, signed with your own Secure Boot keys. This is based on Unified Kernel Images that embed a digest of the target container root filesystem, typically alongside a bootloader (such as systemd-boot) also signed with your key.
A sealed image is a cryptographically signed and verified bootc image that provides end-to-end integrity protection. This is achieved through:
- Unified Kernel Images (UKIs): Combining kernel, initramfs, and boot parameters into a single signed binary
- Composefs integration: Using composefs with fsverity for content-addressed filesystem verification
- Secure Boot: Cryptographic signatures on both the UKI and systemd-boot loader
A sealed image includes:
- composefs digest: A SHA-512 hash of the entire root filesystem, computed at build time
- Unified Kernel Image (UKI): A single EFI binary containing the kernel, initramfs, and kernel command line with the composefs digest embedded
- Secure Boot signature: The UKI is signed with your private key
At boot time, the composefs digest in the kernel command line (e.g., composefs=<sha512-hash>) is verified against the mounted root filesystem. This creates a chain of trust from firmware to userspace, ensuring the system will only boot if the root filesystem matches exactly what was signed.
For sealed images, the container must:
- Include a kernel and initramfs in
/usr/lib/modules/<kver>/ - Have systemd-boot available (and NOT have
bootupd) - Not include a pre-built UKI (the build process generates one)
Sealed images also require:
- Secure Boot support in the target system firmware
- A filesystem with fsverity support (e.g., ext4, btrfs) for the root partition
You can use a sealed UKI without Secure Boot enabled. The composefs and mounting code is fully orthogonal to Secure Boot - the fsverity digest of the root filesystem and all of its contents will still be validated at runtime, which does provide an increased level of integrity.
However: nothing validates that root digest itself, meaning any locally running code can replace the UKI (e.g. after a container breakout) and fully control the next boot.
It is intentional to support booting with Secure Boot disabled, because a valid use case is to temporarily disable it in order to test a change locally on e.g. one machine, then re-enable it later. However at the current time it is not yet streamlined to regenerate the UKI locally.
The key to building sealed images is using a multi-stage Dockerfile where a separate stage mounts the target rootfs, computes its composefs digest, and generates the signed UKI in one step:
# Build your rootfs with all packages and configuration
FROM <base-image> as rootfs
RUN apt|dnf|zypper install ... && bootc container lint --fatal-warnings
# Generate the sealed UKI in a tools stage
FROM <tools-image> as sealed-uki
RUN --mount=type=bind,from=rootfs,target=/target \
--mount=type=secret,id=secureboot_key \
--mount=type=secret,id=secureboot_cert <<EORUN
set -euo pipefail
# Compute the composefs digest from the mounted rootfs
digest=$(bootc container compute-composefs-digest /target)
# Find the kernel version
kver=$(ls /target/usr/lib/modules)
# Generate and sign the UKI with the digest embedded
ukify build \
--linux "/target/usr/lib/modules/${kver}/vmlinuz" \
--initrd "/target/usr/lib/modules/${kver}/initramfs.img" \
--cmdline "composefs=${digest} rw" \
--os-release "@/target/usr/lib/os-release" \
--signtool sbsign \
--secureboot-private-key /run/secrets/secureboot_key \
--secureboot-certificate /run/secrets/secureboot_cert \
--output "/out/${kver}.efi"
EORUN
# Final image: copy the sealed UKI into place
FROM rootfs
COPY --from=sealed-uki /out/*.efi /boot/EFI/Linux/This pattern works because:
- The
--mount=type=bind,from=rootfsprovides read-only access to the target filesystem bootc container compute-composefs-digestcomputes the SHA-512 hash of the rootfsukifycreates the UKI with that digest in the kernel command line (composefs=<digest>)- The final stage copies the signed UKI into the rootfs without modifying any files used in the digest calculation
bootc container compute-composefs-digest [PATH]Computes the composefs digest for a filesystem. The digest is a 128-character SHA-512 hex string that uniquely identifies the filesystem contents.
Options:
PATH: Path to the filesystem root (default:/target)--write-dumpfile-to <PATH>: Generate a dumpfile for debugging
Note: This command is currently hidden from
--helpoutput as it's part of the experimental composefs feature set.
The sealed image should have:
- The signed UKI at
/boot/EFI/Linux/<kver>.efi - A signed systemd-boot at
/boot/EFI/BOOT/BOOTX64.EFIand/boot/EFI/systemd/systemd-bootx64.efi - The raw
vmlinuzandinitramfs.imgremoved from/usr/lib/modules/<kver>/(they're now embedded in the UKI)
For production environments with dedicated signing infrastructure:
- Build unsigned UKI: Compute digest and create an unsigned UKI (omit
--signtoolfrom ukify) - Sign externally: Take the unsigned UKI to your signing infrastructure
- Complete the seal: Inject the signed UKI into the final image
This workflow is planned for streamlining in future releases (see #1498).
See CONTRIBUTING.md for information on building and testing bootc itself with composefs support.
To use sealed images, the container image must have a UKI and systemd-boot installed (and not have bootupd). If these conditions are met, bootc will automatically detect and use the composefs backend during installation.
There is a --composefs-backend option for bootc install to explicitly select a composefs backend apart from sealed images; this is not as heavily tested yet.
The composefs backend is experimental; on-disk formats are subject to change.
- Garbage collection: In progress
- Extended install APIs: Ability to cleanly implement anaconda %post and osbuild post mutations and general post-install pre-reboot; right now some tools just mount the deployment directory (note this one also relates to APIs in general)
- OCI registry install: Installing from registry can fail due to config mismatch (suggestion: just clean reject v2s2)
- composefs-rs repository finalization
- Extended test suite: Right now we're not covering upgrades well, need to build upgrade image in sealed cases
- Full workflow test - add composefs into https://gitlab.com/fedora/bootc/tests/bootc-workflow-test for example
- Workflow upgrades especially "from old systems"
- Unified storage: Not strictly a blocker but a really nice to have
- Sealed image build UX: Streamlined tooling for building sealed images
- In place transitions:
- First: support factory reset from ostree to composefs
- Next: Support copying /etc and /var
- A lot more practical level docs for using this
- Remove
/usr/lib/bootc/kargs.das part of UKI creation (alsobootc container inspectshould show UKI kargs)
- See filesystem.md for information about composefs in the standard ostree backend
- See bootloaders.md for bootloader configuration details
- composefs-rs - The underlying composefs implementation
- Unified Kernel Images specification
- ukify documentation - Tool for building UKIs