Piero V.

Debian on an encrypted microSD on a Surface Pro 2017

Wow, I have not needed to write a guide about installing a Linux system for years (well, these are my notes rather than a complete guide).

Partly because I found it quite easy in the latest… 5 years? Partly because I avoid reinstalling my systems unless strictly needed.

This time is different: I am targeting a peculiar device (a Surface Pro 2017) with a microSD (I am too lazy to repartition its SSD) and full disk encryption (including /boot).

But I am happy because I have learned a lot! For example, if you choose the expert installation for Debian, you can disable the source repositories immediately!

Big caveat: my initial plan was to install GRUB on the microSD, but it did not work. If I understood correctly, the Surface cannot boot from SDs. So, I used the ESP of the SSD. If you wanted a completely autonomous system on a microSD that disappears as soon as you remove it, I fear you cannot get one.

Preparing the install drive

After I discovered Rufus, I have always used it to prepare installation drives on Windows.

But Debian ISOs have a feature I really appreciate: in UEFI mode, you can just extract the image to a FAT32 partition. The advantages are that you do not need Windows, and you do not have to format the drive, you do not lose any existing data. And, on top of that, secure boot worked at the first try (with Microsoft & 3rd party CAs, but I do not remember if it is the default). I have tried with other distributions, but none worked in the same way.

The Surface uses a Marvell wireless card. It works on Linux, but only if you provide its proprietary firmware. You can find it in the firmware-libertas package from the non-free section of Debian. You should add it to the installation drive, if you intend to use the wireless for the installation. I did not, and used my USB Ethernet card, instead.

Preparing the microSD

From what I understood, if you use Debian Bullseye, you need two different LUKS volumes. One for /boot, which needs to be LUKS 1, and one for the rest.

The reason is that LUKS 2 support was introduced only with GRUB 2.06, and the current Debian stable is still on 2.04. I am not completely sure, but I preferred avoiding reinstalling everything because of a similar error. Also, the Debian installer does not let you choose between LUKS1 and LUKS2 from a shallow test.

In my opinion, you do not need to choose two different passphrases because each partition will contain the data to open the other one. You could even use only keys for the second volume. But having a passphrase, too, is helpful in many cases, such as when you are in the recovery environment. Also, the passphrase is a good backup access plan: deleting the only existing copy of the keyfile is too easy.

You can partition the card from the Debian installer, but you will need to load either fdisk or parted, which I find less comfortable than a GUI 😁️.

For this reason, and to be quicker, I used Gparted on my Linux PC to create the GPT partition table and the partitions on the format I preferred. You will need at least two partitions: one small (less than 1GB is enough; notice that I have used a 64GB card, but you can use a smaller one) for the boot volume and one for the rest of the system. You can leave unformatted the two partitions to encrypt, as you just need to create them. In any case, we will format them with cryptsetup.

I also added an EFI system partition because I discovered it is not supported too late.

Loading the Debian installer

To perform this installation you will need to start an expert install, from the advanced menu.

Then you will need to load some additional modules by choosing Load installer components from CD. You will need at least crypto-dm-modules, but there are a lot of other useful packages there.

This is not enough! You will also need the cryptsetup program, but it cannot be installed with that menu. So, open a shell (or go to the tty2 with Ctrl-Alt-F2) and run anna-install cryptsetup-udeb.

We will also create the encrypted volumes from the same shell:

# Choose your correct devices! And double, triple check you choose the correct ones!
cryptsetup luksFormat --type=luks1 $DEV_BOOT
cryptsetup luksFormat $DEV_ROOT

Then, we will need to open the devices, and format them. Formatting them is optional, but I preferred doing so to avoid the installer complaining about the missing partition table.

cryptsetup luksOpen $DEV_BOOT surface-boot
cryptsetup luksOpen $DEV_ROOT surface-os
mkfs.ext4 /dev/mapper/surface-boot
mkfs.ext4 /dev/mapper/surface-os

After that, you can go back to the installation and proceed as usual. At the moment of the disk partitioning, the UI will include the encrypted volumes as they were regular drives/partitions.

When you choose them, remember to enable noatime and nodiratime, to avoid writing just because you access a file. If your SD supports trimming, you can also select discard.

Here, I also told the installer not to use the EFI partition of my USB drive. Using the SSD ESP is compulsory, sadly, but did not have any side/negative effect.

Make the installation bootable

The bootloader installation is the other step you need to pay attention to. And managing encryption manually makes everything more difficult.

