Update kickstart with ssh and other details

This commit is contained in:
John A. Hoeven 2026-07-16 16:29:48 +02:00
commit ac231b790a
Signed by: giovannino
GPG key ID: 306E507219506D4E

View file

@ -8,12 +8,18 @@
# USB method: Insert USB, boot, type: inst.ks=file:///ks.cfg
# HTTP method: Boot, type: inst.ks=http://<workbench_ip>:8000/alma10-minimal-bigboy.ks
#
# Reference: /home/john/projects/bigboy-alma/alma-phase1-install-workflow.md
# Reference: plannng/alma-phase1-install-workflow.md
#
# Checksum (validate before use):
# sha256sum alma10-minimal-bigboy.ks
# (Note: Update after final edits)
#
# BEFORE USING THIS FILE — fill in both placeholders below:
# <user-name> — your administrator account username
# <sha512-hash> — output of `openssl passwd -6`, run on any Linux box.
# NEVER put a plaintext password in this file — it is
# committed to git and lives in history permanently.
#
# ============================================================================
# ============================================================================
@ -45,8 +51,9 @@ timezone Europe/Rome --utc
# ============================================================================
# Network: DHCP on primary interface (enp4s0)
# Will typically receive 192.168.0.240 on Fritzy bench LAN
# Phase 2 (Ansible) may configure static IP or DHCP reservation
# Will typically receive an address on the workbench bench LAN
# (192.168.0.0/24) during build/maintenance. Phase 13 later migrates
# BigBoy to the home LAN (192.168.1.0/24).
network --bootproto=dhcp --device=link --activate --hostname=bigboy --ipv6=off
# ============================================================================
@ -54,16 +61,67 @@ network --bootproto=dhcp --device=link --activate --hostname=bigboy --ipv6=off
# ============================================================================
# Root password: LOCK (no password login allowed)
# SSH key-based auth will be set up in Phase 2 (Ansible)
# This prevents accidental password-based access
# All administrative access happens through the account below, plus sudo.
rootpw --lock
# ----------------------------------------------------------------------
# USER ACCOUNT (Administrator access)
# ----------------------------------------------------------------------
#
# Password login is enabled deliberately for initial bring-up — not every
# device John works from has an SSH key provisioned yet. This is an
# intentional, temporary loosening: Phase 9 (Security Hardening) disables
# PasswordAuthentication and moves to key-only, matching the same
# kickstart-lenient / Ansible-hardens pattern used for SELinux and
# firewalld elsewhere in this file. Don't remove password login without
# confirming a working key-based login first — until Phase 9 runs, this
# password is the only way in.
#
# The value below MUST be a hash, never a plaintext password — this file
# is committed to git and the value lives in history permanently even if
# changed later. Generate with:
# openssl passwd -6
# on any Linux box, then paste the resulting $6$... hash in place of
# <sha512-hash>.
user --name=<user-name> --groups=wheel --shell=/bin/bash --password=<sha512-hash> --iscrypted
# SELinux: Disabled for initial deployment (Phase 9 enables in Permissive)
# Allows us to monitor denials during first month without blocking services
selinux --disabled
# Firewall: Disabled during installation (Phase 9 hardens with firewalld)
firewall --disabled
# ----------------------------------------------------------------------
# FIREWALL: Enabled from first boot — LAN-only SSH access
# ----------------------------------------------------------------------
#
# Originally planned as disabled-until-Phase-9. That plan assumed
# key-only SSH from the start; since password auth is enabled above for
# initial bring-up, leaving the firewall off would mean password-auth SSH
# is reachable from anywhere that can route to this box — not acceptable
# even temporarily.
#
# firewalld starts enabled; the default zone carries no blanket SSH
# allowance. %post below adds rich rules restricting SSH specifically to
# the two known LAN ranges:
# 192.168.1.0/24 — home LAN (also covers WireGuard VPN clients, which
# Fritz bridges directly into this range — confirmed
# 2026-07-16, no separate VPN subnet exists)
# 192.168.0.0/24 — workbench bench LAN (BigBoy's build/maintenance
# network; also what's reached by devices whose
# home-LAN traffic workbench NATs onto the bench
# switch — arrives with workbench's bench-LAN address,
# already covered by this same range)
#
# No forwarded port 22 exists on the router, so this firewall rule is a
# second layer, not the only thing standing between BigBoy and the open
# internet — but it's the correct posture regardless, especially with
# password auth active.
#
# Phase 9 still applies its broader hardening pass on top of this
# baseline; that pass should also revoke the temporary password-login
# exception above, not just review the firewall further.
firewall --enabled
# ============================================================================
# REPOSITORY CONFIGURATION
@ -84,6 +142,10 @@ repo --name="almalinux10-crb" --mirrorlist="https://mirrors.almalinux.org/mirror
# Additional packages not in standard RHEL repos
repo --name="epel10" --mirrorlist="https://mirrors.fedoraproject.org/mirrorlist?repo=epel-10&arch=x86_64"
# NOTE: these repos require real outbound internet access during install,
# not just reachability within the bench LAN — confirm this path is open
# before booting, not after a stalled package download mid-install.
# ============================================================================
# BOOTLOADER CONFIGURATION
# ============================================================================
@ -106,6 +168,11 @@ bootloader --location=partition --boot-drive=nvme0n1
#
# Important: SATA partitions are created but NOT mounted during kickstart.
# Phase 3 Ansible role handles subvolume creation, mounting, and fstab.
#
# Drive identity confirmed 2026-07-16 via blkid labels prior to wipe:
# sda = BACKUPDRV, sdb = RAGLIB, sdc = AILOGS, sdd = PROMPTLIB
# (labels are destroyed by the wipe/reinstall — recorded here for
# provenance only; Phase 3 re-establishes them from group_vars/bigboy.yml)
# ============================================================================
# Do not erase existing partitions (safety measure)
@ -143,21 +210,21 @@ part / --fstype=btrfs --size=1 --grow --ondrive=nvme0n1
# - Configure fstab with UUIDs (from HARDWARE.md)
# - Set compression and mount options
# SATA Drive 1 (sda): RAG Library partition
# Will be mounted at /srv/rag-library in Phase 3
part /srv/rag-raw --fstype=btrfs --size=1 --grow --ondrive=sda
# SATA Drive 2 (sdb): Prompt Library partition
# Will be mounted at /srv/prompt-library in Phase 3
part /srv/prompt-raw --fstype=btrfs --size=1 --grow --ondrive=sdb
# SATA Drive 3 (sdc): Backup partition
# SATA Drive 1 (sda): Backup partition — was labeled BACKUPDRV
# Will be mounted at /srv/backup in Phase 3
part /srv/backup-raw --fstype=btrfs --size=1 --grow --ondrive=sdc
part /srv/backup-raw --fstype=btrfs --size=1 --grow --ondrive=sda
# SATA Drive 4 (sdd): AI Logs partition
# SATA Drive 2 (sdb): RAG Library partition — was labeled RAGLIB
# Will be mounted at /srv/rag-library in Phase 3
part /srv/rag-raw --fstype=btrfs --size=1 --grow --ondrive=sdb
# SATA Drive 3 (sdc): AI Logs partition — was labeled AILOGS
# Will be mounted at /srv/ai-logs in Phase 3
part /srv/ai-raw --fstype=btrfs --size=1 --grow --ondrive=sdd
part /srv/ai-raw --fstype=btrfs --size=1 --grow --ondrive=sdc
# SATA Drive 4 (sdd): Prompt Library partition — was labeled PROMPTLIB
# Will be mounted at /srv/prompt-library in Phase 3
part /srv/prompt-raw --fstype=btrfs --size=1 --grow --ondrive=sdd
# ============================================================================
# PACKAGE SELECTION
@ -327,22 +394,76 @@ EOF
# This ensures nouveau won't load on next boot
dracut --force 2>&1 >> /srv/deployment-log/kickstart.log
# ============================================================================
# SUDO BOOTSTRAP (temporary — narrow NOPASSWD exception)
# ============================================================================
#
# Phase 2 (Ansible) is what actually configures the real sudoers policy for
# the wheel group. But Phase 2 itself needs to run privileged commands to
# do that — and without this, there is no path to escalate privilege at
# all between first boot and Phase 2 completing. This drop-in is narrowly
# scoped to <user-name> only, clearly temporary, and is expected to be
# superseded (not just left in place) once Phase 2's real sudoers policy
# is applied. Verify Phase 2 actually replaces this rather than assuming
# it does.
cat > /etc/sudoers.d/00-bootstrap-<user-name> << 'EOF'
# Temporary bootstrap exception — superseded by Phase 2 Ansible sudoers policy.
# If you are reading this after Phase 2 has run, something did not get
# cleaned up correctly; check ansible/roles/phase-2-*/ for the real policy.
<user-name> ALL=(ALL) NOPASSWD: ALL
EOF
chmod 0440 /etc/sudoers.d/00-bootstrap-<user-name>
# ============================================================================
# SSH DAEMON SETUP (Foundation for Phase 2+ Ansible)
# ============================================================================
# Explicitly enable password authentication — don't rely on the distro
# default, which can vary and may already be hardened in the base image.
# Phase 9 flips this back to 'no' once key-based auth is confirmed working.
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config
# Enable SSH daemon to start on boot
systemctl enable sshd
# Start SSH immediately (allows manual access if needed before Phase 2)
systemctl start sshd
# Restart to pick up the PasswordAuthentication change above
systemctl restart sshd
# Log SSH readiness
{
echo "SSH daemon enabled and started"
echo "SSH daemon enabled and started, password auth explicitly enabled"
systemctl status sshd | head -1
} >> /srv/deployment-log/kickstart.log 2>&1
# ============================================================================
# FIREWALL: Restrict SSH to known LAN ranges only
# ============================================================================
#
# firewalld is enabled (see FIREWALL block above) but the default zone has
# no blanket ssh service allowance — only these two specific source ranges
# can reach sshd at all. Anything outside 192.168.1.0/24 or 192.168.0.0/24
# is dropped by the zone default, before authentication is even attempted.
#
# firewall-cmd --permanent writes directly to the zone's XML config on
# disk; this works correctly here even though firewalld isn't actively
# running yet inside the install chroot — the rules take effect the
# moment firewalld starts on first real boot.
firewall-cmd --permanent --zone=public \
--add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="ssh" accept'
firewall-cmd --permanent --zone=public \
--add-rich-rule='rule family="ipv4" source address="192.168.0.0/24" service name="ssh" accept'
{
echo "Firewall rich rules applied: SSH restricted to LAN ranges"
echo " Allowed: 192.168.1.0/24 (home LAN, incl. WireGuard VPN clients)"
echo " Allowed: 192.168.0.0/24 (workbench bench LAN)"
} >> /srv/deployment-log/kickstart.log 2>&1
# ============================================================================
# POST-SCRIPT COMPLETION LOG
# ============================================================================
@ -372,15 +493,17 @@ exit 0
# ============================================================================
#
# Note: Root password is locked (rootpw --locked above)
# These policies apply only to user account creation during installation
# These policies apply to the user account created during installation
# ============================================================================
%anaconda
# Root password policy (not applicable due to locked root)
# pwpolicy root --minlen=6 --minquality=50 --notstrict --nochanges --notempty
# User account policy (lenient; Ansible Phase 2 will harden)
pwpolicy user --minlen=6 --minquality=50 --notstrict --nochanges --emptyok
# User account policy — the account has a real (hashed) password per the
# USER ACCOUNT section above, so this is not left empty-ok as it was when
# no user account existed.
pwpolicy user --minlen=8 --minquality=50 --notstrict --nochanges --notempty
# LUKS encryption policy (if encrypted partitions created)
pwpolicy luks --minlen=6 --minquality=50 --notstrict --nochanges --notempty
@ -399,22 +522,34 @@ reboot --eject
# ============================================================================
#
# Verification checklist before use:
# [ ] Replaced <user-name> with the actual administrator username
# (appears in THREE places: user --name=, sudoers filename, sudoers
# file content — a find/replace across the whole file is safest)
# [ ] Replaced <sha512-hash> with the actual `openssl passwd -6` output
# [ ] NVMe device name is correct (nvme0n1)
# [ ] SATA device names are correct (sda, sdb, sdc, sdd)
# [ ] Network interface (enp4s0) matches hardware
# [ ] Hostname (bigboy) is correct
# [ ] Timezone (Europe/Rome) is correct
# [ ] Repositories are accessible (test with: curl <repo_url>)
# [ ] Real outbound internet access confirmed (not just bench LAN reachability)
# [ ] Post-install script has no syntax errors
#
# Expected outcome (Phase 1):
# - AlmaLinux 10.2 minimal installation
# - NVMe partitioned: EFI (1GB) + btrfs root (~499GB)
# - SATA drives partitioned: single btrfs partition each
# - SSH daemon running and ready for Ansible
# - <user-name> account created, wheel group, password login enabled
# - Temporary NOPASSWD sudo bootstrap in place for <user-name>
# - SSH daemon running, password auth explicitly enabled
# - Firewall enabled, SSH restricted to 192.168.1.0/24 and 192.168.0.0/24
# - /srv/deployment-log/ created and logged
# - Nouveau blacklisted, initramfs rebuilt
# - System reboots automatically
#
# Known temporary states this file creates, both closed out by Phase 9:
# 1. Password-based SSH login (Phase 9 → key-only)
# 2. Blanket NOPASSWD sudo bootstrap (Phase 9/Phase 2 → real sudoers policy)
#
# Next phase: Phase 2 (System Configuration & Secondary Drive Preparation)
# ============================================================================