veilor-os/kickstart/veilor-os.ks
veilor-org 8515bdbe38 ks: drop init_on_alloc/init_on_free from live cmdline (5x boot time on KVM)
Live ISO stalled at dracut for 5+min on KVM with init_on_alloc=1
init_on_free=1 — kernel zeroes every page on alloc/free, brutal in
virtualized memory. Keep slab_nomerge + lockdown=integrity +
randomize_kstack + vsyscall=none for live (cheap). Re-add memory
init flags on installed system via veilor-firstboot post-install
GRUB edit (planned v0.3).
2026-05-01 23:23:35 +01:00

255 lines
9.4 KiB
Text

#version=DEVEL
# veilor-os kickstart — Fedora 43 KDE base, hardened, minimal.
# Build with livemedia-creator inside build/Containerfile.
# ── Install source ──
# Hard-code version (not $releasever) because lorax doesn't expand
# inside kickstart `url`/`repo` directives. Updates repo critical:
# base Fedora 43 ships selinux-policy 42.12 with pcre2-10.47-built
# file_contexts.bin, which fails chroot %triggerin against host's
# libselinux (built against pcre2 10.46). 43.7 in updates is rebuilt.
url --mirrorlist="https://mirrors.fedoraproject.org/mirrorlist?repo=fedora-43&arch=x86_64"
# Explicit `repo --name=fedora` lets livecd-creator see base repo (it only
# reads repo.repoList, ignores url= directive). livemedia-creator + Anaconda
# honor both. No behavior change for either tool.
# Use direct baseurl (kernel.org mirror) to avoid mirrorlist 404s during
# Fedora's metadata sync windows.
repo --name=fedora --baseurl="https://download.fedoraproject.org/pub/fedora/linux/releases/43/Everything/x86_64/os/" --install
repo --name=updates --baseurl="https://download.fedoraproject.org/pub/fedora/linux/updates/43/Everything/x86_64/" --install
# Local fix-repo: build-time-only workaround for host pcre2/libselinux skew.
# Stripped from CI ks via sed in build-iso.yml. NOT shipped state.
repo --name=veilor-fix --baseurl=file:///tmp/veilor-fix-repo --install --cost=1
# ── Locale / keyboard / time (template — adjust per build) ──
keyboard --xlayouts='us'
lang en_GB.UTF-8
timezone Europe/London --utc
# ── Install mode ──
# Note: no display mode (text/graphical/cmdline) — livemedia-creator forbids.
firstboot --disable
eula --agreed
# Build-time SELinux disabled to avoid PCRE2 regex version mismatch between
# host libselinux and chroot's selinux-policy file_contexts.bin (pcre2 10.46
# vs 10.47). veilor-firstboot.service triggers `fixfiles -F onboot` and
# `setenforce 1` on first boot to re-enable enforcing mode.
selinux --permissive
# veilor-firstboot + veilor-modules-lock enabled via %post after overlay
# copy (units don't exist yet at services-config phase).
services --enabled=sshd,fail2ban,usbguard,tuned,auditd,firewalld,chronyd,sddm
# ── Network / hostname ──
network --bootproto=dhcp --device=link --activate --hostname=veilor-os
firewall --enabled --service=ssh
# ── Identity (zero-prompt; only LUKS passphrase asked at install) ──
# Note: `auth` command removed in pykickstart 3.x — defaults (sha512 shadow) apply.
rootpw --lock
user --name=admin --groups=wheel --gecos="veilor admin" --password="" --plaintext
# ── Bootloader: kernel hardening flags ──
# Note: init_on_alloc/init_on_free removed from default live cmdline —
# they zero every memory page at boot which 5x'd KVM live boot time.
# Re-enable per-install via veilor-firstboot.service for production.
bootloader --location=mbr --append="lockdown=integrity slab_nomerge randomize_kstack_offset=on vsyscall=none"
# ── Live ISO partitioning (flat — for live rootfs build only) ──
# NOTE: This is the *live* image kickstart. Final installed system uses
# a separate installer kickstart (kickstart/install.ks, planned v0.2.1)
# that does LUKS2 + btrfs subvols on the target disk.
part / --fstype=ext4 --size=8192
# ── Packages ──
%packages --excludedocs
@^kde-desktop-environment
@kde-apps
@core
@hardware-support
@standard
# live install plumbing (required by livemedia-creator --make-iso)
# CRITICAL: livesys-scripts + anaconda-live ship the systemd units lorax expects
# at squashfs creation. Without them, EFI/BOOT not built and ISO wrap fails.
# (Upstream Fedora's fedora-live-kde.ks includes these via fedora-live-base.ks.)
livesys-scripts
anaconda-live
@anaconda-tools
kernel-modules
kernel-modules-extra
glibc-all-langpacks
dracut-live
dracut-config-generic
kernel
grub2-efi-x64
grub2-efi-x64-modules
grub2-pc
grub2-pc-modules
grub2-tools
grub2-tools-extra
shim-x64
efibootmgr
syslinux
isomd5sum
xorriso
# core hardening tools
fail2ban
fail2ban-firewalld
usbguard
usbguard-tools
audit
policycoreutils-python-utils
tuned
chrony
firewalld
plymouth
# admin essentials
git
vim-enhanced
tmux
htop
podman
skopeo
NetworkManager
NetworkManager-wifi
# fonts
fontconfig
freetype
fira-code-fonts
# remove fluff
# Note: KDE Plasma 6 hard-deps on cups/geoclue2/ModemManager/PackageKit
# transitively (plasma-print-manager, xdg-desktop-portal, NM-wwan etc),
# so package removal breaks depsolve. Daemons disabled at runtime via
# scripts/20-harden-kernel.sh instead.
-abrt*
-snapd
-kde-connect
-open-vm-tools-desktop
-mlocate
%end
# ── Post-install (nochroot): copy overlay tree into installed root ──
%post --nochroot --erroronfail
set -uo pipefail
# DEST: livecd-creator sets INSTALL_ROOT, livemedia-creator uses /mnt/sysimage.
DEST="${INSTALL_ROOT:-/mnt/sysimage}"
[[ -d $DEST ]] || { echo "[ERR] DEST=$DEST does not exist (livecd-creator? livemedia-creator?)" >&2; exit 1; }
# Try multiple source paths:
# /run/install/repo/veilor — boot ISO (--virt mode)
# /work — bind mount in CI container
# $(dirname kickstart)/.. — local --no-virt builds
SRC=""
for candidate in /run/install/repo/veilor /work /mnt/work; do
if [[ -d $candidate/overlay ]]; then
SRC=$candidate
break
fi
done
# Fallback: derive from kickstart path. Anaconda passes ks via --kickstart=<path>.
if [[ -z $SRC ]]; then
KS_PATH=$(ps -ef | grep -oP -- '--kickstart[= ]\K[^ ]+' | head -1)
if [[ -n $KS_PATH && -d $(dirname "$KS_PATH")/../overlay ]]; then
SRC=$(realpath "$(dirname "$KS_PATH")/..")
fi
fi
if [[ -z $SRC ]]; then
echo "[ERR] cannot locate veilor-os repo source — overlay/scripts not copied" >&2
exit 1
fi
echo "[INFO] using SRC=$SRC DEST=$DEST"
set -x
cp -a "$SRC/overlay/." "$DEST/" || echo "[ERR] overlay cp failed: $?"
mkdir -p "$DEST/usr/share/veilor-os" || echo "[ERR] mkdir failed: $?"
ls -la "$SRC/assets" "$SRC/scripts" 2>&1 || echo "[ERR] assets/scripts missing in $SRC"
cp -a "$SRC/assets" "$DEST/usr/share/veilor-os/" || echo "[ERR] assets cp failed: $?"
cp -a "$SRC/scripts" "$DEST/usr/share/veilor-os/" || echo "[ERR] scripts cp failed: $?"
ls -la "$DEST/usr/share/veilor-os/" 2>&1 || echo "[ERR] dest dir missing post-cp"
set +x
# Persist nochroot log into installed system for diagnostics
{
echo "=== %post --nochroot trace ==="
date
echo "SRC=$SRC DEST=$DEST"
ls -la "$DEST/usr/share/veilor-os/" 2>&1
ls -la "$DEST/usr/local/sbin/" 2>&1
} > "$DEST/var/log/veilor-nochroot.log" 2>&1 || true
%end
# ── Post-install (chroot): apply hardening, theme, branding ──
%post
set -uo pipefail
exec > >(tee -a /var/log/veilor-install.log) 2>&1
echo "════════════════════════════════════════════════════════"
echo " veilor-os install — %post"
echo "════════════════════════════════════════════════════════"
REPO=/usr/share/veilor-os
chmod +x $REPO/scripts/*.sh $REPO/scripts/selinux/*.sh /usr/local/bin/veilor-power /usr/local/sbin/veilor-firstboot
# Live image plumbing (matches upstream Fedora live ks). Without these the
# squashfs/EFI build fails — livesys-scripts ships systemd units lorax expects.
systemctl enable livesys.service livesys-late.service 2>/dev/null || true
systemctl enable tmp.mount 2>/dev/null || true
# /etc/machine-id reset on first boot (live image baseline)
> /etc/machine-id
# Apply hardening
bash $REPO/scripts/10-harden-base.sh
bash $REPO/scripts/20-harden-kernel.sh
# Build SELinux module
bash $REPO/scripts/selinux/build-policy.sh || echo "[WARN] SELinux build failed; load on first boot"
# Apply KDE theme + DuckSans + os-release branding
bash $REPO/scripts/kde-theme-apply.sh
# Force admin password set on first boot.
# livecd-creator does NOT honor `user` kickstart directive (it's a LIVE
# image, no installer step). Create admin manually in chroot %post.
if ! getent passwd admin >/dev/null; then
useradd -m -G wheel -s /bin/bash -c "veilor admin" admin
passwd -d admin # blank password
chage -d 0 admin # expire → forced reset on first login
echo "[INFO] admin user created (blank password, expired)"
fi
# zram swap (no disk swap; keys never leak to platter)
dnf install -y zram-generator || true
cat > /etc/systemd/zram-generator.conf << 'EOF'
[zram0]
zram-size = min(ram, 8192)
compression-algorithm = zstd
EOF
# Enable services
systemctl enable veilor-firstboot.service
systemctl enable veilor-modules-lock.service
systemctl enable sshd fail2ban usbguard tuned auditd firewalld chronyd
# Default tuned profile = balanced (AC/battery udev rule will override)
tuned-adm profile veilor-balanced 2>/dev/null || true
# Lock root explicitly (kickstart --lock should already do this)
passwd -l root
# Sanity: zero references to onyx / personal IPs in installed system
if grep -rqi 'onyx\|192\.168\.0\.\|fedora\.local' /etc/veilor* /etc/tuned/profiles/veilor-* 2>/dev/null; then
echo "[ERR] brand leak detected in /etc — investigate"
fi
echo "════════════════════════════════════════════════════════"
echo " veilor-os install complete"
echo "════════════════════════════════════════════════════════"
%end