maintain selinux attributes into the erofs build

This commit is contained in:
Audiobuzz
2026-06-15 21:45:59 +00:00
parent 72d3f49369
commit 450a989d4e
4 changed files with 48 additions and 8 deletions
+1 -1
View File
@@ -95,7 +95,7 @@ jobs:
sudo apt-get install -y --no-install-recommends \ sudo apt-get install -y --no-install-recommends \
qemu-system-x86 qemu-utils libguestfs-tools linux-image-generic \ qemu-system-x86 qemu-utils libguestfs-tools linux-image-generic \
erofs-utils cryptsetup-bin jq systemd-ukify systemd-boot-efi \ erofs-utils cryptsetup-bin jq systemd-ukify systemd-boot-efi \
buildah shellcheck buildah shellcheck attr
sudo chmod 0644 /boot/vmlinuz-* 2>/dev/null || true sudo chmod 0644 /boot/vmlinuz-* 2>/dev/null || true
- -
+2 -1
View File
@@ -52,7 +52,8 @@ shellcheck --exclude=SC1091,SC2154 files/dracut/95dot1x-macsec/*.sh scripts/*.sh
Build-host deps: qemu-kvm, libguestfs-tools (+ a kernel for its supermin Build-host deps: qemu-kvm, libguestfs-tools (+ a kernel for its supermin
appliance), erofs-utils, cryptsetup, jq, systemd-ukify **and systemd-boot-efi** appliance), erofs-utils, cryptsetup, jq, systemd-ukify **and systemd-boot-efi**
(the latter ships the `linuxx64.efi.stub` ukify needs), sbsigntools, (the latter ships the `linuxx64.efi.stub` ukify needs), sbsigntools,
buildah (or docker). buildah (or docker), **attr** (`getfattr` — `extract-artifacts.sh` asserts the
SELinux labels survived the export; an unlabeled enforcing root denies login).
## Architecture invariants — do not violate these ## Architecture invariants — do not violate these
+24 -2
View File
@@ -99,9 +99,19 @@ is the tmpfs overlay), fleet-generic (no per-host state).
e.g. a tightly-constrained kiosk session + documented deviation — when e.g. a tightly-constrained kiosk session + documented deviation — when
hardening lands. hardening lands.
## [~] 5. Deploy & validate the end-to-end boot path (open-network test) ## [x] 5. Deploy & validate the end-to-end boot path (open-network test)
In progress. Stand up `serving/` (dnsmasq + nginx + SPDK) per ✅ **DONE (2026-06-15).** Full chain validated on QEMU/Proxmox: UEFI HTTP boot →
initramfs → DHCP → `nvmf-connect.service` auto-connects the NVMe/TCP subsystem →
two namespaces (data + verity hash) appear by pinned UUID → `systemd-veritysetup`
maps `/dev/mapper/root` → uncompressed erofs mounts → `systemd.volatile=overlay`
→ multi-user. Booted with `rd.dot1x=0` (open network) and the IP discovery
address. See bench findings below for the full list of fixes. Remaining cleanup
to leave the lab-test posture (now unblocked): revert the hardcoded IP to the
`nvme.fleet.lab` DNS name, and re-enable security (`DISABLE_DOT1X=false`) — the
secure path needs the same connect trigger over macsec0 (see ⚠ note below).
Original task: stand up `serving/` (dnsmasq + nginx + SPDK) per
[serving/README.md](../serving/README.md), rebuild the UKI with [serving/README.md](../serving/README.md), rebuild the UKI with
`nvmet_traddr=nvme.fleet.lab` (now a Packer var — older UKIs have the literal `nvmet_traddr=nvme.fleet.lab` (now a Packer var — older UKIs have the literal
`NVMET_TRADDR` placeholder and won't connect), then boot a UEFI HTTP-boot client `NVMET_TRADDR` placeholder and won't connect), then boot a UEFI HTTP-boot client
@@ -185,6 +195,18 @@ boot LAN.
`systemd.verity_root_data=`/`systemd.verity_root_hash=` by-id devices with no `systemd.verity_root_data=`/`systemd.verity_root_hash=` by-id devices with no
offset. Touches `extract-artifacts.sh`, `build-oci.sh` (artifact list + offset. Touches `extract-artifacts.sh`, `build-oci.sh` (artifact list +
SHA256SUMS), `serving/spdk-setup.sh` (2nd bdev/namespace), and invariant #9. SHA256SUMS), `serving/spdk-setup.sh` (2nd bdev/namespace), and invariant #9.
- **SELinux labels must survive into the erofs.** It booted to multi-user but
`root`/`packer-build-only` login was accepted then the session was killed
instantly. Cause: kickstart sets `selinux --enforcing`, but the build dropped
`security.selinux` xattrs (`virt-tar-out` + plain `tar -xpf` don't carry
them), so the enforcing target denied the login session on an unlabeled root
— and a read-only erofs can't autorelabel. Confirmed by booting with
`enforcing=0` (SMBIOS-injected) → login worked. **Fixed:** export via
`guestfish tar-out … selinux:true xattrs:true acls:true`, restore with
`tar --xattrs --xattrs-include='*' --acls --selinux`, and a `getfattr`
build-time assertion that `/usr/bin/bash` is labeled before `mkfs.erofs`
(mkfs.erofs preserves xattrs). Needs `attr` on the build host. The image now
boots **enforcing**.
**⚠ The secure path has the same dependency on the **⚠ The secure path has the same dependency on the
(absent) nvmf autoconnect** — when 802.1X is re-enabled, the macsec0 path (absent) nvmf autoconnect** — when 802.1X is re-enabled, the macsec0 path
must likewise drive `connect-all` (or the network-manager port #1 must wire must likewise drive `connect-all` (or the network-manager port #1 must wire
+21 -4
View File
@@ -37,7 +37,7 @@ ROOT_HASH_UUID=${ROOT_HASH_UUID:-f1ee7000-0000-4000-8000-000000000002}
ROOT_DATA_DEV="/dev/disk/by-id/nvme-uuid.${ROOT_DATA_UUID}" ROOT_DATA_DEV="/dev/disk/by-id/nvme-uuid.${ROOT_DATA_UUID}"
ROOT_HASH_DEV="/dev/disk/by-id/nvme-uuid.${ROOT_HASH_UUID}" ROOT_HASH_DEV="/dev/disk/by-id/nvme-uuid.${ROOT_HASH_UUID}"
for bin in virt-copy-out virt-tar-out virt-ls mkfs.erofs veritysetup jq; do for bin in virt-copy-out virt-ls guestfish mkfs.erofs veritysetup jq getfattr; do
command -v "$bin" >/dev/null || { echo "ERROR: $bin not found on build host" >&2; exit 1; } command -v "$bin" >/dev/null || { echo "ERROR: $bin not found on build host" >&2; exit 1; }
done done
@@ -54,12 +54,29 @@ virt-copy-out -a "$QCOW2" "/boot/$KERNEL" "/boot/initramfs-generic.img" "$OUT/"
mv "$OUT/$KERNEL" "$OUT/vmlinuz" mv "$OUT/$KERNEL" "$OUT/vmlinuz"
mv "$OUT/initramfs-generic.img" "$OUT/initramfs.img" mv "$OUT/initramfs-generic.img" "$OUT/initramfs.img"
echo "==> Exporting root tree" echo "==> Exporting root tree (preserving SELinux labels + xattrs)"
virt-tar-out -a "$QCOW2" / "$WORK/rootfs.tar" # SELinux labels MUST survive into the erofs, or the enforcing target denies the
# login session — you authenticate, then logind kills the session, and a
# read-only erofs can't autorelabel to fix itself. guestfish tar-out with
# selinux:true/xattrs:true captures security.selinux; the extraction restores it
# (--xattrs), and mkfs.erofs preserves xattrs into the image. (The old
# virt-tar-out + plain `tar -xpf` dropped the labels — that was the login bug.)
guestfish --ro -a "$QCOW2" -i \
tar-out / "$WORK/rootfs.tar" numericowner:true xattrs:true selinux:true acls:true
mkdir "$WORK/root" mkdir "$WORK/root"
tar -C "$WORK/root" --numeric-owner -xpf "$WORK/rootfs.tar" tar -C "$WORK/root" --numeric-owner --xattrs --xattrs-include='*' --acls --selinux \
-xpf "$WORK/rootfs.tar"
rm -rf "$WORK/root/boot/"* "$WORK/rootfs.tar" # diskless hosts don't need /boot rm -rf "$WORK/root/boot/"* "$WORK/rootfs.tar" # diskless hosts don't need /boot
# Fail loudly if labels didn't make it — shipping an unlabeled enforcing image
# boots but denies all logins (the symptom we just chased down).
if ! getfattr -h -n security.selinux "$WORK/root/usr/bin/bash" >/dev/null 2>&1; then
echo "ERROR: SELinux label missing on /usr/bin/bash in the extracted tree." >&2
echo " An enforcing boot would deny login. Check guestfish/tar xattr flags." >&2
exit 1
fi
echo "==> SELinux labels preserved (bash: $(getfattr -h --only-values -n security.selinux "$WORK/root/usr/bin/bash" 2>/dev/null))"
echo "==> Building reproducible erofs image" echo "==> Building reproducible erofs image"
# UNCOMPRESSED on purpose: the target Rocky 9 kernel's erofs is built without # UNCOMPRESSED on purpose: the target Rocky 9 kernel's erofs is built without
# CONFIG_EROFS_FS_ZIP, so mounting a compressed image fails at boot with # CONFIG_EROFS_FS_ZIP, so mounting a compressed image fails at boot with