Anaconda und Kickstart

Anaconda, welches hauptsächlich aus dem Hause Red Hat stammt, ist ein Installationsprogramm zur manuellen oder automatisierten Installation eines Linux-Betriebssystems (und nicht mit der freien wissenschaftlichen Python-Distribution mit dem gleichen Namen zu verwechseln). Anaconda bietet seinen Installationsassistenten je nach Wunsch oder System-Ressourcen per Web UI (Standard ab RHEL 10), GUI oder TUI an.

Anaconda wandelt sich von Version zu Version stark und wird meist einfacher und klarer. Mit RHEL 10 löst die browserbasierte Anaconda Web UI den bisherigen GTK-Installer als Standard ab. Der Text-Modus und die Kickstart-gestützte Installation funktionieren unverändert weiter.

Die Datei, um die Installation automatisiert durchzuführen (dem Installationsassistenten also die Antworten unterzuschieben), nennt sich Kickstart. Zu jeder Neuinstallation erzeugt Anaconda automatisch die Datei /root/anaconda-ks.cfg, die als Setup-Referenz dient, und mit der man das System unbeaufsichtigt wieder in den Ursprungszustand versetzen kann.

Unter Debian heisst das Äquivalent Preseed (über den klassischen Debian Installer, d-i), unter Ubuntu 20.04+ heisst es Autoinstall (über den Installer subiquity, YAML-basiert). Die drei Formate sind nicht kompatibel zueinander, folgen aber demselben Prinzip: eine Datei beantwortet alle Fragen, die der Installer sonst interaktiv stellen würde.

Eine Kickstart-Datei lässt sich wie folgt auf Korrektheit prüfen:

dnf --assumeyes install pykickstart
ksvalidator /root/anaconda-ks.cfg

Ist die Kickstart-Datei valide, beendet sich ksvalidator ohne Fehler. Mit --version RHEL10 lässt sich explizit gegen die RHEL-10-Syntax prüfen.

Kickstart-Datei

Kickstart-Dateien werden praktischerweise auf einem Webserver abgelegt. Zusätzlich hat man so die Möglichkeit, die Dateien auch dynamisch zu generieren.

Um eine automatisierte Installation durchzuführen, im GRUB-Menü des Installers E drücken, die gewünschten Parameter an die linux-Zeile anhängen und mit Ctrl-X booten. Seit RHEL 8 verwendet GRUB2 im BIOS- wie im UEFI-Modus die linux- und initrd-Kommandos (die früheren linuxefi/initrdefi-Varianten gibt es nicht mehr):

linux inst.ks=https://example.com/ks.cfg

Das setzt voraus, dass das System über die primäre Netzwerkkarte dynamisch eine IP-Adresse zugewiesen bekommt, mit der es auf den angegebenen Webserver zugreifen kann (statt des Namens des Webservers empfiehlt es sich, dessen IP-Adresse zu verwenden, um Namensauflösungsproblemen vorzubeugen). Falls das System über mehrere Netzwerkkarten verfügt, will Anaconda wissen, über welche es seine Netzwerkeinstellungen beziehen soll. Um diese Unterbrechung zu verhindern, hilft die direkte Angabe der primär zu verwendenden Netzwerkkarte:

linux inst.ks=https://example.com/ks.cfg ip=ens33:dhcp

Möchte man, dass Anaconda IP-Adresse und Netzmaske per Übergabe konfiguriert, verwendet man z.B.

linux inst.ks=https://example.com/ks.cfg ip=192.0.2.62::192.0.2.1:255.255.255.0:server.example.com:ens33:none nameserver=192.0.2.100 nameserver=192.0.2.101

Liegt die Kickstart-Datei auf einem HTTPS-Server mit selbstsigniertem Zertifikat, lässt sich die Zertifikatsprüfung mit inst.noverifyssl deaktivieren:

linux inst.ks=https://example.com/ks.cfg inst.noverifyssl

Bemerkung

