LUKS/Cryptsetup mit Hardware-Dongle (kein FIDO, kein KeyFile)

DukeNucEm

New Member
Nov 23, 2024
2
1
1
Hallo zusammen.
Total "OT", aber vielleicht hat ja einer eine Idee / sowas schon mal gesehen.
Ich kann's nicht g**glen, weil immer nur Ansätze mit "USB Stick" und "Keyfile" dabei raus kommen. Will ich aber nicht ;-)

Was will ich? Home Server für den Fall des Hardware-klaus sichern. Dieb kommt, nimmt einfach den NUC mit, SSDs darin sind aktuell unverschlüsselt. Wenn ich das umbaue auf volle Verschlüsselung soll die Kiste ohne SSH-Login booten & entschlüsseln, sofern ein bestimmtes USB-Device dran steckt. Kein USB-Speicher-Stick mit Key-File, sondern ein Stück "unrelated hardware".
- Ich habe für's Smarthome "controller sticks" (zigbee & homematic RF). Der eine hängt wegen besserer Sendeleistung aus dem Keller an einer simplen passiven USB-Verlängerung und seine Antenne steckt in einem Deckendurchbruch (Betondecken...). Fragt nicht, hat sich so ergeben, funktioniert seit Jahren.
- Nun würde ich den Stick da einfach "festdübeln" (nein, natürlich kein Loch in die Platine bohren...Profi am Werk, hier ;-)) . Den Stick nimmt dann sicher kein Dieb in Eile mit indem er erst Schrauben aus der Wand dreht.
- Der Stick ist aber kein normaler USB-Speicher, also kann ich kein Keyfile drauf legen.
- Also denk' ich mir: Ich müsste doch nur die Seriennummer des USB-Sticks als Key in einen "Slot" von luks/cryptsetup schreiben (wo man sonst einen key rein schreibt).
- Dann mit einem script im initramfs mit ein bissel Magie aus "lsusb", "grep", "/bin/udevadm info" die Seriennummer des Sticks zur Boot-Zeit auslesen und als key an die Partitionen übergeben.
- Die gewünschte Seriennummer selbst steht nirgends, nicht mal in dem script, ich schreibe sie nur einmal händisch beim Setup der Partitionen in den entsprechenden Slot.
- Der Dieb kann also allein anhand des Unlock-Sripts nur verstehen, was es tut... und wenn er's kapiert, müsste er wiederkommen und den Stick von der Wand schrauben. Wohl kaum :)

Ist sowas schon mal jemandem über den Weg gelaufen?

PS: Klar, ich könnte auch den NUC an der Wand festschrauben... aber da macht sich vielleicht einer die Mühe 4 Bolzen rauszudrehen, weil er denkt: Mensch, wenn das so gesichert ist, ist das erst recht wertvoll. Beim Antennen-Stick: Okay, aha, naja, smarthome-Antennen-Gedöns, keine 3 Euro wert. Kabel ab, NUC mitnehmen, aber den Stick doch nicht...
 
Ich antworte mir mal selbst... lange liegen gelassen, das Thema. Aber: Ja, so geht das!

Basis ist heute ein Debian 13 Trixie, somit sollte das auch mit einem PVE 9.0+ gehen. Und vermutlich auch mit Vorgängern - noch nicht getestet.

In der intird gibt es kein lsusb, aber udevadm, grep und awk. Und damit geht es auch.

Vorweg: Beispiel hier mit einem ollen USB-Flash-Stick. Tatsächlich würde es bei mir ein "Smarthome-Dingens" welches ich mit USB-Verlängerung "unklaubar" an die Wand dübeln würde. Augenscheinlich irgendeine "Antenne", nichts wertvolles, wird garantiert nicht mitgenommen. Jegliche USB-SSD oder was sonst noch direkt am Gerät liegt vermutlich schon.

1) Identifizieren einer geeignten Seriennummer oder eines anderen halbwegs sinnigen "Schlüssels" aus den Hardware-Infos, die udevadm info /dev/bus/usb/*/* ausgibt. Durch /*/* werden alle devices gelistet (was man sonst eher mit lsusb machen würde, haben wir aber später nicht). Dann braucht man für "sein" Gerät eine geeignete HW-ID, bspw. ein ID_SERIAL_SHORT= Wert. Kommt auf die Hardware an, die man da hat, welche Werte die jeweils überhaupt haben. Nicht jedes USB-Device hat eine "Serial Number".

2) Wert mittels grep und awk aus der Ausgabe schneiden
Bspw:
udevadm info /dev/bus/usb/*/* | grep _Flash_
Gibt zwei gute Zeilen für ein bestimmtes Gerät:
E: ID_SERIAL=USB_Flash_DISK_1408045150119156
E: ID_USB_SERIAL=USB_Flash_DISK_1408045150119156

Zeilen eines einfachen USB-Sticks, der "_Flash_Disk_" im Namen hat, was sonst kein anderes angeschlossenes Gerät in meinem Test-Setup hier hat. Den USB-Stick würde ein Dieb natürlich am Server lassen und mitnehmen, also nicht die richtige Wahl...

3) Seriennummer extrahieren:
udevadm info /dev/bus/usb/*/* | grep _Flash_ | grep ID_SERIAL | awk -F '_' '{print $5}'
Gibt uns: 1408045150119156
Diesen udevadm info Aufruf muss man sich passend zu seinem USB-Device bauen, der kommt weiter unten ins unlock-script.
Wenn man es einem Dieb schwerer machen will zu verstehen, was man da "grept", dann eine geeignete kryptische Regex bauen statt _Flash_. Hauptsache man grept nicht die Seriennumer selbst im script, dann kann man die auch gleich auf den Server kleben ;-)