Since we encrypted /boot, we need to enter its passphrase on GRUB. However, also Linux needs to unlock the partitions, and GRUB cannot relay the passphrase to it. Therefore, you usually add a keyfile to the second slot of LUKS, and you include this file in the initramfs.

From an installer shell (such as the tty2 again), run these commands before switching to the installation of the bootloader:

dd bs=512 count=4 if=/dev/random of=/target/etc/keyfile iflag=fullblock
chmod 400 /target/etc/keyfile
chown root:root /target/etc/keyfile
# Again, adjust to your devices
cryptsetup luksAddKey $DEV_BOOT /target/etc/keyfile
cryptsetup luksAddKey $DEV_ROOT /target/etc/keyfile

Then you need to tell your new OS where it can find the keyfile by adding the following lines to /target/etc/crypttab:

surface-boot UUID=uuid-of-the-luks1-partition /etc/keyfile luks,discard
surface-os   UUID=uuid-of-the-luks2-partition /etc/keyfile luks,discard

And you need to copy this keyfile to the initramfs: open /target/etc/cryptsetup-initramfs/conf-hook and set KEYFILE_PATTERN=/etc/keyfile. I initially missed this step, so I had to do it from the recovery environment. This file is added by cryptsetup-initramfs: if it does not exist, you need to chroot to /target and install this package manually with apt.

As a result, the initramfs should be readable only by root: open /target/etc/initramfs-tools/initramfs.conf and set UMASK=0077 (I had to add that entry).

Then you can select the step to install the bootloader. In my case, the installer detected that I was installing in a removable device and asked if I wanted to add a fallback copy of GRUB for non-UEFI-compliant BIOSes.

This was very fortunate because before dismissing that dialog, I went to tty2 once again and add GRUB_ENABLE_CRYPTODISK=y to /target/etc/default/grub. This is essential because the installation of GRUB will fail otherwise.

If you do not get the prompt, your GRUB installation will fail. But I think that you could set that flag after the failure and then try the installation again. You cannot modify the configuration file before because the GRUB package is not available yet. The prompt is shown after the package installation but before running the actual GRUB installation to your EFI partition.

I still had some troubles to boot, and had to go to the recovery a couple of times. But I have tried to understand what I did wrong and written correct notes. So, everything should go very smoothly for you.

Post-install

Debian Bullseye distributes Linux 5.10, which does not support several peripherals of the Surface. You cannot even see the battery status without Linux 5.12+.

So, the first step is adding the linux-surface repository. Please follow the official guide: it is very precise and detailed. Also, it tells how to make this kernel work with secure boot.

Only the custom kernel supports a non-trivial component: the touch screen! However, the results vary on an application basis. For example, you should set MOZ_USE_XINPUT2=1 before launching Firefox, or the touchscreen will select the text instead of scrolling the page.

The rest works with Debian’s standard Linux image, too. As stated earlier, you will need firmware-libertas for the WiFi card. However, I could not connect to my network with WPA 3, and I had to downgrade to WPA 2 (with both kernels).

The touchpad has some strange settings on Mate, but they can be easily adjusted. Double and triple-finger taps are detected, and so is the double-finger scrolling. You will likely be used to natural scrolling on Windows: in many DEs, it needs to be enabled explicitly.

The Surface screen has 267 DPI, but Mate detects it and automatically scales everything. Lightdm does not, but since it is only the login screen, I did not fix it. GRUB is also very small, but you should be able to customize the font to a bigger one.

Speaking of GRUB, I have noticed that unlocking the filesystem takes a long, long time. I found that GRUB’s implementation of LUKS is not great, and you will need to reduce the iteration count of the key hashing if you want to solve this problem. But a higher number of iterations should be more secure. In practice: 1. do not choose an easy passphrase, and 2. these are crypto nerds talking.

Also, regarding encryption, my Windows partition was detected as encrypted, even though I have never set up BitLocker. So, I cannot open it from Linux, which is an inconvenience because sharing files between the two is useful from time to time.

I have not tested Bluetooth, but it is a technology I try to avoid, so I think I do not even have bluez installed.

The audio works, both on speakers and on headphones. I have not tried the microphone.

The webcams are the only hardware I could not get working. But it was expected, because their support is a work in progress, and I did not try very hard.

The sensors should be supported, but the accelerometer did not cause the display to rotate, on Mate. This is unfortunate, because I really appreciate this feature when I use the Surface to read. Maybe it works as expected on GNOME.

Last but not least, I have decided to follow some tricks to reduce the stress on the SD, such as mounting /tmp on RAM.

It was a long journey, but we arrived at our destination. Hopefully, it has been worth it.

References