Wer auf den grafischen Installer (bzw. ab RHEL 10 auf die Web UI) verzichten möchte oder muss, kann während der Installation einen Text-only-Modus erzwingen. Dazu im Installations-Menü die E-Taste drücken und inst.text an die linux-Zeile anhängen. Man beachte, dass so allerdings nur ein Minimal-System ohne aktive Netzwerkkarten installiert wird. Mit zusätzlichem inst.asknetwork wird die Netzwerkkarte während der Installation aktiviert. Die Installation solch eines Servers nimmt weniger als 5 Minuten in Anspruch.

Wird ein USB-Stick verwendet, kommt es auf einigen Maschinen vor, dass Anaconda das Betriebssystem unbedingt auf dem Stick installieren möchte (der Stick wird beispielsweise als /dev/sda erkannt, so dass man im Kickstart-File mit --driveorder=sdb,sda arbeiten muss). Der Parameter nousbstorage verhindert solche unschönen Workarounds, die zudem nicht zuverlässig und überall funktionieren:

linux nousbstorage ...

Falls das Kickstart-File auf einem CD-ROM/DVD liegt:

linux inst.ks=cdrom:/install.cfg

Allgemeiner Aufbau

Innerhalb der einzelnen Sektionen kommt es seltenst auf die Reihenfolge der Kommandos an. Im Zweifel Doku zu Rate ziehen.

# mandatory sections

command section

%packages section
%end


# optional sections

%pre
%end

%pre-install
%end

%post
%end

%onerror
%end

%traceback
%end

Command Section

Sammelsurium an Befehlen in der Command Section, aus dem Alltag:

# GUI/Web UI: Use graphical install (default on RHEL 10)
graphical

# GUI/TUI: Use textual install
text

# Installation Media: Use CDROM installation media
cdrom

# Installation Media: Use hard drive installation media
harddrive --partition=LABEL=RHEL-10-0-0-BaseOS-x86_64 --dir=/

# Installation Media: Use HTTP
url --url="http://198.51.100.10/rhel10/"

# Installation Media: Use an NFS share
nfs --server=198.51.100.10 --dir=/exports/rhel10

# Register with Red Hat Subscription Manager (RHEL only)
rhsm --organization=1234567 --activation-key=my-activation-key --connect-to-insights

# System Timezone (modern form: chrony via timesource)
timezone Europe/Zurich --utc
timesource --ntp-server=0.ch.pool.ntp.org
timesource --ntp-server=1.ch.pool.ntp.org

# System Timezone: Disable NTP entirely
timezone Europe/Zurich --utc
timesource --ntp-disable

# Keyboard Layout: Swiss German
keyboard --vckeymap=ch --xlayouts='ch'

# Keyboard Layout: US
keyboard --vckeymap=us --xlayouts='us'

# System Language
lang en_US.UTF-8

# Network: Set Hostname
network --hostname=localhost.localdomain

# Network: Static
network --bootproto=static --device=eth0 --gateway=192.0.2.1 --ip=192.0.2.62 --nameserver=192.0.2.100,192.0.2.101 --netmask=255.255.255.0 --ipv6=auto --activate

# Network: DHCP
network --bootproto=dhcp --device=enp1s0 --ipv6=auto --activate

# Run the Setup Agent on first boot
firstboot --enable

# Root password: Set root password
rootpw --iscrypted $6$SClI7oo...Mi/waVA3Frinvz0

# Root password: Lock the root account (then create an admin user via `user`)
rootpw --lock

# Root password: Allow SSH login as root with password (disabled by default since RHEL 9)
rootpw --iscrypted --allow-ssh $6$SClI7oo...Mi/waVA3Frinvz0

# System services
services --enabled="chronyd,sshd"
services --disabled="kdump"

# Only use the listed disks for installation
ignoredisk --only-use=vda,nvme0n1

# Partition clearing information
clearpart --none --initlabel

# System bootloader configuration
# On UEFI systems omit --location; Anaconda places the bootloader in the EFI system partition.
bootloader --append="crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M" --location=mbr --boot-drive=vda

