How to install encrypted Debian on an M1 MacBook Pro
Table of Contents
In this post I’ll describe how to install an encrypted Debian (13, “Trixie”) on an M1 MacBook Pro (others might work too).
I have tried the Asahi Linux Fedora distribution a while ago and was surprised at how well it worked, the Asahi Contributors did an awesome job! However, I am more familiar with Debian, so I wanted to use that. Disk encryption is also required because the device is a laptop and I’m not sure yet where I might take it tomorrow.
Important
- First of all, ensure that there is enough free space on your macOS partition!
- You will need enough space for your Debian installation (only you know how much you need), and a temporary second installation which will be used to encrypt the main one.
- It’s important to install/create the temporary Debian install after the primary one, so the space used for the temporary installation will able to be reintegrated into the macOS partition.
- To make it easy to differentiate between the primary and temporary installation, I’d suggest using a different GUI in the temporary installation.
- Doing things wrong can brick your device. You need a second Mac in order to reflash the one you modified in case you (for example) accidentally delete the macOS Recovery or something like that!
- Don’t run this on your primary machine unless you have backups and a way to recover (a second Mac)!
Sources
- There is an Article about installing Debian on M1 Hardware in the Debian Wiki which is very helpful for a basic overview of the installer and how it works.
- There is a very helpful post about encrypting an already existing Debian installation on which this post is based, with additional modifications for M1 Macs/Asahi I found while going through it!
- The Asahi Partitioning Cheat Sheet might be helpful as well.
Installation
Let’s start with the installation (all Linux commands are supposed to be run as root, all macOS commands as your primary macOS user unless otherwise noted)!
Installing the primary Debian
In macOS, open the terminal and run curl -L https://bananas.debian.net/install | sh
, follow the instructions the script gives and read everything at least twice before pressing enter.
Initially, the script will only offer to shrink your macOS installation, select that, follow the instructions to set the desired partition sizes (without the temporary second installation for now, only the primary one), and after it is done you will be sent back to the partition overview where the free space will be shown alongside an additional option to install Debian into it. Start the installation, then wait until the script shows the instructions for the next steps.
Read the instructions carefully.
The script will have you reboot into the Startup Options then choose the newly installed Debian installation which will actually launch a macOS recovery where you have to authenticate three times using your macOS credentials (once for accessing the recovery, then once to disable SIP, and then once again along with your username to change the boot policy for the Debian installation), after which the install script will finally boot the new Debian installation. In there you could do some first-time setup tasks now, but I’d do most of that (except maybe updates and keyboard/locale settings) when the encryption is done.
Preparing for the encryption
There are some tasks that need to be done in order ot prepare the installation for the encryption while it is booted:
- Install required packages:
apt install cryptsetup cryptsetup-initramfs
- Add the line
GRUB_ENABLE_CRYPTODISK=y
to/etc/default/grub
- Run
update-initramfs -u -k all && update-grub
to update the initramfs and GRUB
After this is done, shut down the system and wait for the device to be fully off, then press and hold the power button to go into Startup Options, then select the macOS partition to boot back into macOS.
Installing the temporary Debian
If you (like me) selected to use all the available space for the Debian install, you might need to clean up more space by deleting more stuff (maybe clean the bin for once).
Otherwise (if you read the guide and reserved the space beforehand) it’s time to run the installer (curl -L https://bananas.debian.net/install | sh
) again, to shrink the macOS partition once more, the temporary installation doesn’t need much space, I ended up using 30GB because it was available.
After new free space is created, select to install Debian into the free space and give the installation a different name, so you can easily separate the two. Then it’s the same procedure as before, let the script run, then reboot, select the new temporary installation, authenticate in recovery in order to make it bootable, then let it reboot.
This time it will bot the wrong Debian instance, which can be detected by the first time setup not appearing. In that case you have to select the temporary installation once again in Startup Options, after which the first time setup for the temporary installation should appear.
Encrypting the primary Debian
In the temporary Debian, we can now encrypt the primary installation, but first of all it’s time to…
Install dependencies
Make sure the connection to the internet (or your mirror) is working, and install the required packages: apt install cryptsetup
.
Find partitions
After that, run fdisk -l
, and search through the output, we will need three partition paths for later from it (it’s easiest to do that in order):
- The primary Debian installation root partition
- This will probably be the largest “Linux filesystem” partition in the output
- It might have a slightly smaller size than what you set in the installer
- The boot partition of the primary Debian installation
- This will be the smaller “Linux filesystem” partition right before the primary partition
- The EFI partition of the primary Debian installation
- This will be the “EFI System” partition right before or after the boot partition of the primary Debian installation
In my case, p10
was the primary Debian, p8
was the EFI partition and p9
the boot partition, but this might differ if you have customized your partition layout.
Ensure that you picked the right partitions! If you accidentally update the wrong boot partition you will have to erase both Debian installations from macOS and start from the beginning again.
Encrypt the partition
Create a script file (for example ~/encrypt.sh
) and paste the following:
#!/bin/bash
set -euo pipefail
# DISCLAIMER: USE AT YOUR OWN RISK AND MAKE BACKUPS
# Based on instructions from:
# https://blog.williamdes.eu/Infrastructure/tutorials/encrypt-an-existing-debian-system-with-luks/
# Which is in turn based on instructions from:
# https://wiki.archlinux.org/index.php/dm-crypt/Device_encryption#Encrypt_an_existing_unencrypted_filesystem
# Save partition path as variable
DISK="${1:-}"
# Check if path exists
if [ -z "$DISK" ]; then
echo "Usage: $0 /dev/nvmeXnXpX"
exit 1
fi
# Run a filesystem check on the selected partition
e2fsck -f "$DISK"
# Make the filesystem slightly smaller to make space for the LUKS header
BLOCK_SIZE=`dumpe2fs -h $DISK | grep "Block size" | cut -d ':' -f 2 | tr -d ' '`
BLOCK_COUNT=`dumpe2fs -h $DISK | grep "Block count" | cut -d ':' -f 2 | tr -d ' '`
SPACE_TO_FREE=$((1024 * 1024 * 32)) # 16MB should be enough, but add a safety margin
NEW_BLOCK_COUNT=$(($BLOCK_COUNT - $SPACE_TO_FREE / $BLOCK_SIZE))
resize2fs -p "$DISK" "$NEW_BLOCK_COUNT"
# Run the encryption process
# MAN: https://man7.org/linux/man-pages/man8/cryptsetup-reencrypt.8.html
cryptsetup reencrypt --encrypt --reduce-device-size 16M "$DISK"
# Resize the filesystem to fill up the remaining space (i.e. remove the safety margin from earlier)
cryptsetup open "$DISK" recrypt
resize2fs /dev/mapper/recrypt
cryptsetup close recrypt
echo "Done!"
Then save and close the file. This script will first make the primary partition a bit smaller to fit the LUKS header, then encrypt the partition (and prompt you to enter YES
and the password you want to use to decrypt the partition), and after that prompt for the same password again in order to open the encrypted partition to resize it to its original (or almost original) size.
After the file is created, make it executable by running chmod +x ~/encrypt.sh
, and then run it:
~/encrypt.sh
After everything is done, and Done!
was logged to the terminal, the partition is encrypted, but there is still some work to do.
GRUB Compatibility
Unfortunately, GRUB doesn’t support the argon2id
key derivation function (source 1, source 2) that cryptsetup uses by default, so the key has to be changed to PBKDF2 (replace <PARTITION_PATH>
with the path of the primary (now encrypted) partition):
cryptsetup luksConvertKey --pbkdf pbkdf2 <PARTITION_PATH>
After that, it is a good idea to check if everything still works:
cryptsetup --verbose open --test-passphrase <PARTITION_PATH>
Making it bootable
The final step is to update the configuration files of the primary Debian installation so that it can successfully boot with the now very different setup.
Chrooting into the primary install
To do that we will mount the primary Debian installation into the currently running temporary one, and use the chroot
tool in order to change some things before we can boot.
As I did in my post about remotely setting up an encrypted Debian server, I will use cryptroot
as the encrypted root partition id, you might want to change it if your preferences differ.
Replace <ROOT_PARTITION_PATH>
with the path of the (encrypted) primary partition, <BOOT_PARTITION_PATH>
with the path to the boot “Linux filesystem” partition of the primary installation, and <EFI_PARTITION_PATH>
with the path to the EFI system partition of the primary installation.
- Unlock the encrypted partition:
cryptsetup luksOpen <ROOT_PARTITION_PATH> cryptroot
- Mount the unlocked partition:
mount /dev/mapper/cryptroot /mnt
- Mount the boot partition:
mount <BOOT_PARTITION_PATH> /mnt/boot
- Mount the efi partition:
mount <EFI_PARTITION_PATH> /mnt/boot/efi
- Mount some required things from the running temporary Debian:
mount --bind /dev /mnt/dev
mount --bind /sys /mnt/sys
mount --bind /proc /mnt/proc
mkdir -p /mnt/run/udev
mount --bind /run/udev /mnt/run/udev
- Chroot into the primary installation:
LANG=C.UTF-8 chroot /mnt /bin/bash
It might appear that nothing has changed with the last command, but if there was no error, and you see a root prompt, you’ve successfully changed into the primary installation.
Configuring the primary system
Next, run blkid -o value -s UUID <ROOT_PARTITION_PATH>
and copy/remember/write down the UUID (we will refer to this as <ROOT_PARTITION_UUID>
).
- Edit
/etc/crypttab
and add the following line:cryptroot UUID=<ROOT_PARTITION_UUID> none luks
- Edit
/etc/fstab
and change the line for the root device so that it uses/dev/mapper/cryptroot
as device instead of what it currently uses (in my case a UUID). - Edit
/etc/default/grub
and add the following into theGRUB_CMDLINE_LINUX=""
variable content:cryptdevice=UUID=<ROOT_PARTITION_UUID>:cryptroot root=/dev/mapper/cryptroot
- Update the initramfs and GRUB:
update-initramfs -u -k all && update-grub
It is at this point where the error I talked about earlier can happen, where you accidentally identified the boot and efi partitions of the temporary system and mounted them into the primary system, the primary system won’t be able to boot because it can’t handle decryption, and the temporary system won’t boot anymore wither since it then tries to but can’t find any encrypted drive!
Finishing up
Now it’s time to exit
the chroot, and then unmount all the disks and reboot using:
umount /mnt/boot/efi /mnt/boot /mnt/proc /mnt/sys /mnt/dev /mnt/run/udev # sometimes I need to run this twice
umount /mnt # If this says "target is busy", run the previous umount again
sync
shutdown -h now
It’s important to use shutdown -h now
because we don’t want to reboot the temporary installation, we want to turn the device off.
Booting the encrypted installation
When the device is fully off, press and hold the power button to boot into Startup Options, then select the primary Debian installation. Same as usual, it should boot the Asahi boot stage, then uBoot, followed by GRUB which loads the kernel, then you should get asked to unlock the primary partition, and after that the system should boot just as usual.
Troubleshooting
In case something doesn’t work, you can shut down the system, enter Startup Options to boot from the temporary Debian, then chroot into the primary system in order to double-check your configuration files, maybe it’s just some wrong UUID or value in the files that need to be configured in order for the system to properly find the newly encrypted root partition. If neither the temporary nor the primary installations will boot, it’s best to boot back into macOS, and then deleting the Linux partitions again in order to start from scratch.
Cleaning up
After the encrypted primary installation was confirmed to be working, the temporary installation can be deleted to reclaim the space back for macOS. In order to do that, boot back into macOS, then:
- Open a terminal
- Run
diskutil list
- You will get multiple “synthesized” disks as output, one of which will be the temp installation, and another the macOS installation
- The name of the temp disk (without the path, for example
disk5
) will be<TEMP_DISK_NAME>
in the next step - The name of the macOS disk (without the path, for example
disk0
) will be<MACOS_DISK_NAME>
in the next step
- Run
diskutil apfs deleteContainer <TEMP_DISK_NAME>
to delete the temp installation - Run
diskutil apfs resizeContainer <MACOS_DISK_NAME> 0
to resize the macOS disk to use the free space from the temp installation
The final step is to shut down the machine once again and boot into Startup Options, because right now the (deleted) temp installation is still the primary booting os in EFI. To change this, select the primary Debian installation in Startup Options and hold down the alt key while you select it so it says “Always Use” on the button. This way, next time you reboot the Mac, Debian will boot automatically. If you decide to skip this step the MacBook will run into a bootloop a few times (I think it was three reboots), then it will default to boot macOS (at least it did in my case).
I hope this post was useful. If you have any suggestions or found errors please let me know!