From 76f82eb8657f75ac389ae49788c4389d2509c1f0 Mon Sep 17 00:00:00 2001 From: Dusty Mabe Date: Mon, 22 Jun 2026 12:35:36 -0400 Subject: [PATCH] add virtiofs systemd credential handling As part of an effort to test more on non-CoreOS bootable container images we'd like a cross architecture way to expose systemd credentials into a VM. This commit adds a new import-virtiofs-systemd-credentials.service that runs in the initramfs and will copy credentials exposed via the io.systemd.credentials virtiofs tag into the /run/credentials/@initrd directory, which will then get imported by systemd itself. Related to https://github.com/systemd/systemd/issues/29175 upstream. Assisted-by: --- manifests/shared-el.yaml | 2 + ...mport-virtiofs-systemd-credentials.service | 45 +++++++++ .../import-virtiofs-systemd-credentials.sh | 92 +++++++++++++++++++ .../module-setup.sh | 50 ++++++++++ overlay.d/README.md | 9 ++ 5 files changed, 198 insertions(+) create mode 100644 overlay.d/40import-virtiofs-systemd-credentials/usr/lib/dracut/modules.d/40import-virtiofs-systemd-credentials/import-virtiofs-systemd-credentials.service create mode 100755 overlay.d/40import-virtiofs-systemd-credentials/usr/lib/dracut/modules.d/40import-virtiofs-systemd-credentials/import-virtiofs-systemd-credentials.sh create mode 100644 overlay.d/40import-virtiofs-systemd-credentials/usr/lib/dracut/modules.d/40import-virtiofs-systemd-credentials/module-setup.sh diff --git a/manifests/shared-el.yaml b/manifests/shared-el.yaml index 0cbd5ff239..fa2c2f8b2b 100644 --- a/manifests/shared-el.yaml +++ b/manifests/shared-el.yaml @@ -46,6 +46,7 @@ conditional-include: - overlay.d/08nouveau - overlay.d/20platform-chrony - overlay.d/30lvmdevices + - overlay.d/40import-virtiofs-systemd-credentials - if: id != "fedora" include: ostree-layers: @@ -53,3 +54,4 @@ conditional-include: - fedora-coreos-config/overlay.d/08nouveau - fedora-coreos-config/overlay.d/20platform-chrony - fedora-coreos-config/overlay.d/30lvmdevices + - fedora-coreos-config/overlay.d/40import-virtiofs-systemd-credentials diff --git a/overlay.d/40import-virtiofs-systemd-credentials/usr/lib/dracut/modules.d/40import-virtiofs-systemd-credentials/import-virtiofs-systemd-credentials.service b/overlay.d/40import-virtiofs-systemd-credentials/usr/lib/dracut/modules.d/40import-virtiofs-systemd-credentials/import-virtiofs-systemd-credentials.service new file mode 100644 index 0000000000..3c827b2357 --- /dev/null +++ b/overlay.d/40import-virtiofs-systemd-credentials/usr/lib/dracut/modules.d/40import-virtiofs-systemd-credentials/import-virtiofs-systemd-credentials.service @@ -0,0 +1,45 @@ +[Unit] +Description=Import systemd credentials from virtiofs +Documentation=https://systemd.io/CREDENTIALS/ +Documentation=https://github.com/systemd/systemd/issues/29175 + +# Only run inside a VM — virtiofs is a VM-only transport. +ConditionVirtualization=vm + +# Only run if the virtiofs sysfs directory exists, meaning the +# virtiofs kernel module is loaded and at least one device is present. +ConditionDirectoryNotEmpty=/sys/fs/virtiofs + +# Only run if we're not in a confidential compute setting as this is +# another vector for configuring the machine and it's not currently +# measured. +ConditionSecurity=!cvm +ConditionSecurity=!measured-uki +ConditionSecurity=!measured-os + +# Only run on Ignition first boot for now as we don't need it for +# anything other than that. +ConditionKernelCommandLine=ignition.firstboot + +# Run in the initramfs so that systemd credentials are in +# /run/credentials/@initrd/ before the initramfs-to-real-root transition. +# Since /run persists across that transition, the systemd credentials +# will be available to generators and services in the real root (e.g. +# systemd-debug-generator for systemd.extra-unit.* and +# systemd.unit-dropin.*, systemd-tmpfiles-setup for tmpfiles.extra, +# systemd-sysusers for passwd.hashed-password.*, etc.) +# +# This must run after the virtio devices are discovered and the +# virtiofs kernel module is loaded. +DefaultDependencies=no +After=systemd-modules-load.service +After=systemd-udev-settle.service +Before=initrd-switch-root.target + +[Service] +Type=oneshot +RemainAfterExit=no +ExecStart=/usr/libexec/import-virtiofs-systemd-credentials.sh + +[Install] +WantedBy=initrd.target diff --git a/overlay.d/40import-virtiofs-systemd-credentials/usr/lib/dracut/modules.d/40import-virtiofs-systemd-credentials/import-virtiofs-systemd-credentials.sh b/overlay.d/40import-virtiofs-systemd-credentials/usr/lib/dracut/modules.d/40import-virtiofs-systemd-credentials/import-virtiofs-systemd-credentials.sh new file mode 100755 index 0000000000..4a51536df7 --- /dev/null +++ b/overlay.d/40import-virtiofs-systemd-credentials/usr/lib/dracut/modules.d/40import-virtiofs-systemd-credentials/import-virtiofs-systemd-credentials.sh @@ -0,0 +1,92 @@ +#!/bin/bash +# import-virtiofs-systemd-credentials.sh - Import systemd credentials from a virtiofs share +# +# This script scans /sys/fs/virtiofs/*/tag for a virtiofs filesystem tagged +# "io.systemd.credentials". If found, it mounts the filesystem and copies +# credential files into /run/credentials/@system/ where systemd will pick +# them up as system credentials. +# +# virtiofs tag discovery requires kernel >= 6.9 (commit a8f62f50b4e4). +# See https://systemd.io/CREDENTIALS/ for the systemd credentials specification. +# See https://github.com/systemd/systemd/issues/29175 for upstream discussion. + +set -euo pipefail + +VIRTIOFS_TAG="io.systemd.credentials" +SYSFS_DIR="/sys/fs/virtiofs" +SYSTEMD_CREDS_DIR="" # defined below +MOUNTPOINT="/run/credentials/@virtiofs" + +# For EL 9 we need to copy to a different directory because importing +# from /run/credentials/@initrd was only added in systemd v254. +# https://github.com/systemd/systemd/pull/28207 +source /etc/os-release +if [ "${PLATFORM_ID:-}" == "platform:el9" ]; then + SYSTEMD_CREDS_DIR="/run/credstore" # Works with LoadCredential +else + SYSTEMD_CREDS_DIR="/run/credentials/@initrd" # Works with ImportCredential +fi + +log() { + echo "import-virtiofs-systemd-credentials: $*" >&2 +} + +# Check if the virtiofs sysfs directory exists at all. If the virtiofs +# kernel module isn't loaded or no virtiofs devices are present, there's +# nothing to do. +if [ ! -d "${SYSFS_DIR}" ]; then + log "no virtiofs sysfs directory found, nothing to do" + exit 0 +fi + +log "importing into ${SYSTEMD_CREDS_DIR}" + +# Scan all virtiofs devices for our well-known tag. The kernel exposes +# virtiofs tags at /sys/fs/virtiofs//tag (since Linux 6.9). +found=0 +for tagfile in "${SYSFS_DIR}"/*/tag; do + [ -e "${tagfile}" ] || continue + tag=$(cat "${tagfile}" 2>/dev/null) || continue + if [ "${tag}" = "${VIRTIOFS_TAG}" ]; then + found=1 + break + fi +done + +if [ "${found}" -eq 0 ]; then + log "no virtiofs share with tag '${VIRTIOFS_TAG}' found, nothing to do" + exit 0 +fi + +log "found virtiofs share with tag '${VIRTIOFS_TAG}'" + +# Create the mountpoint and mount the virtiofs share +mkdir -p "${MOUNTPOINT}" +if ! mount -t virtiofs "${VIRTIOFS_TAG}" "${MOUNTPOINT}"; then + log "failed to mount virtiofs tag '${VIRTIOFS_TAG}'" + rmdir "${MOUNTPOINT}" 2>/dev/null || true + exit 1 +fi + +# Create the system credentials directory if it doesn't exist. +# This is where systemd looks for system-level credentials. +mkdir -p "${SYSTEMD_CREDS_DIR}" + +# Copy each systemd credential file from the virtiofs mount into the systemd +# credentials import initrd directory. Credential names are the filenames. +count=0 +for credfile in "${MOUNTPOINT}"/*; do + [ -f "${credfile}" ] || continue + credname=$(basename "${credfile}") + cp "${credfile}" "${SYSTEMD_CREDS_DIR}/${credname}" + # Credentials should be readable only by root + chmod 0600 "${SYSTEMD_CREDS_DIR}/${credname}" + log "imported systemd credential: ${credname}" + count=$((count + 1)) +done + +# Clean up the mount +umount "${MOUNTPOINT}" +rmdir "${MOUNTPOINT}" 2>/dev/null || true + +log "imported ${count} systemd credential(s)" diff --git a/overlay.d/40import-virtiofs-systemd-credentials/usr/lib/dracut/modules.d/40import-virtiofs-systemd-credentials/module-setup.sh b/overlay.d/40import-virtiofs-systemd-credentials/usr/lib/dracut/modules.d/40import-virtiofs-systemd-credentials/module-setup.sh new file mode 100644 index 0000000000..2ede86b658 --- /dev/null +++ b/overlay.d/40import-virtiofs-systemd-credentials/usr/lib/dracut/modules.d/40import-virtiofs-systemd-credentials/module-setup.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +# +# Dracut module: import-virtiofs-systemd-credentials +# +# Imports systemd credentials from a virtiofs share tagged +# "io.systemd.credentials" into /run/credentials/@system/. +# This runs in the initramfs so that systemd credentials are available +# to generators in the real root (e.g. systemd-debug-generator for +# systemd.extra-unit.* and systemd.unit-dropin.*) and early services +# (e.g. systemd-tmpfiles-setup for tmpfiles.extra). +# +# This provides a cross-architecture alternative to SMBIOS OEM strings +# and fw_cfg for passing systemd credentials into VMs. Unlike those +# mechanisms, virtiofs works on all architectures including s390x and +# ppc64le. +# +# See https://systemd.io/CREDENTIALS/ +# See https://github.com/systemd/systemd/issues/29175 + +check() { + # Don't include in kdump initramfs + if [[ $IN_KDUMP == 1 ]]; then + return 1 + fi + return 0 +} + +depends() { + echo systemd +} + +installkernel() { + instmods -c virtiofs +} + +install_and_enable_unit() { + local unit="$1"; shift + local target="$1"; shift + inst_simple "$moddir/$unit" "$systemdsystemunitdir/$unit" + systemctl -q --root="$initdir" add-requires "$target" "$unit" || exit 1 +} + +install() { + inst_script "$moddir/import-virtiofs-systemd-credentials.sh" \ + "/usr/libexec/import-virtiofs-systemd-credentials.sh" + + install_and_enable_unit import-virtiofs-systemd-credentials.service initrd.target +} diff --git a/overlay.d/README.md b/overlay.d/README.md index 8c61e703c2..5f2845e1f4 100644 --- a/overlay.d/README.md +++ b/overlay.d/README.md @@ -86,3 +86,12 @@ change [1]. See [2]. [1] https://github.com/coreos/fedora-coreos-tracker/issues/1969 [2] https://github.com/coreos/fedora-coreos-tracker/issues/2029 + +40import-virtiofs-systemd-credentials +------------------------------------- + +Support exposing systemd-credentials via virtiofs. This is a +cross-architecture alternative way to get settings into an +instance when Ignition isn't an option (i.e. non-coreos bootable +container) or when we want to explicity test behavior when no +Ignition is provided to an instance.