Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save devgioele/e897c341b8d1c18d58b44ffe21d72cf6 to your computer and use it in GitHub Desktop.
Save devgioele/e897c341b8d1c18d58b44ffe21d72cf6 to your computer and use it in GitHub Desktop.
Tutorial for installing a 64-bit Arch Linux ARM system on the Raspberry Pi 4B, with an encrypted root filesystem, and the option to remotely unlock it via a pre-boot SSH daemon.

Arch Linux ARM 64 on Raspberry Pi 4B With Full Disk Encryption And SSH Unlock: 2022 Edition

There are multiple ways to get a full disk encrypted arch linux system on raspberry. In this tutorial, we will install a 64-bit arch linux armv8 system, using dropbear as ssh server for remote pre-boot unlocking of the root filesystem. However, it will still be possible to unlock and use the pi as usual, with a keyboard and monitor. We will also create an unencrypted partition in the installation process, usable as a rescue system.

For different setup options, see the end of the document.

Get The Image and check the signature

wget http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-aarch64-latest.tar.gz.sig
wget http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-aarch64-latest.tar.gz
gpg --verify ArchLinuxARM-rpi-aarch64-latest.tar.gz.sig

Make sure to verify the GPG-key from Arch Linux ARM Build System <builder@archlinuxarm.org> and its fingerprint. At this time it is 68B3 537F 39A3 13B3 E574 D067 7719 3F15 2BDB E6A6

Installation

Basically, follow the installation instructions from archlinuxarm.org for the "AArch64 Installation", with a few changes:

The boot partition needs to be larger than 100M, use e.g. 300M to be on the safe side. The second partition will be unencrypted and used for the installation system, use 3G or more if you want to include more software here. Make a third partition from the remaining space, it will be our encrypted system.

You should overwrite the third partition with random bytes, to achieve greater forensic resistance:

sudo dd if=/dev/urandom of=/dev/mmcblk1p3 bs=4M status=progress conv=fsync

Now put the sdcard in the pi, apply power, log in (over ssh if you want) as user alarm, password alarm. The root password root.

Prepare the rescue system

On the new system on the pi, upgrade, and install the necessary software:

pacman-key --init
pacman-key --populate archlinuxarm
pacman -Syu
pacman -S --needed sudo git rsync base-devel uboot-tools dropbear

You might also want to set a locale, keymap, hostname and everything else you want to have in the rescue system. Use the usual arch wiki installation guide for reference.

Enable sudo (you need it to build packages from AUR). Use visudo and append the line alarm ALL=(ALL) ALL.

To be on the safe side, reboot your system now, and log in again.

Install the mkinitcpio tools

You need the following AUR packages: mkinitcpio-utils mkinitcpio-netconf mkinitcpio-dropbear.

Using an AUR helper is not strictly necessary, as you can install the mkinitcpio packages manually from the AUR, but it is probably more convenient. E.g. after installing yay, use:

yay -S mkinitcpio-utils mkinitcpio-netconf mkinitcpio-dropbear

Note: yay is an especially handy AUR helper on Arch Linux ARM, since it can easily skip architecture checks when building pkgbuilds with an officially unsupported arch.

Set up SSH

mkinitcpio-dropbear only seems to be able to deal with RSA keys. So, on your primary computer, generate a new one:

ssh-keygen -t rsa -b 4096 -a 100 -f ~/.ssh/pi_rescue_key

Transfer it to the pi:

ssh-copy-id -i ~/.ssh/pi_rescue_key.pub alarm@192.168.1.100

(The IP address is probably different, of course) Then, on the pi:

sudo cp ~/.ssh/authorized_keys /etc/dropbear/root_key

The matching lines in your ~/.ssh/config file should be something like this:

Host pi_rescue
  HostName 192.168.1.100
  User root
  IdentityFile ~/.ssh/pi_rescue
  
Host pi
  HostName 192.168.1.100
  User alarm
  IdentityFile ~/.ssh/pi_rescue

You can then simply use ssh pi, and ssh pi_rescue to unlock at boot.

Prepare the initial ramdisk

You might want to backup the files we will be editing:

sudo cp /etc/mkinitcpio.conf /etc/mkinitcpio.conf.rescue
sudo cp /boot/boot.txt /boot/boot.txt.rescue

Or, even better, backup the whole /boot/ partition. If you break your encrypted system, you can simply overwrite the /boot/ partition with the backup, and thus easily boot the rescue system to fix things.

sudo cp -r /boot /root/boot_rescue

In /etc/mkinitcpio.conf:

Change the line MODULES=() to

MODULES=(g_cdc usb_f_acm usb_f_ecm smsc95xx g_ether broadcom)

These are needed for the initramfs to contain the ethernet and usb drivers (the ethernet is connected over usb internally). More Information on this.

Also, insert the hooks sleep netconf dropbear encryptssh before filesystem in the line HOOKS=().

The line should look like this:

HOOKS=(base udev autodetect modconf block sleep netconf dropbear encryptssh filesystems keyboard fsck)

