Modifying the Fedora42 ISO for a automated (kickstart) deployment
Overview
While there are plenty of articles online detailing how to do this with older releases (40 and older), there is sparse information about the automated ISO creation process for fedora 42.
There were 2 particular problems that I found especially annoying:
- If you want to use UEFI, you need to extract the efi image from the original iso and make amendments to it so the bootloader can find your kickstart file
- Unfortunately the above also means we will have to modify our xorriso command accordingly to work with the extracted efiboot.img rather than eltorito.img which is mainly used for optical drives
Prerequisites
What you need to tag along:
- A Fedora 42 iso
- xorriso utility
- A basic idea of what you whant to put in your kickstart file
- Some patience as this is a finicky process
- Extract the exact boot information from the official fedora iso:
xorriso -indev path_to_fedora42.iso -report_el_torito as_mkisofs 2>/dev/null | grep -E "^-"(we will build our xorriso command around this)
Write the kickstart file
The kickstart file should look similar to the example below, however it can be much more simple or complex, depending on the needs.
Needsless to say, you will need to replace the USERNAME, ENCRYPTED_PASSWORD and the sda values below to comply with your actual setup. To generate a secure hashed password: mkpasswd -m sha-512.
#version=DEVEL
## Locale settings
keyboard --vckeymap=gb --xlayouts='gb' # Keyboard layouts
lang en_GB.UTF-8 # System language
timezone Europe/Berlin --utc # System timezone
## Installer settings
text # Install in text mode
firstboot --enable # Run the Setup Agent on first boot
reboot --eject
## Disk configuration
ignoredisk --only-use=sda # Ignore all other disks - AMEND THIS ACCORDINGLY, sda IS USUALLY THE FIRST DISK
clearpart --all --initlabel # Partition clearing information
autopart --type=lvm --encrypted --luks-version=luks2 # Auto configure the whole disk, use LVM and luks
## User config
user --groups=wheel --name=USERNAME --password=ENCRYPTED_PASS --iscrypted --gecos="USERNAME"
rootpw --lock # Lock the root account
## Packages to install
%packages
@^cinnamon-desktop-environment
@c-development
@container-management
@desktop-accessibility
@headless-management
@sound-and-video
@virtualization
aide
btop
dnf-automatic
%end
## Post install config
%post --log=/root/ks-post.log --erroronfail
# Install any security updates available now
yum -y update --security
# Set the default target for boot
systemctl set-default graphical.target
# Automatic security updates
echo -e "[commands]\napply_updates=True\nupgrade_type=security" > /etc/dnf/automatic.conf
systemctl enable dnf-automatic.timer
# Disable kernel crash dump collection for better memory
systemctl disable kdump.service
systemctl mask kdump.service
# Disable sssd if no remote logins
systemctl disable sssd
# Password requirements
echo "minlen = 10" >> /etc/security/pwquality.conf
echo "minclass = 4" >> /etc/security/pwquality.conf
# Set a lockout timeout for failed login attempts
echo -e "deny = 7\nunlock_time = 1800\neven_deny_root\nroot_unlock_time = 1800\naudit\nsilent" >> /etc/security/faillock.conf
# Prevent chrony from acting as a remote server
echo -e "port 0\ncmdport 0" >> /etc/chrony.conf
# Harden sudo
echo -e "Defaults use_pty\nDefaults timestamp_timeout=30" > /etc/sudoers.d/custom
# Enforce stronger ssh algorithms
echo -e "KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256\nMACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256" >> /etc/ssh/sshd_config
# Enforce a more secure umask
sed -i 's/umask 022/umask 027/g' /etc/bashrc
sed -i 's/UMASK 022/UMASK 027/g' /etc/login.defs
sed -i 's/002/027/g' /etc/profile.d/ccache.sh
sed -i 's/002/027/g' /etc/profile.d/ccache.csh
# Prevent logins with empty passwords
sed -i 's/ nullok//g' /etc/authselect/system-auth
sed -i 's/ nullok//g' /etc/authselect/password-auth
# Set the default firewall policy
sed -i 's/DefaultZone=public/DefaultZone=drop/g' /etc/firewalld/firewalld.conf
# Show system logs/output when booting the system up
sed -i 's/ rhgb quiet//g' /etc/default/grub
grub2-mkconfig -o /boot/grub2/grub.cfg
dracut --regenerate-all --force
# Set permissions for user init files
find /home/USERNAME -maxdepth 1 -type f -name '.*' -exec chmod u-s,g-wxs,o= {} \;
find /root -maxdepth 1 -type f -name '.*' -exec chmod u-s,g-wxs,o= {} \;
# Initialise the AIDE DB
aide --init
%end
Mount the ISO and prepare the partitions
In order to mount the fedora iso and creaete our new target we use the below commands:
Mount the iso as a loop device:
# mount -o loop Fedora-Everything-netinst-x86_64-42-1.1.iso /mnt/iso/
Copy it’s contents to the new target:
# rsync -av /mnt/iso/ /mnt/modified_iso/
Firstly we create the esp partition. This has to be extracted from the original iso as such:
# dd if=Fedora-Everything-netinst-x86_64-42-1.1.iso \
of=/tmp/efi_partition.img \
bs=512 \
skip=1840632 \
count=25808
The above block sectors are specified for the exact iso you see listed above, if you are using a different iso:
- Write it to a disk (using dd or cat)
- Use the
fdisk -l /dev/sdXcommand to identify the block sectors beginning and end for each partition
Mount the extracted esp partition, modify the grub.cfg and copy it to the new target:
# mkdir -p /tmp/efi_image
# mount -o loop /tmp/efi_partition.img /tmp/efi_image
# sed -i 's/quiet$/fips=1 inst.ks=hd:LABEL=Fedora-E-dvd-x86_64-42:\/ks.cfg/g' /tmp/efi_image/EFI/BOOT/grub.cfg
# cp /tmp/efi_partition.img /mnt/modified_iso/images/efiboot.img
Finally copy your kickstart file to the new target:
# cp ks.cfg /mnt/modified_iso/
# chmod 0640 /mnt/modified_iso/ks.cfg
Generate the ISO and write to media
Now comes the exciting part (and the one that is most likely to fail) - we get to generate our custom iso.
If you comapre the below command with the output of the xorriso -indev .. mentioned earlier, you will see that we have essentially copied the boot options that existed in the actual Fedora iso.
To generate the iso:
# xorriso -as mkisofs \
-V 'Fedora-E-dvd-x86_64-42' \
--grub2-mbr /mnt/modified_iso/boot/grub2/i386-pc/boot_hybrid.img \
--protective-msdos-label \
-partition_cyl_align off \
-partition_offset 16 \
-partition_hd_cyl 64 \
-partition_sec_hd 32 \
-append_partition 2 28732ac11ff8d211ba4b00a0c93ec93b /mnt/modified_iso/images/efiboot.img \
-appended_part_as_gpt \
-iso_mbr_part_type a2a0d0ebe5b9334487c068b6b72699c7 \
--boot-catalog-hide \
-b 'images/eltorito.img' \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
--grub2-boot-info \
-eltorito-alt-boot \
-e images/efiboot.img \
-no-emul-boot \
-o new-fedora-custom.iso \
/mnt/modified_iso
Your newly created custom iso should now exist under the filename of: new-fedora-custom.iso in the current working directory.
Use the dd command to write it to your media. If your USB drive is under /dev/sdc use:
# dd if=new-fedora-custom.iso of=/dev/sdc bs=8M status=progress oflag=direct
The End
Hopefully the above can be of use to others too. Bare in mind the same analogy (using xorriso -indev, modifying bootloader on the esp partition, etc) can be done with pretty much any linux you find your hands on.
If you’ve enjoyed this, make sure to go ahead and look at the Articles section.
My personal projects you can find on my git server.
If you have a question or want to get in touch, feel free to email me.
Thank you for reading and have a good night!