# Disk: Automatic Partitioning
autopart --type=lvm

# Disk: Create platform-specific required partitions automatically (biosboot, /boot/efi, PReP)
reqpart --add-boot

# Boot Partition: Manual Partitioning with BIOS-/Legacy-Boot and XFS, on one partition
part /boot --fstype="xfs" --ondisk=sda --size=1024
part pv.01 --fstype="lvmpv" --ondisk=sda --size=1024 --grow

# Boot Partition: Manual Partitioning with UEFI-Boot and XFS
part /boot/efi --fstype="efi" --ondisk=nvme0n1 --size=600 --fsoptions="umask=0077,shortname=winnt"
part /boot --fstype="xfs" --ondisk=nvme0n1 --size=1024

# OS Partition
part pv.01 --fstype="lvmpv" --ondisk=nvme0n1 --size=1024 --grow

# Include a file that was created in Pre-Section
%include /tmp/disk-part.ks

# LVM: Volume Group (pesize defaults to 4 MiB, explicit here for clarity)
volgroup rhel --pesize=4096 pv.01

# LVM: LV - Unencrypted, XFS (/: use minimum 1024MB, but use more if available)
logvol swap --fstype="swap" --recommended --name=swap --vgname=rhel
logvol /    --fstype="xfs" --grow --size=1024 --name=root --vgname=rhel

# LVM: LV - Encrypted with LUKS2, Ext4
logvol swap --fstype="swap" --size=7857 --encrypted --luks-version=luks2 --name=swap --vgname=rhel
logvol /    --fstype="ext4" --size=967276 --encrypted --luks-version=luks2 --name=root --vgname=rhel


# LVM: LV - CIS-compliant (/home, /tmp, /var, /var/log, /var/log/audit and /var/tmp on their own partitions)
# all sizes are in MB
# the sizes of the LVM LV's below require a disk with 30 GB
# Anaconda creates the LVs in reverse order; LVs listed at the end will be created first
logvol /backup        --fstype="xfs"  --size=6144    --vgname=rhel --name=backup        --fsoptions="nodev"
logvol /var           --fstype="xfs"  --size=6144    --vgname=rhel --name=var           --fsoptions="nodev"
logvol /              --fstype="xfs"  --size=8192    --vgname=rhel --name=root
logvol /home          --fstype="xfs"  --size=1024    --vgname=rhel --name=home          --fsoptions="nodev"
logvol /tmp           --fstype="xfs"  --size=1024    --vgname=rhel --name=tmp           --fsoptions="nodev,noexec,nosuid"
logvol /var/log       --fstype="xfs"  --size=1024    --vgname=rhel --name=var_log       --fsoptions="nodev,noexec,nosuid"
logvol /var/log/audit --fstype="xfs"  --size=512     --vgname=rhel --name=var_log_audit --fsoptions="nodev,noexec,nosuid"
logvol /var/tmp       --fstype="xfs"  --size=1024    --vgname=rhel --name=var_tmp       --fsoptions="nodev,noexec,nosuid"
logvol swap           --fstype="swap" --recommended  --vgname=rhel --name=swap


# Do not configure the X Window System
skipx

# Local repo on the installation medium
repo --name="AppStream" --baseurl=file:///run/install/repo/AppStream

# Do something at the end of the setup
shutdown

%addon com_redhat_kdump --enable --reserve-mb='auto'
%end

%addon com_redhat_kdump --disable --reserve-mb='auto'
%end

%addon org_fedora_oscap
    content-type = scap-security-guide
    profile = xccdf_org.ssgproject.content_profile_cis
%end

%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end

Bemerkung

Der aus RHEL 6/7 bekannte Befehl auth (bzw. authconfig) wurde mit RHEL 8 entfernt und wird in RHEL 10 stillschweigend ignoriert. Wer PAM/NSS anpassen will, macht das in %post per authselect select <profile>.