You might also want to add the keymap hook after block, and set up a different keymap in /etc/vconsole.conf, if you want to use a non-US keyboard layout for entering your encryption passphrase.

Then, regenerate the initramfs:

sudo mkinitcpio -P

Note: If you get the Error: Unrecognised key type message while the mkinitcpio-dropbear hook is running: Remove at least one of these ssh hostkeys, and regenerate it in the /etc/ssh directory with the -m PEM option. Example:

cd /etc/ssh
sudo rm ssh_host_*key*
sudo ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" -m PEM < /dev/null
sudo ssh-keygen -t rsa -b 4096 -f ssh_host_rsa_key -N "" -m PEM < /dev/null

Then re-run mkinitcpio -P. See this dropbear bug on the key converting error.

Set up the encrypted partition

sudo cryptsetup luksFormat -c aes-xts-plain64 -s 512 -h sha512 --use-random -i 1000 /dev/mmcblk1p3
sudo cryptsetup luksOpen /dev/mmcblk1p3 root
sudo mkfs.ext4 /dev/mapper/root
sudo mount /dev/mapper/root /mnt

The number of iterations in the key derivation function, here -i 1000, can be increased to make the encryption passphrase more resistant. With 1000 iterations, it takes about 2 seconds to unlock the partition.

Sync the system

Now, copy the prepared system to the encrypted partition:

sudo rsync --info=progress2 -axHAX / /mnt/

Adjust Partitions

Add to /mnt/etc/fstab (file on the encrypted partition /mnt/etc/, not in /etc/!):

/dev/mapper/root  /               ext4    defaults,noatime  0       1

and to /mnt/etc/crypttab:

root   /dev/mmcblk1p3   none   luks

Configure the bootloader

More information on the new boot process that follows

You don't have to edit /boot/config.txt and /boot/cmdline.txt anymore, also the latter doesn't even exists anymore.

Instead, edit /boot/boot.txt.

Comment out the part uuid line, add a static ip setup, the cryptdevice, and change the root filesystem, all in the setenv line. It should look like this:

# After modifying, run ./mkscr

# Set root partition to the second partition of boot device
#part uuid ${devtype} ${devnum}:2 uuid

setenv bootargs console=ttyS1,115200 console=tty0 ip=192.168.1.100::192.168.1.1:255.255.255.0:pi_rescue:eth0:none cryptdevice=/dev/mmcblk1p3:root root=/dev/mapper/root rw rootwait smsc95xx.macaddr="${usbethaddr}"

if load ${devtype} ${devnum}:${bootpart} ${kernel_addr_r} /Image; then
  if load ${devtype} ${devnum}:${bootpart} ${fdt_addr_r} /dtbs/${fdtfile}; then
    if load ${devtype} ${devnum}:${bootpart} ${ramdisk_addr_r} /initramfs-linux.img; then
      booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r};
    else
      booti ${kernel_addr_r} - ${fdt_addr_r};
    fi;
  fi;
fi

After changing the file, regenerate the bootloader image:

cd /boot/
sudo ./mkscr

