Using composefs with OSTree
composefs
The composefs project is a new hybrid Linux stacking filesystem that provides many benefits when used for bootable host systems, such as a strong story for integrity.
At the current time, integration of composefs and ostree is experimental. This issue tracks the latest status.
Enabling composefs (unsigned)
When building a disk image or to transition an existing system, run:
ostree config --repo=/ostree/repo set ex-integrity.composefs true
This will ensure that any future deployments (e.g. created by ostree admin upgrade
)
have a .ostree.cfs
file in the deployment directory which is a mountable
composefs metadata file, with a “backing store” directory that is
shared with the current /ostree/repo/objects
.
composefs configuration
The ostree-prepare-root
binary will look for ostree/prepare-root.conf
in /etc
and
/usr/lib
in the initramfs. Using that configuration file you can enable composefs,
and specify an Ed25519 public key to validate the booted commit.
See the manpage for ostree-prepare-root
for details of how to configure it.
Integrity of backing OSTree objects
In ostree/prepare-root.conf
, if composefs.enabled
is set to signed
or verity
,
before the content of a file in the mounted composefs is read,
the integrity of its backing OSTree object in /ostree/repo/objects
is validated by the digest stored in .ostree.cfs
.
This can ensure the integrity of the “backing store”.
Injecting composefs digests
When generating an OSTree commit, there is a CLI switch --generate-composefs-metadata
and a corresponding C API ostree_repo_commit_add_composefs_metadata
. This will
inject the composefs digest as metadata into the ostree commit under a metadata
key ostree.composefs.v0
. Because an OSTree commit can be signed, this allows
covering the composefs fsverity digest with a signature.
Signatures
If a commit is signed with an Ed25519 private key (see ostree
sign
), and composefs.keyfile
is specified in prepare-root.conf
,
then the initrd will find the commit being booted in the system repo
and validate its signature against the public key. It will then ensure
that the composefs digest being booted has an fs-verity digest
matching the one in the commit. This allows a fully trusted read-only
/usr.
The exact usage of the signature is up to the user, but a common way to use it with transient keys. This is done like this:
- Generate a new keypair before each build
- Embed the public key in the initrd that is part of the commit.
- Ensure the initrd has a
prepare-root.conf
with[composefs] enabled=signed
, and either usekeypath
or inject/etc/ostree/initramfs-root-binding.key
; for more seeman ostree-prepare-root
- After committing, run
ostree sign
with the private key. - Throw away the private key.
When a transient key is used this way, that ties the initrd with the userspace part from the commit. This means each initrd can only boot the very same userspace it was made for. For example, if an older version of the OS has a security flaw, you can’t boot a new fixed (signed) initrd and have it boot the older userspace with the flaw.
Requirements
The current default composefs integration in ostree does not have any requirements from the underlying kernel and filesystem other than having the following kernel options set:
CONFIG_OVERLAY_FS
CONFIG_BLK_DEV_LOOP
CONFIG_EROFS_FS
At the current time, there are no additional userspace runtime requirements.
Status
IMPORTANT The integration with composefs is experimental and subject to change. Please try it and report issues but do not deploy to production systems yet.
Compatiblity
One issue that ostree users transitioning to composefs may hit is that it is no
longer possible to add new toplevel directories via the chattr -i / && mkdir /somedir && chattr -i
trick. A bit more on this in the following issues:
However, users who were doing things like this probably want to enable the
root.transient
option; see man ostree-prepare-root
which will allow
this (but also change other behaviors too).
Comparison with other approaches
There is also support for using IMA with ostree. In short, composefs provides much stronger and more efficient integrity:
- composefs validates an entire filesystem tree, not just individual files
- composefs makes files actually read-only, whereas IMA does not by default
- composefs uses fs-verity which does on-demand verification (IMA by default does a full readahead of every file accessed, though IMA can also use fs-verity as a backend)
Further references
- https://github.com/containers/composefs
- https://www.kernel.org/doc/html/next/filesystems/fsverity.html