Tipp

Zur logvol-Direktive:

  • die alleinige Angabe von --size erzeugt ein LogVol mit genau der angegebenen Grösse, in MB

  • --grow bedeutet: nimm dir mindestens --size MB, und wenn mehr Platz da ist, nimm dir den ganzen Rest, aber maximal bis zur optionalen --maxsize, und unter Berücksichtigung aller statischen Grössenangaben

  • wird --grow mehrfach verwendet, werden die einzelnen LV zu gleichen Teilen erstellt

  • statt mit --size, --maxsize und --grow, die Absolutwerte darstellen, lässt sich auch mit --percent arbeiten

%packages Section

%packages
@^minimal-environment
aide
audit
chrony
firewalld
kexec-tools
libselinux
openscap
openscap-scanner
rsyslog
scap-security-guide
sudo
-mcstrans
-openldap-clients
-setroubleshoot
-squid
-telnet
-xorg-x11-server-common
-ypbind
%end

%pre Section

Wird vor dem Start des Setups ausgeführt. Im Beispiel wird eine Kickstart-Datei mit Informationen zu Disk-Grössen dynamisch generiert und in der Command-Section per %include eingebunden.

%pre --interpreter=/usr/bin/bash
touch /tmp/disk-part.ks
# get disk size in GiB
DISKSIZE=$(parted --script --machine /dev/sda unit GiB print | grep --extended-regexp "/dev/sda:[0-9]*GiB" | cut --delimiter=: --fields=2 | sed --expression='s/GiB$//')
if [ ! -e /sys/firmware/efi ]; then
    # boot mode: BIOS
    if [ "${DISKSIZE}" -gt 2000 ]; then
        # and GPT needed -> create biosboot
        echo "part biosboot --fstype=biosboot --size=1 --ondisk=sda" > /tmp/disk-part.ks
    fi
fi
%end

%post Section

Die %post-Sektion wird nach der Betriebssystem-Installation und vor dem Poweroff/Reboot ausgeführt. Dieses Beispiel legt unter anderem vordefinierte Public SSH-Keys auf der Maschine ab.

%post --interpreter=/usr/bin/bash --log=/root/ks-post.log
dnf --assumeyes install nano wget

#---- Install our SSH keys ----
mkdir --mode=0700 /root/.ssh/

cat <<EOF >/root/.ssh/authorized_keys
ssh-ed25519 AAAA...ehO alice@linuxfabrik.ch
ssh-ed25519 AAAA...xYz bob@linuxfabrik.ch
EOF

### set permissions
chmod 0600 /root/.ssh/authorized_keys

### fix selinux context
restorecon -R /root/.ssh/
%end

Gehärtete Kickstart-Datei

Diese Kickstart-Datei (getestet mit RHEL 10) setzt die Security-Anforderungen der Security-Profile der CIS, PCI-DSS, Essential Eight, OSPP, STIG etc. um. Die Haupt-Anforderung liegt im Partitionierungsschema. Nachträgliche System-Anpassungen nimmt man am besten per Ansible oder Shell-Skript vor:

#version=RHEL10

# Use text mode install
text

# Run the Setup Agent on first boot
firstboot --enable

# Keyboard layouts
keyboard --vckeymap=ch --xlayouts='ch'

# System language
lang en_US.UTF-8

# Root password
# Plaintext password is: linuxfabrik
rootpw --iscrypted $6$YxsFrMkfy1PIRvCU$GJfIziATCSEOIaGLIrTa6aO1INNiNRforoW1k4N1AVju4FnCltEp6fOaq1GJdHTFaVuOmTpuTcrCAOXsXmtov1


# Do not configure the X Window System
skipx

# System services
services --enabled="chronyd,sshd,firewalld,auditd"

# System timezone
timezone Europe/Zurich --utc
timesource --ntp-server=0.ch.pool.ntp.org
timesource --ntp-server=1.ch.pool.ntp.org


