How to create a fully unattended installation iso?

I have downloaded the Fedora Server 38 iso and I have configured my ks.cfg and now I want to make a fully automated iso. How do I do this? I was told I needed to add my ks.cfg file to the root directory of the usb but I can’t do that because it is always mounted as read-only. That also means I’m unable to make the changes to grub so that the installation starts on its own.

My favorite way is to use lorax to inject the kickstart into an existing netinstall ISO.

I sadly have not much time to work on this project but you can see how it works and borrow the idea:

Though late to the party maybe this will help someone new.

Make a second usb flash drive with your kickstart file on it

#!/bin/bash
set -x

#Produce a filesystem disk image with
#  FSLABEL=OEMDRV
#  ks.cfg file in /
#
#Script must be run from top
# top-|-bin
#     |-downloads
#     |-files
#     |-images
#     |-tmp
#
#Cleanup between invocations is manual

#Kickstart file:
KSCFG=files/ks.cfg
#Generated files:
OEMDRV=images/oemdrv.img

test -e $OEMDRV && { echo $0: ABORT: $OEMDRV exists >&2;exit 1; }
test -e $KSCFG || { echo $0: ABORT: $KSCFG does not exist >&2;exit 1; }

#Build the filesystem image
dd if=/dev/zero of=$OEMDRV bs=1M count=1 || { echo $: ABORT: dd $OEMDRV failed >&2;exit 1; }
mkfs.ext4 -L OEMDRV $OEMDRV || { echo $: ABORT: mkfs.ext4 $OEMDRV failed >&2;exit 1; }
e2cp -O root -G root $KSCFG ${OEMDRV}:/ || { echo $: ABORT: e2cp $KSCFG failed >&2;exit 1; }

Then put the filesystem on a usb flash drive without a partition table.

dd if=images/oemdrv.img of=/dev/sdX bs=1M

Boot the F38 Server iso with the oemdrv also plugged in and away it goes.

The default on the F38 iso is to test the media after a 60 sec timeout before starting the install. For uefi this can be done more quickly by modifying the F38 iso. The media test will fail after modification so make sure it is a good iso beforehand (works well using usb flash as media).

#!/bin/bash
set -x

#Modify downloaded install image so it boots more quickly
#
#This breaks being able to integrity test on boot
#Make sure it is a good image to start with
#
# must be run from top
# top-|-bin
#     |-downloads
#     |-files
#     |-images
#     |-tmp
#
#Cleanup between runs is manual

#downloaded image to use
DOWNLOAD=downloads/netinst.iso

test -e $DOWNLOAD || { echo $0: ABORT: $DOWNLOAD does not exist >&2;exit 1; }

#Generated files
INSTIMG=images/instimg.iso
TMPGRUB=tmp/grub.cfg

test -e $INSTIMG && { echo $0: ABORT: $INSTIMG exists >&2;exit 1; }
test -e $TMPGRUB && { echo $0: ABORT: $TMPGRUB exists >&2;exit 1; }

#This is a fragile technique as the makeup of the DOWNLOAD may not stay static
cp $DOWNLOAD $INSTIMG
test -e $INSTIMG || { echo "$0: ABORT: cannot cp $DOWNLOAD $INSTIMG" >&2;exit 1; }
# find the start of the ESP
PTJSON=$(sfdisk -J $INSTIMG)
SECSIZE=$(jq -r '.partitiontable.sectorsize' <<<$PTJSON)
ESPSTART=$(jq -r '.partitiontable.partitions[] | select(.type == "C12A7328-F81F-11D2-BA4B-00A0C93EC93B") | .start' <<<$PTJSON)
ESPOFFSET=$(($ESPSTART * $SECSIZE))
mcopy -i $INSTIMG@@$ESPOFFSET ::/EFI/BOOT/grub.cfg $TMPGRUB || { echo $0: ABORT: cannot mcopy grub.cfg >&2;exit 1; }
sed -i 's/set default="1"/set default="0"/' $TMPGRUB
sed -i 's/set timeout=60/set timeout=0/' $TMPGRUB
mcopy -i $INSTIMG@@$ESPOFFSET -o $TMPGRUB ::/EFI/BOOT/grub.cfg || { echo $0: ABORT: cannot mcopy $INSTIMG >&2;exit 1; }

Write the modified iso to usb flash device

dd if=images/instimg.iso of=/dev/sdX bs=1M

When testing on a vm I usually use the Server dvd without any internet access. But the kickstarted system will need to be updated and the dvd is a limited set of packages.