4) Passphrase für das luks crypt-Device hinzufügen
hier bspw. für meine /dev/sda3
su -
cryptsetup luksAddKey /dev/sda3
Fragt nach einem aktuell bereits gültigen passphrase und dann 2x nach dem Neuen der hinzugefügt werden soll. Aufpassen, bei copy+paste oder auch beim tippen keine Leerzeichen mitnehmen oder sich vertippen (aber wir testen das gleich nochmal).
Hier dann also den Wert aus Schritt 3 zwei Mal eingeben.

5) testen, ob richtig eingetragen:
cryptsetup luksAddKey /dev/sda3
Fragt wieder nach einem gültigen passphrase. Hier nun einmal den gerade Hinzugefügten zuerst eingeben - wenn dann wiederum nach einem Neuen gefragt wird war der erste richtig ;-)

5a) Optional - einmal einen "Testlauf" machen
Prüfen, ob beim boot der udevadm Befehl auch wirklich funktionieren wird.
Dazu habe ich dropbear "überredet", den ich für remote unlock vorher eingebaut hatte.
  1. in /usr/share/initramfs-tools/scripts/init-premount/dropbear
    direkt vor der Zeile exec /sbin/dropbear -$flags ${DROPBEAR_OPTIONS-} eine Zeile
    echo "Test:"$(udevadm info /dev/bus/usb/*/* | grep _Flash_ | grep ID_SERIAL | awk -F '_' '{print $5}') einbauen; die Ausgabe der gefundenen Seriennummer erscheint dann auf der lokalen Konsole des Servers wenn dropbear auf SSH-Connect wartet.
  2. update-intiramfs -u - v
  3. reboot
  4. Auf der lokalen Konsole müsste 'Test:1408045150119156' auftauchen während der dropbear wartet.
6) keyscript anlegen:
nano /lib/cryptsetup/scripts/passkey
Da die anderen Scripte in diesem Ordner auch kein .sh tragen, lasse ich es auch hier weg.
Dort, oder einen anderen Ort wählen, an dem cryptsetup-scripte liegen, die in die initramfs mit eingebaut werden; kommt nicht darauf an wo oder in welchem init-step-Ordner, denn das script wird nicht vom init-prozess direkt aufgerufen, sondern vom cryptsetup anhand der crypttab; also hauptsache ein Örtchen, das vom initramfs-Bau "mitgenommen" wird, damit das script in der initrd vorhanden ist.
Inhalt der Datei ist genau eine ausführbare Zeile mit dem oben erarbeiteten udevadm Aufruf in $(...), und zwar genau mit echo -n davor, wobei das -n absolut zwingend ist! Ohne das echo -n $(...) funktioniert das nicht.
Code:
#!/bin/sh
echo -n $(udevadm info /dev/bus/usb/*/* | grep _Flash_ | grep ID_SERIAL | awk -F '_' '{print $5}')
Es darf keine andere Zeile (etwa ein echo "Automatische Entsprerrung in 10 Sekunden..."; sleep 10) davor stehen - sonst wird das als passphrase übergeben, was natürlich nicht funktionieren wird, und der eigentliche passphrase kommt nie an.
Dann das noch als ausführbar setzen, damit update-initramfs das auch mitnimmt:
chmod 700 /lib/cryptsetup/scripts/passkey

7) /etc/crypttab anpassen
die Option keyscript=/lib/cryptsetup/scripts/passkey hinzufügen
nano /etc/crypttab
Zeile sieht dann etwa so aus:
sda3_crypt UUID=(...) none luks,discard,keyscript=/lib/cryptsetup/scripts/passkey

8) initrd neu bauen
update-initrd -u -v
(Die Ausgabe könnte man sich mit > log.txt umleiten und dann einmal mit cat log.txt | grep passkeyprüfen, dass das eigene Script auch tatsächlich eingebaut wurde.)

9) Reboot, und zuschauen, wie der Server bootet, sofern der USB-Stick dran steck.

10) Stick abnehmen, reboot,... und schön wieder selber tippen ;-)

"Notfall-Schlüsseldienst" (falls man das -n beim echo vergessen hat... soll ja Leute geben ;-) )
Falls etwas nicht richtig funktioniert, und die manuelle Eingabe eines passphrase auch nicht klappen will, wird der Server nach einer Weile in die (initramfs) Notfall-Shell booten. Dort kann man sich retten, indem man das luks device manuell aufschließt.
cat /cryptroot/crypttab verrät euch, welches device ihr braucht.
Wenn euer veschlüsseltes Device mit der / Partition drin sda3 wäre:
cryptsetup luksOpen /dev/sda3 sda3_crypt
Nun euren passphrase eingeben. Shell gibt sich ein paar stille Sekunden, und dann steht da wieder (initramfs) und wartet auf den nächsten Befehl.
Einfach exit eingeben, und der Bootvorgang geht weiter.

So ausführlich damit ich's in 12 Monaten nochmal hinbekomme wenn ich das am Produktivsystem mache :-D
 
  • Like
Reactions: UdoB