# We will restrict root login
# Add a user that can login and escalate privileges
# Plaintext password is: linuxfabrik
user --name=linuxfabrik --groups=wheel --iscrypted --password=$6$YxsFrMkfy1PIRvCU$GJfIziATCSEOIaGLIrTa6aO1INNiNRforoW1k4N1AVju4FnCltEp6fOaq1GJdHTFaVuOmTpuTcrCAOXsXmtov1

# Configure firewall settings for the system (optional)
# --enabled reject incoming connections that are not in response to outbound requests
# --service=ssh allow sshd through the firewall
firewall --enabled --service=ssh

# State of SELinux on the installed system (optional)
# Defaults to enforcing
selinux --enforcing


# System bootloader configuration
# On UEFI systems omit --location; Anaconda places the bootloader in the EFI system partition.
bootloader --location=mbr --append="audit=1 audit_backlog_limit=8192 slub_debug=P page_poison=1 vsyscall=none"

# Initialize (format) all disks (optional)
zerombr

# The following partition layout scheme assumes disk of size 20GB or larger
# Modify size of partitions appropriately to reflect actual machine's hardware
#
# Remove Linux partitions from the system prior to creating new ones (optional)
# --linux      erase all Linux partitions
# --initlabel  initialize the disk label to the default based on the underlying architecture
clearpart --linux --initlabel

# Create required platform-specific partitions automatically (biosboot on BIOS/GPT, /boot/efi on UEFI)
reqpart --add-boot


# OS Partition
part pv.01 --fstype="lvmpv" --size=1024 --grow


# LVM: Volume Group
volgroup rhel --pesize=4096 pv.01


# LVM: LV - CIS-compliant (/home, /tmp, /var, /var/log, /var/log/audit and /var/tmp on their own partitions)
# all sizes are in MB
# the sizes of the LVM LV's below require a disk with 30 GB
# Anaconda creates the LVs in reverse order; LVs listed at the end will be created first
logvol /var           --fstype="xfs"  --size=6144    --vgname=rhel --name=var           --fsoptions="nodev"
logvol /              --fstype="xfs"  --size=8192    --vgname=rhel --name=root
logvol /home          --fstype="xfs"  --size=1024    --vgname=rhel --name=home          --fsoptions="nodev"
logvol /tmp           --fstype="xfs"  --size=1024    --vgname=rhel --name=tmp           --fsoptions="nodev,noexec,nosuid"
logvol /var/log       --fstype="xfs"  --size=1024    --vgname=rhel --name=var_log       --fsoptions="nodev,noexec,nosuid"
logvol /var/log/audit --fstype="xfs"  --size=512     --vgname=rhel --name=var_log_audit --fsoptions="nodev,noexec,nosuid"
logvol /var/tmp       --fstype="xfs"  --size=1024    --vgname=rhel --name=var_tmp       --fsoptions="nodev,noexec,nosuid"
logvol swap           --fstype="swap" --recommended  --vgname=rhel --name=swap


# Reboot after the installation is complete (optional)
# --eject   attempt to eject CD or DVD media before rebooting
reboot --eject


%packages
@^minimal-environment
aide
audit
chrony
firewalld
openscap-scanner
scap-security-guide
sudo
%end


%pre

%end


%post --interpreter=/usr/bin/bash --log=/root/ks-post.log
#---- Install SSH keys ----
mkdir --mode=0700 /root/.ssh/

cat <<EOF >/root/.ssh/authorized_keys
ssh-ed25519 AAAAC3Nz... alice@linuxfabrik.ch
ssh-ed25519 AAAAC3Nz... bob@linuxfabrik.ch
EOF

### set permissions
chmod 0600 /root/.ssh/authorized_keys

### fix up selinux context
restorecon -R /root/.ssh/
%end

Linuxfabrik-Kickstart-Projekt

