Raspberry Pi OS mit verschlüsselter Root-Partition

Di, 21. September 2021, Lioh Möller

Anforderungen

Es wird eine SD-Karte mit Raspberry Pi OS (lite) benötigt sowie ein mindestens gleich grosser USB-Stick. Das Betriebssystem lässt sich mithilfe von dd oder einer Anwendung wie Etcher auf die SD-Karte übertragen. Nachdem die Grundkonfigurationen im Raspberry Pi OS vorgenommen wurden (Wichtig: Tastaturlayout!) kann mit der Einrichtung der Verschlüsselung begonnen werden.

Zunächst werden die benötigten Tools installiert:

sudo apt install busybox cryptsetup initramfs-tools

Um zu testen, ob die Verschlüsselung grundsätzlich funktioniert, kann folgender Befehl eingegeben werden:

cryptsetup benchmark -c xchacha20,aes-adiantum-plain64

Das Ergebnis sollte in etwa wie folgt aussehen:

# Tests are approximate using memory only (no storage IO).
# Algorithm | Key | Encryption | Decryption
xchacha20,aes-adiantum 256b 111.2 MiB/s 114.6 MiB/s

Vorbereitungen

Zur Anpassung des initial ram filesystems (initramfs), wird zunächst eine Datei /etc/kernel/postinst.d/initramfs-rebuild mit dem folgenden Inhalt erstellt:

#!/bin/sh -e

# Rebuild initramfs.gz after kernel upgrade to include new kernel's modules.
# https://github.com/Robpol86/robpol86.com/blob/master/docs/_static/initramfs-rebuild.sh
# Save as (chmod +x): /etc/kernel/postinst.d/initramfs-rebuild

# Remove splash from cmdline.
if grep -q '\bsplash\b' /boot/cmdline.txt; then
  sed -i 's/ \?splash \?/ /' /boot/cmdline.txt
fi

# Exit if not building kernel for this Raspberry Pi's hardware version.
version="$1"
current_version="$(uname -r)"
case "${current_version}" in
  *-v7+)
    case "${version}" in
      *-v7+) ;;
      *) exit 0
    esac
  ;;
  *+)
    case "${version}" in
      *-v7+) exit 0 ;;
    esac
  ;;
esac

# Exit if rebuild cannot be performed or not needed.
[ -x /usr/sbin/mkinitramfs ] || exit 0
[ -f /boot/initramfs.gz ] || exit 0
lsinitramfs /boot/initramfs.gz |grep -q "/$version$" && exit 0 # Already in initramfs.

# Rebuild.
mkinitramfs -o /boot/initramfs.gz "$version"

Die Datei muss als ausführbar markiert werden:

sudo chmod +x /etc/kernel/postinst.d/initramfs-rebuild

Um fehlende Programme und Libraries in das initramfs zu integrieren, wird ein hook-File /etc/initramfs-tools/hooks/luks_hooks mit folgendem Inhalt erstellt:

#!/bin/sh -e
PREREQS=""
case $1 in
prereqs) echo "${PREREQS}"; exit 0;;
esac

. /usr/share/initramfs-tools/hook-functions

copy_file binary /lib/arm-linux-gnueabihf/libgcc_s.so.1
copy_exec /sbin/resize2fs /sbin
copy_exec /sbin/fdisk /sbin
copy_exec /sbin/cryptsetup /sbin

Auch diese Datei wird als ausführbar markiert:

sudo chmod +x /etc/initramfs-tools/hooks/luks_hooks

Nun muss sichergestellt werden, dass auch die benötigten Kernel-Module zum initramfs hinzugefügt werden.

Dazu werden die folgenden Zeilen an die Datei /etc/initramfs-tools/modules angehängt:

algif_skcipher
xchacha20
adiantum
aes_arm
sha256
nhpoly1305
dm-crypt

Daraufhin kann das initramfs erstellt werden:

sudo -E CRYPTSETUP=y mkinitramfs -o /boot/initramfs.gz

Eine mögliche Warnmeldung von cryptsetup kann an dieser Stelle ignoriert werden.

Mit folgenden Befehlen kann überprüft werden, ob die Programme bzw. die Kernel-Module jetzt im initramfs vorhanden sind:

lsinitramfs /boot/initramfs.gz | grep -P "sbin/(cryptsetup|resize2fs|fdisk)"
lsinitramfs /boot/initramfs.gz | grep -P "(algif_skcipher|chacha|adiantum|aes-arm|sha256|nhpoly1305|dm-crypt)"

Boot vorbereiten

Um das Betriebssystem von einer verschlüsselten Partition starten können, muss die Startkonfiguration entsprechend angepasst werden. Dazu wird zunächst die Datei /boot/config.txt um folgende Zeile erweitert:

initramfs initramfs.gz followkernel

In der Datei /boot/cmdline.txt wird die Zeile, in der die Root-Partition spezifiziert, wird wie folgt angepasst:

root=/dev/mapper/sdcard cryptdevice=/dev/mmcblk0p2:sdcard

In der /etc/fstab muss die Device-Node der Root-Partition geändert werden:

/dev/mapper/sdcard

Sofern die /boot Partition in der Form PARTUUID=xxxxx angegeben ist, muss dieser Eintrag auf den Geräte-Pfad /dev/mmcblk0p1 angepasst werden.

Die Datei /etc/crypttab muss um folgende Zeile erweitert werden:

sdcard /dev/mmcblk0p2 none luks

Nun kann das System neu gestartet werden. Da bisher noch keine verschlüsselte Partition eingerichtet wurde, wird beim Systemstart lediglich die initramfs Shell geladen werden, in welcher die weitere Konfiguration vorgenommen werden kann.

Root Partition verschlüsseln

In der initramfs Shell kann zunächst getestet werden ob cryptsetup funktioniert:

cryptsetup benchmark -c xchacha20,aes-adiantum-plain64

Sofern der Test erfolgreich war, kann der Inhalt der root Partition auf den USB-Stick kopiert werden, um daraufhin die SD-Karte zu verschlüsseln. Anschliessend wird der Inhalt der root Partition zurück auf die nun verschlüsselte SD-Karte kopiert. Alle bisherigen Daten auf dem USB-Stick gehen dabei verloren.

Vor dem Kopieren wird jedoch die Dateisystem-Grösse auf das Minimum reduziert, sodass der Kopiervorgang weniger Zeit in Anspruch nimmt. Zuerst wird zur Vorbereitung das Filesystem auf Fehler überprüft:

e2fsck -f /dev/mmcblk0p2

Nach diesem Schritt kann das Dateisystem verkleinert. Wichtig hierbei ist, dass die Anzahl der 4k Blocks notiert wird:

resize2fs -fM -p /dev/mmcblk0p2

Eine mögliche Ausgabe kann dabei wie folgt aussehen:

Resizing the filesystem on /dev/mmcblk0p2 to 2345678 (4k) blocks.

In diesem Beispiel wäre die Zahl 2345678 von Bedeutung. Nach diesem Schritt wird eine Prüfsumme der gesamten Partition berechnet. Dies wird nach jedem Kopiervorgang wiederholt, um sicherzustellen, dass keine Inkonsistenzen entstehen.

Hinweis: Bei den folgenden Befehlen muss XXXXX durch die zuvor erhaltenen Block-Anzahl ersetzt werden.

dd bs=4k count=XXXXX if=/dev/mmcblk0p2 | sha1sum

Die ermittelte Prüfsumme sollte notiert werden. Daraufhin kann der USB-Stick angeschlossen werden. Um zu testen, ob dieser korrekt erkannt wurde, kann der folgende Befehl verwendet werden:

fdisk -l /dev/sda

Nun kann die Kopie gestartet werden. Auch hier muss daran gedacht werden, dass die Anzahl der ermittelten Blocks angegeben wird.

dd bs=4k count=XXXXX if=/dev/mmcblk0p2 of=/dev/sda

Ähnlich wie zuvor wird die Prüfsumme der Kopie jetzt berechnet:

dd bs=4k count=XXXXX if=/dev/sda | sha1sum

Sofern die Prüfsummen übereinstimmen, kann mit den nächsten Schritten fortgefahren werden.

Es folgt die Verschlüsselung der Root-Partition. Hierfür wird mithilfe von cryptsetup ein LUKS Volumen erstellt. Dazu kann der folgende Befehl genutzt werden:

cryptsetup --type luks2 --cipher xchacha20,aes-adiantum-plain64 --hash sha256 --iter-time 5000 –-key-size 256 --pbkdf argon2i luksFormat /dev/mmcblk0p2

cryptsetup wird zweimal zur Eingabe einer Passphrase auffordern.

Nach dem Erstellen des Volumens muss dieses geöffnet werden:

cryptsetup luksOpen /dev/mmcblk0p2 sdcard

Es wird nach der zuvor vergebenen Passphrase gefragt. Nachdem das Volumen geöffnet ist, wird das Root-Filesystem vom USB-Stick zurück auf die nun SD-Karte kopiert. (Anzahl Blocks ersetzen)

dd bs=4k count=XXXXX if=/dev/sda of=/dev/mapper/sdcard

Auch nun wird wieder die Prüfsumme berechnet und mit dem zuvor ermittelten Wert verglichen:

dd bs=4k count=XXXXX if=/dev/mapper/sdcard | sha1sum

Sofern die Prüfsummen übereinstimmen, wird abschliessend die Integrität des Dateisystems überprüft:

e2fsck -f /dev/mapper/sdcard

Da das Filesystem bisher noch in der Grösse minimiert ist, muss dieses wieder auf die vollständige Grösse erweitert werden:

resize2fs -f /dev/mapper/sdcard

Der USB-Stick kann nun entfernt werden und die initramfs-Shell kann verlassen werden.

exit

Nach dem Verlassen der Shell mit exit startet das Betriebssystem wieder normal.

Booting

Um nicht bei jedem Systemstart in der initramfs-Shell die verschlüsselte Partition manuell mit cryptsetup öffnen zu müssen, wird initramfs nochmals neu erstellt. Das Betriebssystem wird anschliessend beim Bootvorgang automatisch nach der Passphrase fragen. Hierfür wird der folgende Befehl genutzt:

sudo mkinitramfs -o /boot/initramfs.gz

Damit ist die Einrichtung der Verschlüsselung bereits abgeschlossen.

Quelle: https://github.com/rr-developer/LUKS-on-Raspberry-Pi/blob/5f7c5ba069f562e9c2cd8cdf9925a7dc49b63896/index.md

Bildquelle: Miiicihiaieil  Hieinizilieir / Wikimedia Commons, CC BY-SA 4.0