Raspberry Pi OS mit verschlüsselter Root-Partition

  Lioh Möller   Lesezeit: 10 Minuten  🗪 8 Kommentare

Um einen Raspberry Pi mit dem offiziellen Betriebssystem und verschlüsselten Root-Partition nutzen zu können, ist einiges an Vorarbeit notwendig, sofern keine Drittanbieter-Hilfsmittel zum Einsatz kommen sollen. Wir erklären dir, wie es funktioniert.

raspberry pi os mit verschlüsselter root-partition

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 xchacha12,aes-adiantum-plain64

Das Ergebnis sollte in etwa wie folgt aussehen:

# Tests are approximate using memory only (no storage IO).
# Algorithm | Key | Encryption | Decryption
xchacha12,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
xchacha12
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 xchacha12,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 xchacha12,aes-adiantum-plain64 --hash sha256 --sector-size 4096 --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

Tags

USB-Stick, count=XXXXX, SD-Karte, Partition, Datei, Initramfs, Root, Prüfsumme, Stick

Markus
Geschrieben von Markus am 10. Februar 2022 um 12:55

Danke für die Übersetzung. Ein Problem was ich dabei habe, ist die mehr oder weniger schwache CPU-Leistung für den Raspi. Der kommt teilweise mit der Verschlüsselung nicht nach, da der kworker/crypt prozess nicht ausreichend Ressourcen abbekommt. Das passiert insbesondere bei größeren Daten-Übertragungen, etwa Backups. Ich habe es bis jetzt nur von einem unencrypted auf eine encrypted partition getestet, es wird vermutlich aber dann total ENG, wenn ich (um beim Beispiel Backup zu bleiben) von dev1 ent- auf dev2 verschlüsseln muss.

Lioh
Geschrieben von Lioh am 10. Februar 2022 um 13:00

Kann ich bestätigen.

Markus
Geschrieben von Markus am 10. Februar 2022 um 13:28

ein cryptsetup mit xchacha12 statt xchacha20 und --sector-size 4096 bringt nochmal einen Performancegewinn, der es m.E. arbeitsfähig macht.

Lioh
Geschrieben von Lioh am 21. Februar 2022 um 11:55

Ich habe die Anleitung entsprechend angepasst.

Marcco134
Geschrieben von Marcco134 am 9. Juni 2022 um 21:42

Es geht leider nicht. Ich komme nur bis "Nun kann das System neu gestartet werden.". Wenn ich neu starte, gibt's nur einen blinkenden Cursor. Versucht mit OS lite 32 und OS Desktop, sowohl 32 als auch 64. Immer das gleiche Ergebnis. Ich habe das ganze per script.sh gemacht, um Tippfehler auszuschliessen. Kann ich das irgend jemanden übermitteln? Ich hätte wirklich sehr gerne eine Lösung. Danke.

Bart
Geschrieben von Bart am 6. September 2022 um 10:05

Es hat funktioniert, aber mit BullsEye musste ich meine /boot/config.txt-Datei ändern: dtoverlay=vc4-fkms-v3d statt dtoverlay=vc4-kms-v3d. Siehe: https://github.com/rr-developer/LUKS-on-Raspberry-Pi/issues/7

Marcco134
Geschrieben von Marcco134 am 22. Oktober 2022 um 21:21

Danke Bart! Nachdem ich Deine Antwort gelesen habe, habe ich es jetzt wieder neu versucht und bin wieder gescheitert. Irgendwas mache ich wohl falsch, weiss aber leider nicht, was?? Nach dem Reboot blinkt nur der Cursor. Ich verwende RaspOS32 in der neuesten Version, also Basis BullsEye (22.10.22). Die ersten Fehlermeldungen erhalte ich beim Erstellen initramfs. Ich bekomme neben Warnmeldungen, die ich anleitungsgetreu ignoriere, auch eine Fehlermeldung: /etc/initramfs-tools/hooks/luks_hooks failed with return 1. Entsprechend der Anleitung überprüfe ich nun mit lsinitramfs und bekomme die Meldung cpio: Vorzeitiges Ende des Archivs. (Mein cpio ist 2.13) Vielleicht liegt es daran, dass ich am PI400 sitze???

Marcco134
Geschrieben von Marcco134 am 23. Oktober 2022 um 16:16

Ich meinte natürlich Basis Bullseye (22.09.22) aber komplett update auf einer frischen sd-card. Gerade auch mit 64 versucht, gleiches Problem.