Notes:

  • You can also add earlyprintk after setenv bootargs to get more debug output from the boot process.
  • Of course, adjust your IP address, gateway and subnet mask
  • You can also get an IP Address with DHCP here, use e.g. ip=::::pi_rescue:eth0:dhcp (See the arch wiki for more net options.
  • You can also set a different MAC address in the setenv line, e.g with: " smsc95xx.macaddr="ab:cd:ef:01:23:45".
  • For problems with building the boot image, see the U-Boot Documentation

Moment Of Truth

Now, reboot your pi. You should be prompted for a the encryption passphrase when connecting the pi to a screen and a keyboard. Also, you should be able to connect with ssh pi_rescue , and enter you passphrase there.

After unlocking, your ssh connection will be dropped.

You can now ssh to your encrypted system with ssh pi!

Configure the new system

You can make all the usual configuration like language, hostname, timezone, NTP, ... you didn't make in the rescue system. It is also possible to use completely different settings here!

Notes

  • If you broke your encrypted system somehow, and were wise enough to made a backup of your /boot/ partition: Plug the sd-card into another computer and regain acces to your rescue system like so:
cd $(mktemp -d) && mkdir boot root
mount /dev/mmcblk1p1 boot
mount /dev/mmcblk1p2 root
cp -r root/root/boot_rescue boot/

Then, boot the pi, and log into the rescue system. Depending on how you messed up, you may want to change-root into the encrypted system and fix stuff:

cryptsetup open /dev/mmcblk1p3 root
mount /dev/mapper/root /mnt
arch-chroot /mnt

Or, maybe you need to re-do the steps above after Prepare the rescue system.

  • Currently, the boot process hangs with the message USB0: scanning bus 0 for devices..., when some USB-devices are connected. Try different USB-devices or disconnect them before booting the pi. This seems to be a bug in U-Boot.

  • If you have issues with ssh, try to connect with ssh root@192.168.1.100 and ssh alarm@192.168.1.100. The -F /etc/ssh/ssh_config and -v are also helpful to debug ssh problems.

  • If dropbear, for some reason, didn't use the openssh hostkeys, but created its own, you will see the WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! message when connecting to the encrypted system. OpenSSH might also prefer other hostkeys over the rsa ones dropbear uses. The solution is to accept two different hostkeys for the same IP address of the pi. Edit ~/.ssh/known_hosts, search for IP address of your pi. Copy the line and delete it, then ssh to the pi. Now paste the line back into the file, so you have two lines with the same ip, but with different hostkeys.

  • Instead of the default linux-aarch64 kernel, linux-aarch64-raspberrypi-bin from the AUR can be used. This is worth a try if some features are not working, like bluetooth, the Raspberry Touch Display, or video.

  • Previously, the AUR package dropbear_initrd_encrypt could be used. This was split into the packages mkinitcpio-netconf, mkinitcpio-dropbear and mkinitcpio-utils.

  • The sleep hook is not strictly necessary, but without it, on some systems, there is a race-condition. The smsc95xx module has not initialized the network interface yet before the net hook tries to configure it.

  • Instead of the netconf hook from the package mkinitcpio-netconf, the net hook from the package mkinitcpio-nfs-utils can be used to parse the ip= kernel parameter. It is more up-to-date, but so far, there does not seem to be a difference between them.

  • You might have to also add an ECDSA key to /etc/dropbear, or your first boot could fail.

  • In similar tutorials, you often see the advice to wipe the encrypted partition with /dev/zero instead of /dev/urandom. But this doesn't add security, it is basically useless! (Unless you only want to wipe previous data from the sdcard, but then you should wipe the whole card and not one partition. Or, unless, you plan to give the encryption passphrase to someone, and want to be able to prove that there are no hidden containers in the un-used space)

Other Setup Choices

Installation method: Instead of using an additional unencrypted partition to make the install, you can emulate the pi cpu architecture on main computer using the qemu and qemu-arch-extra packages. See this tutorial, and adapt it to the new rpi-4 64-bit version of arch linux arm. Also: arch wiki on QEMU

SSH daemon: Instead of using dropbear, you can also include tinyssh in the initial ramdisk. See the arch wiki.

mkinitcpio hooks: Instead of using mkinitcpio-dropbear, mkinitcpio-netconf, and mkinitcpio-utils, it can all be done with systemd and the mkinitcpio-systemd-tool AUR package. See the arch wiki entry on remote unlocking of dm-crypt.

File system: Some folks might want to use btrfs instead of ext4 on the encrypted filesystem. This gives the advantage See this tutorial, and adapt it for the newer rpi-4 64-bit version.

Links

https://archlinuxarm.org/platforms/armv8/broadcom/raspberry-pi-3#installation

https://github.com/grazzolini/mkinitcpio-netconf

https://github.com/grazzolini/mkinitcpio-dropbear

https://github.com/grazzolini/mkinitcpio-utils

https://www.denx.de/wiki/U-Boot/Documentation

https://wiki.archlinux.org/index.php/Mkinitcpio#HOOKS

https://wiki.archlinux.org/index.php/Dm-crypt/Specialties#Remote_unlocking_of_the_root_(or_other)_partition

https://raspberrypi.stackexchange.com/questions/67051/raspberry-pi-3-with-archarm-and-encrypted-disk-will-not-boot-how-can-be-identif

Older, mostly outdated tutorials:

https://gist.github.com/gea0/4fc2be0cb7a74d0e7cc4322aed710d38

https://gist.github.com/pezz/5310082

http://www.deadunicornz.org/blog/2013/12/20/raspberrypi-root-partition-encryption/index.html

https://github.com/phortx/Raspberry-Pi-Setup-Guide

https://gist.github.com/morgner/82105e8ce053b22b284eac86ce89555d

https://github.com/NicoHood/NicoHood.github.io/wiki/Raspberry-Pi-Encrypted-Btrfs-Root

https://wiki.polaire.nl/doku.php?id=archlinux-raspberry-encrypted

https://raspberrypi.stackexchange.com/questions/7159/can-the-raspberry-boot-to-an-lvm-root-partition

https://project.altservice.com/issues/289

@EnigmaCurry
Copy link

[if you] see the WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! message when connecting to the encrypted system .. The solution is to accept two different hostkeys for the same IP address of the pi. Edit ~/.ssh/known_hosts, search for IP address of your pi. Copy the line and delete it, then ssh to the pi. Now paste the line back into the file, so you have two lines with the same ip, but with different hostkeys.

The solution for me was to instead keep two separate known_hosts files for the two different hosts. Here's the snippet in my ~/.ssh/config:

Host pi4
     User alarm

Host pi4_rescue
     User root
     IdentityFile ~/.ssh/pi_rescue_key
     UserKnownHostsFile ~/.ssh/pi_rescue.known_hosts.txt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment