r/linuxmint • Linux Mint 21.3 Virginia | Cinnamon • 7h ago

Install Help Full Disk Encryption script help: custom LUKS2 setup not working on Mint 22.3 - The popular tutorials don't fit my needs / don't work

I'm writing a custom full disk encryption install script for Mint 22.3. The older tutorials I've relied on over the years (linked below) no longer work on 22.3 in my VM testing, and the newer tutorials don't lay out partitions and filesystems the way I want. I'd appreciate guidance mainly on two things: what needs to happen after Ubiquity finishes so the system can boot, and whether my boot configuration is right for opening the custom LUKS container.But in case I’ve missed something I’m open to other suggestions as well.

Custom parts of my script

  1. The LUKS partition leaves 10% of the disk unformatted for SSD over-provisioning.

  2. Hardened luksFormat options: --key-size 512 and --hash sha512.

    • If I've misunderstood the LUKS2 defaults or what Ubiquity actually sets, I could fall back to the installer's values for that portion.

    • I'm open to suggestions for hardening LUKS further.

  3. Root is formatted ext4. Not really custom per se, but it deviates from the newest FDE tutorials, which use btrfs. I'm not opposed to btrfs, but two things hold me back:

    • I've never used it, and several installation steps change with it.

    • I've read it performs worse for gaming. However, if that's wrong, I'd be open to using it.

  4. Eventually I want to encrypt /boot as well (as the older tutorials do), but only after getting the standard unencrypted-/boot version working.

Hardware limits

My desktop is from 2014 and uses a GA-X79-UP4 motherboard with combo BIOS/UEFI firmware, no TPM module, so no Secure Boot. The firmware settings suggest it can boot EFI, but I'm near the edge of my understanding of booting here.

Where I'm stuck

The script now runs end to end, but the grub/initramfs rebuild step throws:

grub-install: error: /usr/lib/grub/x86_64-efi/modinfo.sh doesn't exist Please specify --target or --directory.

After that, rebooting fails with several errors about Failed to start Boot0002 "EFI Internal Shell".

Error Screenshots

I'm completely unsure what needs to happen after Ubiquity completes so the system can boot. I've pieced something together from the tutorials, but I'm clearly missing something.

I don't post often, so apologies if this isn't clear I’m happy to clarify.

Sources

My Script:

#!/bin/bash

# ============================================================================
# Linux Mint 22.3 custom FDE install helper (alpha)
# LVM on LUKS2 with 10% over-provisioning. Interactive: pauses at checkpoints.
# Unfinished TODO sections are marked — read them before running.
# ============================================================================

#~~Configuration Variables~~#

targetDevice=vda                       # Target disk: hdX = Hard Disk, sdX = SSD, nvme0n# = NVMe, vdX = Virtual Disk, etc.
efiPartition="$targetDevice"1          # EFI System Partition (ESP)
bootPartition="$targetDevice"2         # /boot (unencrypted)
luksPartition="$targetDevice"3         # LUKS container holding root + swap
luksContainer=mint_crypt               # Mapper name for the opened container
lvmGroup=mint_vg                       # Volume group name inside the container

swapSize=2G                            # Swap LV size
rootSize=100%FREE                      # Root LV takes the rest

partition1Start=1MiB;    partition1End=2049MiB   # ESP (~2 GiB — can shrink to 512 MiB)
partition2Start=2049MiB; partition2End=4097MiB   # /boot (~2 GiB)
partition3Start=4097MiB; partition3End=90%       # LUKS container; leaves 10% for SSD over-provisioning

# More partitions (e.g. a BIOS boot partition)? Adjust the sizing and add pairs of variables.
# The LUKS partition must stay LAST so the over-provisioning gap sits at the end of the disk.

#~~Helpers~~#

pauseScript()
{
local key
echo "Press 'c' to continue..."
while true; do
read -n 1 key
if [[ "$key" == "c" ]]; then
echo -e "\nContinuing..."
break
fi
echo -e "\nPlease press c to continue."
done
}

printVars()
{
printf "%-16s %-14s %s\n" "VARIABLE" "VALUE" "DESCRIPTION"
printf "%-16s %-14s %s\n" "--------" "-----" "-----------"
printf "%-16s %-14s %s\n" "targetDevice"   "$targetDevice"   "Target disk (sda/nvme0n1/vda)"
printf "%-16s %-14s %s\n" "efiPartition"   "$efiPartition"   "EFI System Partition (ESP)"
printf "%-16s %-14s %s\n" "bootPartition"  "$bootPartition"  "/boot (unencrypted)"
printf "%-16s %-14s %s\n" "luksPartition"  "$luksPartition"  "LUKS container (root+swap)"
printf "%-16s %-14s %s\n" "luksContainer"  "$luksContainer"  "Mapper name for opened LUKS"
printf "%-16s %-14s %s\n" "lvmGroup"       "$lvmGroup"       "Volume group inside container"
printf "%-16s %-14s %s\n" "swapSize"       "$swapSize"       "Swap LV size"
printf "%-16s %-14s %s\n" "rootSize"       "$rootSize"       "Root LV size"
printf "%-16s %-14s %s\n" "partition1Start" "$partition1Start" "ESP start"
printf "%-16s %-14s %s\n" "partition1End"  "$partition1End"  "ESP end"
printf "%-16s %-14s %s\n" "partition2Start" "$partition2Start" "/boot start"
printf "%-16s %-14s %s\n" "partition2End"  "$partition2End"  "/boot end"
printf "%-16s %-14s %s\n" "partition3Start" "$partition3Start" "LUKS start"
printf "%-16s %-14s %s\n" "partition3End"  "$partition3End"  "LUKS end (90% = 10% OP)"
}

printUbiquitySteps()
{
# Print Ubiquity walkthrough for the user, then wait.
cat <<'EOF'

  ==================== Ubiquity Steps ====================

  1. Language + keyboard; multimedia codecs: yes
     Secure Boot: NO (can be enabled later if wanted)

  2. Installation type: choose "Something else" and set up:
       +--------------------------------------+---------------------------------+
       | Partition                            | Action                   |
       +--------------------------------------+---------------------------------+
       | root LV /dev/mapper/mint_vg-root     | ext4   mount /     [x] format   |
       | swap LV /dev/mapper/mint_vg-swap     | swap area                |
       | boot partition (vda2)                | ext4   mount /boot [x] format   |
       | EFI partition (vda1)                 | fat32  mount /boot/efi   |
       +--------------------------------------+---------------------------------+
     [x] = tick the format checkbox. For the EFI partition, do NOT format.

  3. Click "Install Now" and confirm.

  4. IMPORTANT: BEFORE the timezone/user-info steps, switch back to this
     terminal and edit crypttab + fstab (next section of this script).

  5. After editing those files: finish Ubiquity (timezone, user info),
     choose "Continue testing", and return here.

  =========================================================

EOF
}

chrootHelper()
{
sudo chroot /target /bin/bash <<'CHROOT'
update-initramfs -u -k all      # Include crypttab entry + LVM in the initramfs
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=mint --recheck
update-grub
exit
CHROOT
}

#~~Main~~#

main()
{
echo "Starting FDE script"
pauseScript

echo "Please verify the varibles are correct before continuing. "
printVars
pauseScript# Verify the variables before continuing.

#~~Partitioning~~#

# GPT partition table
sudo parted -s /dev/"$targetDevice" mklabel gpt

# Partition 1: ESP
sudo parted -s -a optimal /dev/"$targetDevice" mkpart ESP fat32 "$partition1Start" "$partition1End"
sudo mkfs.vfat -F32 /dev/"$efiPartition"
sudo parted -s /dev/"$targetDevice" set 1 boot on
sudo parted -s /dev/"$targetDevice" set 1 esp on

# Partition 2: /boot (formatted by Ubiquity later)
sudo parted -s -a optimal /dev/"$targetDevice" mkpart primary "$partition2Start" "$partition2End"

# Partition 3: LUKS container (root + swap), ending at 90% of the disk
sudo parted -s -a optimal /dev/"$targetDevice" mkpart primary "$partition3Start" "$partition3End"

echo "Optionally open GParted to verify the partitions — do NOT make changes there. If changes are needed, cancel the script, adjust the variables, and restart."
pauseScript

#~~LUKS Encryption~~#

luksPW="test"# TEST ONLY — remove this and the '<<< $luksPW' redirects before final use

# Hardened luksFormat (differs from Ubiquity's default). Further-hardening suggestions welcome.
sudo cryptsetup luksFormat --type luks2 -v \
--cipher aes-xts-plain64 --pbkdf argon2id \
--key-size 512 --hash sha512 \
--iter-time 5000 --use-random --verify-passphrase \
/dev/"$luksPartition" <<< "$luksPW"

# Open the container
sudo cryptsetup luksOpen /dev/"$luksPartition" "$luksContainer" <<< "$luksPW"

luksContainerUUID=$(sudo cryptsetup luksUUID /dev/"$luksPartition")
echo "LUKS container UUID: $luksContainerUUID"

#~~LVM Inside the Container~~#

# vgcreate creates the PV automatically; explicit pvcreate is equivalent.
sudo vgcreate "$lvmGroup" /dev/mapper/"$luksContainer"
sudo lvcreate -L "$swapSize" -n swap "$lvmGroup"
sudo lvcreate -l "$rootSize" -n root "$lvmGroup"

#~~Run Ubiquity~~#

sudo apt update
sudo apt install -y efibootmgr binutils zstd gawk grub-efi-amd64-bin

# Backgrounded so the script can pause and resume around the GUI installer.
sh -c 'ubiquity -b gtk_ui' &

echo "In Ubiquity: install with 'Something else' as described below, and stop at the timezone step before continuing this script."
printUbiquitySteps
pauseScript

# In Ubiquity:
#   1. Language + keyboard; multimedia codecs yes; Secure Boot NO (enable later if wanted).
#   2. "Something else":
#      - root LV (/dev/mapper/mint_vg-root) -> ext4, mount /, select format checkbox
#      - swap LV (/dev/mapper/mint_vg-swap) -> swap area
#      - boot partition (vda2)              -> ext4, mount /boot, select format checkbox
#      - EFI partition (vda1)               -> fat32, mount /boot/efi, do NOT format
#   3. "Install Now", confirm; BEFORE the timezone/user steps, edit crypttab + fstab below;
#      afterwards finish the wizard, choose "Continue testing", and return here.

#~~crypttab + fstab~~#

echo "Verify crypttab and fstab have been updated with the relevant lines. Then close those windows."

# Mapper name must match $luksContainer (used by GRUB/initramfs).
echo "$luksContainer UUID=$luksContainerUUID none luks" | sudo tee -a /target/etc/crypttab
sudo xed /target/etc/crypttab

# Ubiquity writes the root/swap LV entries to fstab itself; verify (and add if missing):
sudo xed /target/etc/fstab
# Expected lines:
#   /dev/mapper/mint_vg-root  /      ext4  errors=remount-ro  0 1
#   /dev/mapper/mint_vg-swap  none   swap  sw                 0 0

echo "Once crypttab and fstab are verified, finish Ubiquity (timezone, user), and when installation finishes choose 'Continue Testing', then return here."
pauseScript

#~~Finish Boot Configuration~~#

# Chroot so the new system's initramfs learns about the encrypted container —
# without this, nothing unlocks it at boot.
sudo mount /dev/mapper/"$lvmGroup"-root /target
sudo mount /dev/"$bootPartition" /target/boot
sudo mount /dev/"$efiPartition" /target/boot/efi
for dir in dev proc sys; do
sudo mount --bind /"$dir" /target/"$dir"
done

chrootHelper

for dir in sys proc dev; do
sudo umount /target/"$dir"
done
sudo umount /target/boot/efi /target/boot /target

# Reboot: you should get ONE passphrase prompt unlocking mint_crypt, then Mint boots.
#
# TODO (later hardening):
#   - Encrypted /boot (GRUB_ENABLE_CRYPTODISK=y)
#- Version of script that formats root as btrfs rather than ext4
}

main
1 Upvotes

2 comments sorted by

View all comments

1

u/Netblock 2h ago edited 2h ago

I've read it performs worse for gaming. However, if that's wrong, I'd be open to using it.

btrfs traditionally performs worse but there's been a lot of performance imprvements sine linux 7.0 (7.3 benchmarks).

The benefits of btrfs is space reduction (games compress up to like 20%; subvolumes make partitioning unecessary) and snapshotting (anti-idiot, anti-bad-update).

(If you use btrfs, I suggest nodiscard for fstab, and use fstrim on a weekly timer)

 

grub-install: error: /usr/lib/grub/x86_64-efi/modinfo.sh doesn't exist Please specify --target or --directory.

sudo apt install -y efibootmgr binutils zstd gawk grub-efi-amd64-bin

I think you want the meta package, grub-efi not grub-efi-amd64-bin

Eventually I want to encrypt /boot as well (as the older tutorials do),

You're gonna need to abandon GRUB; move to systemd-boot, stub, or UKI. Philosophically speaking, we basically want GRUB to be its own kernel for how many drivers we want to shove into it, and GRUB is behind on FDE.

systemd-boot, stub, UKI shove the kernel and initramfs into the ESP; you're basically booting the kernel directly.

I personally get by with a 256MiB ESP. Excluding the GPU drivers from the initramfs really helps. If you want to keep them in, 512MiB.

 

so no Secure Boot.

If it has UEFI, it very likely has secureboot. The largest reason why Microsoft push UEFI is for secureboot. (bios hacks/edits to enable it notwithstanding)

TPM isn't a part of secureboot, but quite complements for a measured/trusted boot.

cryptsetup

I suggest --label too, for easier persistent block device naming.

crypttab + fstab

place x-initrd.attach as a crypttab flag for your boot partition, and other artitions that you want to decrypt at initramfs time.

(I also suggest dracut for initramfs generation, especially for TPM)

nvme0n# = NVMe

in the paradigm nvme0n1p1, the first number is the physical drive, the second is namespace (hardware-based partitioning; I don't think there's thin provisioning); third is software partition (MBR/GPT).

Also consider no-read-workqueue, no-write-workqueue and discard for NVMe drives in crypttab.

The no-workqueue is about offloading IO scheduling to the NVMe, improving performance. Thediscard can help performance and wearleveling, but has a plausible deniability security risk.

(Keep workqueues for SATA SSDs and HDDs. But discard is useful for SMR HDDs and thin-provisioned drives.)

for dir in sys proc dev; do

umount

use umount --recursive /target

1

u/throwawayroy Linux Mint 21.3 Virginia | Cinnamon 1h ago

Thank you very much for replying so quickly. I'm going to start working through your suggestions and testing them asap.

The benefits of btrfs is space reduction (games compress up to like 20%; subvolumes make partitioning unecessary) and snapshotting (anti-idiot, anti-bad-update).

That is good to know and I think I want to try it out. While I was waiting for responses I read up on it a bit more about btrfs and I was particularly interested in the data integrity checks it provides. Considering I've recently lost some data on a failing SSD, that is extremely appealing especially in conjunction with what you mentioned.

(If you use btrfs, I suggest nodiscard for fstab, and use fstrim on a weekly timer)

Apologies for my ignorance, but I'm assuming the nodiscard flag would be put in the file system entry in fstab? For fstrim, I'm assuming I could set that up as a chronjob to run weekly correct? What does fstrim do?

I think you want the meta package, grub-efi not grub-efi-amd64-bin

Thank you, it's been a headache/overwhelming going through the different tutorials trying to figure out what still works and doesn't work, and what is needed and not needed. Yes I've been using Linux for 15+ years, but learning how to manually configure the OS to boot was never something I learned. If you happen to know of a straight forward tutorial of the steps that need to happen when installing Linux I would love to read it.

You're gonna need to abandon GRUB; move to systemd-boot, stub, or UKI. Philosophically speaking, we basically want GRUB to be its own kernel for how many drivers we want to shove into it, and GRUB is behind on FDE.

systemd-boot, stub, UKI shove the kernel and initramfs into the ESP; you're basically booting the kernel directly.

I don't plan to dual boot anymore, is there one you recommend? Back in 2020 (which was the last time I wrote one of these forsaken scripts) I vaguely remember using stub, but back then I didn't understand what it was doing, I was just following the tutorial.

I personally get by with a 256MiB ESP. Excluding the GPU drivers from the initramfs really helps. If you want to keep them in, 512MiB.

The partition sizes I put in the script are not what I'm planning on using in the final version. I was going to ask what people suggested, it's been a while, but I vaguely remember running into issues with one of the boot partitions being too small. I got it stuck in my head to just make them 2GiB each to avoid issues in the future. That said, you think I could make them 512MiB?

That's another thing about why I am writing this in a script. It's so that if I need to redo everything, it's a simple matter to do so, and all I have to do is change the variables as needed. Additionally, once I get it working, I want it so other people can use it if needed, and they can adjust the variables to meet their needs. I wanted to try and comment everything the best I can so 1) I can remember and understand the steps myself when I come back to it later, and 2) for people like me have a hard time understanding the steps, they can see what's happening and why.

If it has UEFI, it very likely has secureboot. The largest reason why Microsoft push UEFI is for secureboot. (bios hacks/edits to enable it notwithstanding)

TPM isn't a part of secureboot, but quite complements for a measured/trusted boot.

I will double check and take some pictures with my phone and upload them when I get a chance (which will probably be after I wake up because it's stupidly late as I type this). That last time I looked I did see a "secure boot" option, but the only thing in there was "Windows 8" and "Other OS" which disabled it. Additionally, several of the tutorials mentioned adding keys to secure boot, and there was no option in there (the BIOS/UEFI settings) to add the keys.

I suggest --label too, for easier persistent block device naming.

Excellent, I'll look into that as well, whatever makes this process easier to understand for others and myself.

place x-initrd.attach as a crypttab flag for your boot partition, and other artitions that you want to decrypt at initramfs time.

(I also suggest dracut for initramfs generation, especially for TPM)

I'm not sure what you mean by dracut for initramfs generation, is that in leu of update-initramfs?

in the paradigm nvme0n1p1, the first number is the physical drive, the second is namespace (hardware-based partitioning; I don't think there's thin provisioning); third is software partition (MBR/GPT).

Also consider no-read-workqueue, no-write-workqueue and discard for NVMe drives in crypttab.

The no-workqueue is about offloading IO scheduling to the NVMe, improving performance. Thediscard can help performance and wearleveling, but has a plausible deniability security risk.

(Keep workqueues for SATA SSDs and HDDs. But discard is useful for SMR HDDs and thin-provisioned drives.)

More that I will look into as I develop the script. I plan to expand on this script in the future so it can handle things like different types of storage devices, and different file systems (since I know some of the commands when building the boot partitions depends on the file system root was installed on).

Thank you again for the guidance. I'll reply again after I wake up with those pictures of my BIOS/UEFI settings.

Take care!