Merge pull request 'optimise-ram' (#11) from optimise-ram into main

Reviewed-on: https://git.bitasylum.org/audiobuzz/diskless-workstation/pulls/11
This commit is contained in:
audiobuzz
2026-07-05 06:46:52 +00:00
2 changed files with 113 additions and 7 deletions
+46 -1
View File
@@ -393,6 +393,17 @@ build {
# AVC in Wazuh — that would also hide future rhsmcertd_t denials.)
"systemctl mask rhsmcertd.service 2>/dev/null || true",
"systemctl disable rhsmcertd.service 2>/dev/null || true",
# Same class of noise, different trigger: dnf-makecache.timer fires ~10 min
# after boot and imports the whole dnf Python stack (dnf/libdnf/librepo/rhsm).
# Because the reproducible erofs `-T 0` reset makes every source .py look
# newer than its baked .pyc, that import REWRITES bytecode into the tmpfs
# overlay (measured 2026-07-03: ~MBs of dnf/libdnf/rhsm __pycache__) and
# throws lib_t write/unlink AVCs. An immutable diskless host never refreshes
# dnf caches (no persistent store, no runtime installs), so mask the timer to
# remove the trigger. Belt-and-braces with the compileall unchecked-hash step
# in 2d (which stops the rewrite at the source). See docs/TODO.md #16.
"systemctl mask dnf-makecache.timer 2>/dev/null || true",
"systemctl disable dnf-makecache.timer 2>/dev/null || true",
# Read-only erofs/verity root; runtime state on a tmpfs overlay provided
# by systemd.volatile=overlay (set in the cmdline by extract-artifacts.sh).
# RHEL/Rocky dracut has no 'overlayfs'/'rootovl' module.
@@ -886,6 +897,21 @@ build {
# custom kiosk files: add them to fapolicyd's trust DB and rebuild it. weston
# /chromium are RPM-installed so already trusted. (See docs/stig-deviations.md.)
"if command -v fapolicyd-cli >/dev/null 2>&1; then",
# RAM: fapolicyd's LMDB trust DB is rebuilt at BOOT onto the tmpfs overlay,
# so its map size (db_max_size, in MB) is a fixed RAM RESERVATION, not a
# ceiling it grows into. The EL9 default (100) was measured consuming a real
# 100 MiB of overlay RAM on a booted host (2026-07-03) — ~80% of the entire
# overlay. The minimal+kiosk trust set is a fraction of that (fapolicyd
# upstream shipped db_max_size=50 for years as the default that covers a
# FULL workstation rpmdb, which is larger than this image). Halve it to
# reclaim ~50 MiB. MUST run before the --update below so the rebuilt db uses
# the smaller map. BENCH-VERIFY the exec-guard still works end-to-end (boot +
# kiosk render + admin SSH + sudo): undersize this and fapolicyd hits
# MDB_MAP_FULL, allowlisting breaks, and login/kiosk exec is bricked (keep
# fapolicyd working — it's the writable-overlay exec guard dm-verity can't
# provide). Can drop lower after measuring `fapolicyd-cli --dump | wc -l` on
# the bench; see docs/TODO.md.
" if [ -f /etc/fapolicyd/fapolicyd.conf ]; then sed -ri 's/^[[:space:]]*#?[[:space:]]*db_max_size[[:space:]]*=.*/db_max_size = 50/' /etc/fapolicyd/fapolicyd.conf; grep -q '^db_max_size' /etc/fapolicyd/fapolicyd.conf || printf 'db_max_size = 50\\n' >> /etc/fapolicyd/fapolicyd.conf; echo '==> fapolicyd: db_max_size set to 50 MiB (was EL9 default ~100)'; fi",
" for f in /usr/local/bin/kiosk-session /usr/local/bin/fleet-sb-enroll /usr/local/bin/fleet-hostapi /usr/sbin/fleet-enrol; do { [ -f \"$f\" ] && fapolicyd-cli --file add \"$f\"; } || true; done",
" fapolicyd-cli --update 2>/dev/null || true",
" echo '==> fapolicyd: trusted custom binaries (kiosk-session, fleet-sb-enroll, fleet-hostapi) + rebuilt trust db'",
@@ -1030,6 +1056,23 @@ build {
# UKI initramfs shrinks too — see TODO #18. Nothing re-adds firmware after
# that point, so the rootfs erofs is already trimmed by the time we get here.)
#
# .pyc invalidation vs reproducible mtimes: the erofs is built `-T 0`, which
# zeroes every file's mtime. Python's DEFAULT .pyc invalidation is
# timestamp-based (the .pyc header stores the source's mtime), so at runtime
# every source .py looks newer than its baked .pyc and Python recompiles into
# the tmpfs overlay — wasting RAM and, under enforcing SELinux, throwing
# lib_t write/unlink AVCs (seen 2026-07-03: dnf/libdnf/rhsm __pycache__
# rewrites 10 min after boot). Recompile ALL bytecode with hash-based,
# UNCHECKED invalidation: the .pyc then carries a source hash flagged
# 'do not check', so Python loads it WITHOUT stat-ing the source, and never
# rewrites regardless of the `-T 0` mtimes. Bonus: hash .pyc embed no mtime,
# so they're more reproducible than timestamp .pyc (reinforces the -T 0
# invariant). MUST run LAST (after every dnf install/remove) so nothing lays
# down a fresh timestamp .pyc afterward; -f forces existing .pyc to this mode.
# Version-agnostic loop so an EL point-release python bump doesn't silently
# skip it. See docs/TODO.md #16.
"for d in /usr/lib/python3.* /usr/lib64/python3.*; do [ -d \"$d\" ] && python3 -m compileall -f -q --invalidation-mode unchecked-hash \"$d\" 2>/dev/null || true; done",
#
# ---- FINAL GUARD: assert the kiosk stack survived the whole pipeline ----
# 2026-07-03 incident: chromium installed cleanly in the 2b kiosk step (the
# footprint audit showed chromium-149 + chromium-common, 523 pkgs), but by
@@ -1043,7 +1086,9 @@ build {
# kiosk-critical package is still installed at the very end of the pipeline
# (after remediation AND all 2d removes). This catches ANY future silent drop
# — a new hard-Requires cascade, an oscap package_*_removed rule, autoremove.
# enable_kiosk=false legitimately ships no browser, so gate on it.
# Run AFTER the .pyc recompile (read-only rpm -q, lays down no bytecode, so it
# doesn't violate the "recompile last" rule). enable_kiosk=false legitimately
# ships no browser, so gate on it.
"if [ \"${var.enable_kiosk}\" = \"true\" ] && [ -n \"${var.kiosk_url}\" ]; then for p in chromium chromium-common weston mesa-dri-drivers mesa-libEGL mesa-libgbm; do rpm -q \"$p\" >/dev/null 2>&1 || { echo \"ERROR: kiosk-critical package '$p' missing from the FINAL image — a later step removed it after the 2b kiosk install (e.g. a dnf remove whose dependency cascade took chromium, cf. the 2026-07-03 nss-mdns incident). Refusing to ship a bricked kiosk.\" >&2; exit 1; }; done; echo '==> guard: kiosk stack intact (chromium/weston/mesa present after remediation + hygiene)'; fi",
]
}