Die Linuxfabrik pflegt unter github.com/Linuxfabrik/kickstart einen harmonisierten Satz an Installations-Vorlagen, der sich über drei Distributions-Familien spannt und auf BIOS wie UEFI läuft. Das Ziel ist eine über alle unterstützten Distros gleich bedienbare, reproduzierbare Minimal-Installation als Ausgangspunkt für die weitere Konfiguration per LFOps.

Unterstützt werden:

  • RHEL 8+, Fedora 38+ und kompatible über lf-rhel.cfg (Kickstart-Format)

  • Debian 11+ über lf-debian.cfg (Preseed-Format)

  • Ubuntu 20.04+ über lf-ubuntu.cfg (Autoinstall für den subiquity-Installer)

Gemeinsame Eigenschaften über alle drei Distro-Familien:

  • Automatische BIOS-/UEFI-Erkennung, GPT auf UEFI.

  • LVM-basierte Partitionierung mit mindestens /, /backup, /boot und swap.

  • Zwei-Benutzer-Modell: Der Benutzer linuxfabrik (in wheel bzw. mit passwort-losem sudo) ist der reguläre administrative Zugang, root ist durchgängig gesperrt und erhält weder Passwort noch SSH-Keys.

  • SELinux läuft auf den RHEL-basierten Varianten im Modus enforcing.

  • Jede Installation hinterlegt einen Build-Stempel im Format YYYYMMDDNN in /root/lf-install-version. Diese Datei ist auf RHEL, Debian und Ubuntu identisch benannt und ermöglicht es, einen beliebigen Host über alle Distros hinweg mit cat /root/lf-install-version der exakten Vorlage zuzuordnen, mit der er installiert wurde.

Aufruf (RHEL/Fedora)

Für den Komfort stellt die Linuxfabrik die Kurz-URL https://linuxfabrik.ch/ks bereit, die auf lf-rhel.cfg im Repo zeigt. Damit verkürzt sich die Eingabe an der Boot-Zeile erheblich. Im GRUB-Menü E drücken, folgende Parameter an die linux-Zeile anhängen und mit Ctrl-X booten:

linux inst.ks=https://linuxfabrik.ch/ks lftype=minimal lfdisk=vda ip=192.0.2.62::192.0.2.1:255.255.255.0::ens3:none nameserver=192.0.2.100

Die Hostname- und Passwort-Abfragen entfallen; der Installer fährt nach dem Download der Kickstart-Datei vollautomatisch durch.

Install-Varianten (lftype=)

Über den Kernel-Cmdline-Parameter lftype= lässt sich eine von vier Varianten auswählen. Voreinstellung ist minimal.

lftype=

Install-Typ

Partitionierung

Passwort linuxfabrik

SSH-Keys linuxfabrik

minimal

Minimal

Minimal, LVM

password

Linuxfabrik-Keys

cis

Minimal, CIS-konform

CIS, LVM

password

Linuxfabrik-Keys

cloud

Cloud

Minimal, LVM

gesperrt (SSH-Login über cloud-init)

keine, durch cloud-init zur Laufzeit

cloud-cis

Cloud, CIS-konform

CIS, LVM

gesperrt (SSH-Login über cloud-init)

keine, durch cloud-init zur Laufzeit

Die CIS-Partitionierung spannt die in der CIS-Benchmark verlangten separaten Mount-Points auf: /home, /tmp, /var, /var/log, /var/log/audit und /var/tmp landen je auf eigenen LVs inklusive der Mount-Optionen nodev, noexec und nosuid, wo die Benchmark das fordert.

Zielplatte (lfdisk=)

Ohne lfdisk= sucht die Kickstart-Datei die erste vorhandene Blockdevice in der Reihenfolge vdasdanvme0n1 und installiert dorthin. Existiert keines dieser Geräte, bricht die Installation ab. Mit lfdisk=$DISK lässt sich das Ziel explizit setzen, z.B. lfdisk=nvme1n1.

Dynamisch generierte Kickstart-Datei

Die eigentliche Logik liegt nicht in lf-rhel.cfg selbst, sondern in einer dynamisch erzeugten Include-Datei. Der Ablauf sieht so aus:

  1. Die %pre-Sektion in lf-rhel.cfg prüft, welche Python-Version im Installer verfügbar ist, schreibt einen Python-Helper nach /tmp/pre-script.py und führt ihn aus.

  2. Der Python-Helper liest lftype= und lfdisk= aus der Kernel-Cmdline, wählt die passenden Listen für Pakete, LVs, Benutzer und %post-Skripte aus und rendert daraus /tmp/dynamic.ks.

  3. lf-rhel.cfg bindet diese Datei mit %include /tmp/dynamic.ks in die Command-Section ein, so dass Anaconda mit der vollständigen, für die gewählte Variante korrekten Kickstart-Datei arbeitet.

Dieses Muster sollte man verstehen, bevor man die Kickstart-Datei anpasst. Geändert wird in der Regel nicht lf-rhel.cfg, sondern der Python-Helper mit seinen distro- und lftype-spezifischen Listen:

  • lfkeys: Array von Public SSH-Keys, die für den Benutzer linuxfabrik auf den Nicht-Cloud-Varianten hinterlegt werden. Der Benutzer root erhält grundsätzlich keine Keys.

  • packages_<lftype>: Paketliste je lftype.

  • part_<lftype>: Array von logvol-Zeilen je lftype.

  • users_<lftype>: Python-Liste mit Dicts (name, cmd, keys) je Benutzer.

  • post_<lftype>: Mehrzeiliger %post-Block, der im Chroot des frischen Systems ausgeführt wird.

Build-Stempel und Nachverfolgbarkeit

Jede Kickstart-, Preseed- oder Autoinstall-Datei aus dem Projekt trägt eine LF_KICKSTART_VERSION im Format YYYYMMDDNN (Datum plus zweistellige Laufnummer). Dieser Stempel wird zum Installationszeitpunkt geloggt und auf dem installierten System in /root/lf-install-version abgelegt. Die Datei ist auf RHEL, Debian und Ubuntu gleich benannt und hat denselben Inhalt, so dass sich ein Host distro-unabhängig identifizieren lässt:

cat /root/lf-install-version

Auf RHEL enthält zusätzlich /root/dynamic.ks in der ersten Kommentar-Zeile # Linuxfabrik Kickstart version: YYYYMMDDNN. Auf Debian taucht derselbe Stempel in /var/log/installer/syslog auf, auf Ubuntu in /var/log/installer/installer-journal.txt. Damit lässt sich bei Nach-Analysen der exakte Build der Vorlage rekonstruieren, mit dem ein Host installiert wurde, auch wenn der Host sonst keine Informationen über seine Installationsgeschichte mehr trägt.

Log-Dateien je Installer

Bei Installationsproblemen ist der Griff in die Installer-Logs meistens schneller als langes Raten. Aus der Installer-Umgebung erreicht man auf RHEL/Rocky/Fedora einen Shell-Prompt mit Ctrl-Alt-F2 oder Ctrl-Alt-F3, auf Debian und Ubuntu mit Ctrl-Alt-F2.

