DEV Community

Achyuta Das
Achyuta Das

Posted on

Optional FDE in ubuntu using initrd hooks

🔍 Context:

Ubuntu’s Autoinstall (Subiquity) typically bakes full disk encryption directly into autoinstall.yaml, making it an all-or-nothing setup—either every install uses encryption, or none do. This becomes limiting when you want a single ISO image to support both encrypted and unencrypted installs without user interaction. In this blog, we will show how to use an initrd hook and a simple trigger mechanism to dynamically choose the right config at install time—enabling flexible, environment-aware deployments from a unified base image. Refer the blog post to understand more about how FDE can be done with autoinstall process.

🛠️ How it works:

The idea is to leverage Ubuntu’s initrd hooks to inject a small script that decides which autoinstall.yaml config to use — with or without full disk encryption — at runtime.

Here’s the breakdown:

  • Two Configs Inside the ISO
    • fde/user-data → contains full disk encryption.
    • nofde/user-data → no encryption. Both set of configurations are included in the ISO in a known directory.
  • A tiny empty image file (~350KB) will be created with a custom label "fde" will be used as the trigger. When installing, if this image is attached (eg: via USB, Floppy, cloud-init disk), it will appear in the system as: /dev/disk/by-label/fde
  • Initrd Hook Script A custom initrd hook script run very early in the boot process, just before we move to the installer fs. It will-
    • Check if the /dev/disk/by-label/fde exists.
    • If yes → copies fde/user-data to a target folder.
    • If no → copies nofde/user-data instead.
  • Update the /boot/grub/grub.cfg to pick up the configuration for autoinstall from the target folder.

🧪 Modifications:

I used Ubuntu 24.04 live server image for this. Let's make a copy of the iso content for us to make our modifications

mkdir -p /mnt/iso ~/edit
sudo mount -o loop ubuntu-24.04.2-live-server-amd64.iso /mnt/iso
rsync -a /mnt/iso/ ~/edit
sudo umount /mnt/iso
Enter fullscreen mode Exit fullscreen mode
  • Let's first create a folder in the base iso which will hold both fde and no-fde autoinstall configurations.
cd ~/edit
mkdir -p cidata/{fde,nofde}

cat <<EOF >> cidata/fde/user-data
... Your autoinstall.yaml content with full drive encryption enabled...
EOF
touch cidata/fde/meta-data

cat <<EOF >> cidata/nofde/user-data
... Your autoinstall.yaml content without full drive encryption enabled...
EOF
touch cidata/nofde/meta-data
Enter fullscreen mode Exit fullscreen mode
  • We need to add a hook to the initrd. So let's first extract the existing initrd.
rm -rf ~/edit/initrd-unpacked/
mkdir -p ~/edit/initrd-unpacked
unmkinitramfs ~/edit/casper/initrd ~/edit/initrd-unpacked/
Enter fullscreen mode Exit fullscreen mode
  • Create a file ~/edit/initrd-unpacked/main/scripts/casper-bottom/98mount-cidata with by below content
#!/bin/sh

PREREQ=""

prereqs() {
    echo "$PREREQ"
}

case $1 in
    prereqs)
        prereqs
        exit 0
        ;;
esac

mkdir -p /root/setup

if [ -b /dev/disk/by-label/fde ]; then
    cp -r /root/cdrom/cidata/fde/. /root/setup/
    echo "FDE data copied to /root/setup/" > /dev/console
else
    cp -r /root/cdrom/cidata/nofde/. /root/setup/
    echo "No FDE data found, copied nofde data to /root/setup/" > /dev/console
fi

chown -R root:root /root/setup/

exit 0

Enter fullscreen mode Exit fullscreen mode
  • Provide executable permission to the file and Update the ORDER file located at ~/edit/initrd-unpacked/main/scripts/casper-bottom
# ORDER file before
...
/scripts/casper-bottom/61desktop_canary_tweaks "$@"
[ -e /conf/param.conf ] && . /conf/param.conf
/scripts/casper-bottom/99casperboot "$@"
[ -e /conf/param.conf ] && . /conf/param.conf

# ORDER file after
...
/scripts/casper-bottom/61desktop_canary_tweaks "$@"
[ -e /conf/param.conf ] && . /conf/param.conf
/scripts/casper-bottom/98mount-cidata "$@"
[ -e /conf/param.conf ] && . /conf/param.conf
/scripts/casper-bottom/99casperboot "$@"
[ -e /conf/param.conf ] && . /conf/param.conf
Enter fullscreen mode Exit fullscreen mode
  • Now that the changes are done, let's re-build the initrd
cd ~/edit/initrd-unpacked
cd early
find . -print0 | cpio --null --create --format=newc > /tmp/initrd
cd ../early2
find . -print0 | cpio --null --create --format=newc >> /tmp/initrd
cd ../early3
find . -print0 | cpio --null --create --format=newc >> /tmp/initrd
cd ../main
find . | cpio --create --format=newc | xz --format=lzma >> /tmp/initrd
rm -f ~/edit/casper/initrd
mv /tmp/initrd ~/edit/casper/initrd
Enter fullscreen mode Exit fullscreen mode
  • Update the grub.cfg for the autoinstall to pick up configuration from the /setup path on the filesystem.\
menuentry "Install Ubuntu Server" {
    set gfxpayload=keep
    linux   /casper/vmlinuz quiet autoinstall ds=nocloud\;s=/setup apparmor=0 ---  ---
    initrd  /casper/initrd
}
Enter fullscreen mode Exit fullscreen mode
  • Generate the md5 sums.
cd ~/edit
sudo rm -f md5sum.txt
sudo bash -c "find . -type f   ! -path './isolinux/*'   ! -path './boot/*'   -print0   | xargs -0 md5sum > md5sum.txt"
Enter fullscreen mode Exit fullscreen mode
  • Rebuild the iso.
sudo xorriso -as mkisofs -J -R -r \
      -V Ubuntu-Server \
      -o custom.iso \
      --grub2-mbr <path to your custom xx-Boot-NoEmul.img> \
      -partition_offset 16 \
      --mbr-force-bootable \
      -append_partition 2 <GUID> <path to your custom xx-Boot-NoEmul.img> \
      -appended_part_as_gpt \
      -iso_mbr_part_type <GUID>\
      -c 'boot.catalog' \
      -b 'boot/grub/i386-pc/eltorito.img' \
      -no-emul-boot -boot-load-size 4 -boot-info-table --grub2-boot-info \
      -eltorito-alt-boot \
      -e '--interval:appended_partition_2:::' \
      -no-emul-boot \
      ~/edit/
Enter fullscreen mode Exit fullscreen mode

✅ Conclusion

With this setup, we have made Ubuntu's Autoinstall system a tad bit smarter and more flexible- capable of deciding at runtime whether to apply full disk encryption, all without any user interaction or multiple full ISO images; all we need is to mount an extra empty, labeled image. This approach is a bit better for reproducible, automated deployments.

Top comments (0)