From 0f77b90f3da96afa4b55fe26da680db61289da71 Mon Sep 17 00:00:00 2001 From: Renato Caldas Date: Thu, 27 Aug 2026 13:00:05 +0100 Subject: [PATCH] ephemeral: Add writable tmpfs overlay over /root/.ssh Some fully transient bootc images might have a read-only /root, which breaks ssh key injection. Overlaying a writable tmpfs over /root/.ssh allows the keys to be injected without changing the write permissions for the /root directory or shadowing existing keys. The implementation mirrors what's currently done for /etc, with an additional bcvk-root-ssh-overlay.service unit embedded in the CPIO archive that gets appended to the initramfs. Since there might be secrets in /root/.ssh, we're ensuring the overlay directories are created with mode 0700. In conventional bootc images, /root is a symlink to /var/roothome, which is created by tmpfiles.d after the pivot to the final root filesystem. Because the target directory doesn't exist during the initramfs stage, attempting to mount an overlay over /root/.ssh would fail. But since /var/roothome is writable in these systems, the overlay is unnecessary and can be safely skipped. Closes: #331 Signed-off-by: Renato Caldas --- crates/kit/src/cpio.rs | 12 +++++++++++ .../src/units/bcvk-root-ssh-overlay.service | 20 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 crates/kit/src/units/bcvk-root-ssh-overlay.service diff --git a/crates/kit/src/cpio.rs b/crates/kit/src/cpio.rs index 62787996c..1e4534942 100644 --- a/crates/kit/src/cpio.rs +++ b/crates/kit/src/cpio.rs @@ -78,6 +78,10 @@ pub fn create_initramfs_units_cpio() -> io::Result> { "usr/lib/systemd/system/bcvk-journal-stream.service", include_bytes!("units/bcvk-journal-stream.service"), ), + File( + "usr/lib/systemd/system/bcvk-root-ssh-overlay.service", + include_bytes!("units/bcvk-root-ssh-overlay.service"), + ), // Drop-in to pull sysroot.mount into initrd-root-fs.target. Without // this, nothing in the dependency graph actually requests the mount; // dracut-rootfs-generator normally creates an @@ -100,6 +104,10 @@ pub fn create_initramfs_units_cpio() -> io::Result> { "usr/lib/systemd/system/initrd-fs.target.d/bcvk-copy-units.conf", b"[Unit]\nWants=bcvk-copy-units.service\n", ), + File( + "usr/lib/systemd/system/initrd-fs.target.d/bcvk-root-ssh-overlay.conf", + b"[Unit]\nWants=bcvk-root-ssh-overlay.service\n", + ), ]; let mut buf = Vec::new(); @@ -195,6 +203,7 @@ mod tests { assert!(names.contains(&"usr/lib/systemd/system/bcvk-var-ephemeral.service")); assert!(names.contains(&"usr/lib/systemd/system/bcvk-copy-units.service")); assert!(names.contains(&"usr/lib/systemd/system/bcvk-journal-stream.service")); + assert!(names.contains(&"usr/lib/systemd/system/bcvk-root-ssh-overlay.service")); // initrd-root-fs.target drop-in assert!(names.contains(&"usr/lib/systemd/system/initrd-root-fs.target.d/bcvk-sysroot.conf")); @@ -205,6 +214,9 @@ mod tests { names.contains(&"usr/lib/systemd/system/initrd-fs.target.d/bcvk-var-ephemeral.conf") ); assert!(names.contains(&"usr/lib/systemd/system/initrd-fs.target.d/bcvk-copy-units.conf")); + assert!( + names.contains(&"usr/lib/systemd/system/initrd-fs.target.d/bcvk-root-ssh-overlay.conf") + ); // Verify file modes: all entries are either regular files (0644) or directories for (name, _size, mode) in &entries { diff --git a/crates/kit/src/units/bcvk-root-ssh-overlay.service b/crates/kit/src/units/bcvk-root-ssh-overlay.service new file mode 100644 index 000000000..45231fa2b --- /dev/null +++ b/crates/kit/src/units/bcvk-root-ssh-overlay.service @@ -0,0 +1,20 @@ +[Unit] +Description=Setup ephemeral /root/.ssh overlay +DefaultDependencies=no +ConditionPathExists=/etc/initrd-release +ConditionPathIsSymbolicLink=!/sysroot/root +Before=initrd-fs.target +# Must run after sysroot.mount and initrd-parse-etc.service +After=sysroot.mount initrd-parse-etc.service +Requires=sysroot.mount + +[Service] +Type=oneshot +RemainAfterExit=yes +TimeoutStartSec=30 +# Bind-mount /sysroot/root/.ssh to a separate location first, then use that as lowerdir. +# Using /sysroot/root/.ssh as both lowerdir and mount destination can hang on older kernels. +ExecStart=/usr/bin/mkdir -m 0700 -p /run/root-ssh-lower /run/root-ssh-upper /run/root-ssh-work +ExecStart=/usr/bin/mount --bind /sysroot/root/.ssh /run/root-ssh-lower +# Use index=off,metacopy=off to avoid extended attr operations on virtiofs +ExecStart=/usr/bin/mount -t overlay overlay -o lowerdir=/run/root-ssh-lower,upperdir=/run/root-ssh-upper,workdir=/run/root-ssh-work,index=off,metacopy=off /sysroot/root/.ssh