Anaconda (RHEL/Fedora):

  • /tmp/dynamic.ks: Die vom %pre-Helper gerenderte Include-Datei. Bei Syntax-Fehlern in einem %include als Erstes prüfen, was tatsächlich drin steht.

  • /tmp/kickstart.install.pre.log: Output des %pre-Skripts inklusive LF_KICKSTART_VERSION, der lftype- und lfdisk-Erkennung sowie der Fortschrittsmeldungen des Python-Helpers.

  • /tmp/pre-script.py: Der Python-Helper selbst. Nützlich, wenn %pre an einer bestimmten Python-Zeile abstürzt.

  • /tmp/ks-script-*.log: Output jedes %post-Blocks.

  • /var/log/anaconda/anaconda.log: Haupt-Narrativ des gesamten Installers. Erster Blick bei nach-dem-Boot sichtbaren Symptomen.

  • /var/log/anaconda/storage.log: Partitionierung, LVM, Formatierung. Anlaufstelle bei „disk not found“, ignoredisk oder LVM-Problemen.

  • /var/log/anaconda/packaging.log: DNF-Transaktionen im Detail.

  • /var/log/anaconda/program.log: Externe Aufrufe (grub2-mkconfig, mkfs.xfs usw.).

  • /var/log/anaconda/ks-script-*.log: Persistente Kopie der %post-Outputs. grep -l 'Linuxfabrik Kickstart version' /var/log/anaconda/ks-script-*.log identifiziert, welches Skript den Linuxfabrik-Block ausgeführt hat.

  • /root/anaconda-ks.cfg: Die von Anaconda erzeugte Zusammenfassung des effektiven Kickstarts (nicht auf allen Targets vorhanden).

  • /root/original-ks.cfg: Wortgetreue Kopie der von inst.ks= bezogenen Vorlage.

  • /root/dynamic.ks: Die Linuxfabrik-Include-Datei nach Abschluss der Installation.

Debian Installer (d-i):

  • /var/log/syslog: Haupt-Syslog des Installers während der Installation.

  • /var/log/partman: Partitionierungs-Log.

  • /var/log/installer/syslog: Installationslog, persistiert nach Abschluss. Enthält die Zeile mit LF_KICKSTART_VERSION.

  • /var/log/installer/cdebconf/questions.dat: Welche Preseed-Antworten debconf tatsächlich erhalten hat. Anlaufstelle, um zu prüfen, ob ein Preseed-Key überhaupt gegriffen hat.

Ubuntu subiquity:

  • /var/log/installer/autoinstall-user-data: Die YAML-Autoinstall-Datei, wie subiquity sie tatsächlich geparst hat.

  • /var/log/installer/subiquity-server-debug.log: Debug-Log des subiquity-Servers, streamt während der Installation.

  • /var/log/installer/curtin-install.log: curtin ist der eigentliche Installer unter subiquity. Erste Anlaufstelle für Partitionierungs-, LVM- und GRUB-Probleme.

  • /var/log/installer/installer-journal.txt: Journal-Snapshot der Installer-Umgebung. Enthält die Zeile mit LF_KICKSTART_VERSION.

Auf den cloud-Varianten (lftype=cloud und lftype=cloud-cis) sowie auf Debian- und Ubuntu-Cloud-Hosts übernimmt cloud-init SSH-Key- und Hostname-Setup beim ersten Boot. Die passenden Logs liegen auf dem frisch installierten System unter /var/log/cloud-init.log und /var/log/cloud-init-output.log.

Aufruf-Beispiele für Debian und Ubuntu

Debian netinst- oder DVD-ISO booten, im Boot-Menü Esc drücken und eingeben:

auto url=http://198.51.100.10/lf-debian.cfg

Ubuntu Server-ISO booten. Die Datei lf-ubuntu.cfg muss als user-data neben einer leeren meta-data auf einem HTTP-Server liegen. An die Kernel-Cmdline anhängen:

autoinstall ds=nocloud-net;s=http://198.51.100.10/

Troubleshooting

DNF error: Error in POSTTRANS scriptlet in rpm package kernel-core

Kann an zu wenig Platz für /var/tmp liegen. Hier sind mindestens 384 MB empfohlen.

ksvalidator meldet Unknown command: auth

Das auth-Kommando existiert seit RHEL 8 nicht mehr. Zeile entfernen und PAM/NSS stattdessen in %post per authselect konfigurieren.

page_poison=1 macht UEFI-System nach erstem Boot unbootbar

Beobachtet auf TianoCore-Firmware unter QEMU. Die Kernel-Cmdline-Option aus dem bootloader --append=-Block entfernen. Details unter RHEL 8.7 Known Issues.

Fedora 38 bootet nicht in den Installer

Als Workaround inst.neednet=1 rd.debug an die Kernel-Cmdline anhängen, um mehr Diagnose-Output zu erhalten.