FreeBSD/System verschlüsseln mit geli(8)

Aus UUGRN

Dieser Artikel beschreibt, wie man ein FreeBSD von einem (fast) vollständig geli-verschlüsselten System booten kann, d.h. auch / liegt auf einem geli-device.

Der hier beschriebene Ansatz unterscheidet sich von diesem Artikel grundlegend dadurch, dass der Bootloader und der Kernel nicht auf eiem USB-Stick oder externen Bootmedium abgelegt ist sondern unverschlüsselt auf der Platte liegt.

Slices und BSD Labels
Hinweis:

Diesen Artikel habe ich anhand meiner Aufzeichnungen und Erinnerung geschrieben. Ich musste auf dem Weg dahin einige Umwege gehen, weil Zwischenschritte ursprünglich nicht funktioniert hatten.
Ich denke dennoch, dass man diese Beschreibung als Rezept nutzen kann, auch wenn sie noch nicht 100% verifiziert ist. Feedback bitte auf der Diskussionsseite oder als Kommentar zum Artikel im Blog. --rabe 16:49, 26. Jul. 2009 (UTC)


Zielsetzung[Bearbeiten]

  • Das gesamte (benutzte) System soll verschlüsselt werden (Ausnahmen... )
  • Auf externe Bootmedien (USB-Stick, Diskette, ... ) soll verzichtet werden

Nebenbedingungen[Bearbeiten]

  • der FreeBSD Bootloader liest sowohl die erforderlichen Kernelmodule als auch den Kernel selbst aus <bootdevice>:/boot
  • der FreeBSD Bootloader liest außerdem <bootdevice>:/etc/fstab und ermittelt dort das zu mountende Root-Filesystem (wird an den Kernel übergeben)
  • der FreeBSD Bootloader kann nur unverschlüsseltes UFS lesen, es kann keine geli-encryption nutzen
  • swap soll verschlüsselt sein
  • es soll ein unverschlüsseltes dumpdevice existieren (für kernel panics, vmcore), Größe mind. RAM
  • es gibt nur eine Festplatte (zB in einem Notebook)
  • andere Betriebssysteme (Multiboot) sind hier möglich, aber nicht extra behandelt.

Vorüberlegung[Bearbeiten]

Es werden 2 Bereiche auf der Festplatte benötigt: verschlüsselt und unverschlüsselt.

Die Festplatte (/dev/ad0) wird daher unterteilt in 2 slices: /dev/ad0s1 (unverschlüsselt) und /dev/ad0s2 (verschlüsselt).

Grund-Installation[Bearbeiten]

Zunächst eine einfache Grundinstallation von FreeBSD durchführen, zB von CD, mit sysinstall. Fast wie immer. Wir benötigen hier zunächst keine Packages.

fdisk[Bearbeiten]

2 Slices (=Partitionen) mit Typ 165 (=FreeBSD) anlegen
  • ca 5GB für /dev/ad0s1
  • Rest für /dev/ad0s2
  • BootLoader in MBR installieren

bsdlabel[Bearbeiten]

In ad0s1 folgende BSD-Labels anlegen
  • ca 1GB für /dev/ad0s1a, Filesystem / (das ist das Boot- und Maintenance-System, unverschlüsselt)
  • Rest für /dev/ad0s1b, swap (das wird später unser unverschlüsseltes dumpdevice)

Software[Bearbeiten]

  • Distributions: Minimal
  • keine weiteren Packages


abschließen[Bearbeiten]

  • Installation mit Netzwerkonfiguration, Root-Passwort, User, ... abschließen.
  • Auf /dev/ad0s1a liegt nun ein bootfähiges und unverschlüsseltes Minimalsystem.
  • Auf /dev/ad0s2 ist derzeit nichts abgelegt, es ist aber angelegt. Wichtig ist, dass es während der Grundinstallation angelegt wird, denn wenn das Maintenance-System von /dev/ad0s1a gebootet ist, kann die Partitionstabelle in /dev/ad0 nicht geschrieben werden. Ein Trick würde es zwar erlauben, aber man kann es dann nicht ohne weiteres sehen/benutzen.
  • Rebooten.

Verschlüsseltes System einrichten[Bearbeiten]

Vorbereitungen[Bearbeiten]

  • Zunächst das soeben installierte Grundsystem booten, einloggen als root. Das sollte ohne Probleme funktionieren. Falls nicht, dann müssen diese Probleme zunächst gefixt werden.
  • prüfen, welche ad0-Devices es gibt:
# ls -la /dev/ad0*
crw-r-----  1 root  operator    0,  86 Jul 26 18:21 /dev/ad0
crw-r-----  1 root  operator    0,  87 Jul 26 18:21 /dev/ad0s1
crw-r-----  1 root  operator    0,  91 Jul 26 18:21 /dev/ad0s1a
crw-r-----  1 root  operator    0,  92 Jul 26 18:21 /dev/ad0s1b
crw-r-----  1 root  operator    0,  93 Jul 26 18:21 /dev/ad0s1c
crw-r-----  1 root  operator    0,  88 Jul 26 18:21 /dev/ad0s2
  • Wichtig ist, dass es /dev/ad0s2 gibt und außerdem keine weiteren /dev/ad0s2*

geli einrichten[Bearbeiten]

Wir legen nun auf /dev/ad0s2 einen geli-Layer. Das "-b" sorgt dafür, dass der Kernel vor dem Mounten von / nach der Passphrase fragt!

# geli init -b /dev/ad0s2

Hier eine nicht zu einfache Passphrase verwenden und gut merken!

Achtung
Die Passphrase muss später mit dem US-Tastaturlayout eingetippt werden können, d.h. man sollte hier auf die Umlaute, x und y und Sonderzeichen verzichten, um Konfusion zu vermeiden.

Die folgenden Schritte sind Schritte, die nach dem Erzeugen eines geli-Devices immer erfolgen sollten:

  • Das eben erzeugt device attachen (zugänglich machen):
# geli attach /dev/ad0s2

... fragt nach der Passphrase, bei Erfolg entsteht ein *.eli-Device

  • prüfen:
# ls -la /dev/ad0s2.eli
crw-r-----  1 root  operator    0,  94 Jul 26 18:21 /dev/ad0s2.eli
  • einmal komplett mit /dev/random überschreiben:
# dd if=/dev/random of=/dev/ad0s2.eli bs=1m 

das kann je nach CPU und Größe des Devices lange bis sehr lange dauern.

Tipp
dd gibt durch Drücken von ^T (Strg+T) ein Zwischenergebnis aus, d.h. bisherige Menge und Geschwindigkeit
  • Wenn das durch ist, kann das geli-slice /dev/ad0s2.eli sicher verwendet werden. Zu Demo-Zwecken kann man auf den Schritt mit /dev/random auch verzichten.

bsdlabel auf ad0s2.eli einrichten[Bearbeiten]

Hier muss ein bsdlabel angelegt werden. Normalerweise könnte man das mit Hilfe von sysinstall oder sade erledigen, diese (er)kennen allerdings nicht das *.eli-Device. Deswegen muss man das bsdlabel hier ausnahmsweise von Hand erzeugen. Wer sich das schonmal angeschaut hat, wird hiervor vermutlich zurückschrecken, aber so schlimm ist das garnicht. Man braucht nichtmal einen Taschenrechner oder Papier+Bleistift!

  • ein standard-Label schreiben:
# bsdlabel -w /dev/ad0s2.eli
  • das Standard-Label ansehen (hier nur eine nachempfundene Ausgabe):
# bsdlabel /dev/ad0s2.eli
# /dev/ad0s2.eli:
8 partitions:
#        size   offset    fstype   [fsize bsize bps/cpg]
  a: 68459374       16    4.2BSD     2048 16384 28552 
  c: 68459390        0    unused        0     0         # "raw" part, don't edit

Es existiert hier nur ein "a:"-Label. Wir wollen allerdings mindestens noch swap und vielleicht auch verschiedene Filesysteme verwenden, deswegen der folgende Schritt

  • bsdlabel exportieren
# bsdlabel /dev/ad0s2.eli > /tmp/bsdlabel_ad0s2.eli
  • bearbeiten:

ad0s2.elic ist hier 33427 MB oder 32.6 GB groß. Folgende Größen sollen angelegt werden:

  • ad0s2.elia / 2GB
  • ad0s2.elib swap 2GB
  • ad0s2.elid /usr 25GB
  • ad0s2.elie /var (Rest, ca 3.5GB)
# vi /tmp/bsdlabel_ad0s2.eli
# /dev/ad0s2.eli:
8 partitions:
#        size   offset    fstype   [fsize bsize bps/cpg]
  a:      2G        16    4.2BSD 
  b:      2G         *     swap
  c: 68459390        0    unused        0     0         # "raw" part, don't edit
  d:     25G         *    4.2BSD 
  e:       *         *    4.2BSD 
  • bsdlabel schreiben:
# bsdlabel -R ad0s2.eli /tmp/bsdlabel_ad0s2.eli

bsdlabel errechnet die richtigen Werte für size und offset.

Die beiden Schritte ließen sich auch zu "bsdlabel -e" zusammenführen, hier geht allerdings dann die Datei verloren (falls man es modifiziert neu versuchen will).

  • Ergebnis ansehen:
# bsdlabel /dev/ad0s2.eli
# /dev/ad0s2.eli:
8 partitions:
#        size   offset    fstype   [fsize bsize bps/cpg]
  a:  4194304       16    4.2BSD     2048 16384 28552 
  b:  4194304  4194320      swap                    
  c: 68459390        0    unused        0     0         # "raw" part, don't edit
  d: 52428800  8388624    4.2BSD     2048 16384 28552 
  e:  7641966 60817424    4.2BSD     2048 16384 28552 

Filesysteme einrichten[Bearbeiten]

  • Wir sollten jetzt das folgende haben:
# ls -la /dev/ad0s2.eli*
crw-r-----  1 root  operator    0,  94 Jul 26 18:21 /dev/ad0s2.eli
crw-r-----  1 root  operator    0,  96 Jul 26 18:21 /dev/ad0s2.elia
crw-r-----  1 root  operator    0,  97 Jul 26 18:21 /dev/ad0s2.elib
crw-r-----  1 root  operator    0,  98 Jul 26 18:21 /dev/ad0s2.elic
crw-r-----  1 root  operator    0,  99 Jul 26 18:21 /dev/ad0s2.elid
crw-r-----  1 root  operator    0, 100 Jul 26 18:21 /dev/ad0s2.elie
  • formatieren:

... mit UFS-Labels, die später verwendet werden (können)

# newfs -L ROOT /dev/ad0s2.elia
[...]

# newfs -L USR -U /dev/ad0s2.elid
[...]

# newfs -L VAR -U /dev/ad0s2.elie
[...]
  • mounten unter /geli/
# mkdir /geli
# mount /dev/ufs/ROOT /geli
# mkdir /geli/usr /geli/var
# mount /dev/ufs/USR /geli/usr
# mount /dev/ufs/VAR /geli/var

Basissystem clonen[Bearbeiten]

Ziel ist es, das installierte Basissystem auf die (neuen) Filesysteme zu kopieren. Ich bevorzuge hierfür "cpdup".

  • kopieren mit cpdup:
# pkg_add -r -v cpdup

# /usr/local/bin/cpdup -v / /geli
[...]
# /usr/local/bin/cpdup -v /var /geli/var
[...]
# /usr/local/bin/cpdup -v /usr /geli/usr
[...]


Bootkonfiguration[Bearbeiten]

Auf /dev/ad0s1a liegt unverschlüsselt das /boot und ein /etc

/boot/loader.conf ergänzen
geom_eli_load="YES"
/boot/device.hints ergänzen
hint.kbdmux.0.disabled="1"

(das behebt Probleme bei der Passphrase-Eingabe im Kernel)

/etc/fstab ändern
#/dev/ad0s1a            /               ufs     rw              1       1
/dev/ad0s2.elia         /               ufs     rw              1       1

Wichtig ist hier nur die Zeile für "/", die vom Bootloader gelesen wird. Für die einzelnen Dateisysteme wird nachher die ad0s2.elia:/etc/fstab verwendet

/geli/etc/fstab
# Device                Mountpoint      FStype  Options         Dump    Pass#
/dev/ad0s2.elib         none            swap    sw              0       0
/dev/ad0s2.elia         /               ufs     rw              1       1
/dev/ufs/VAR            /var            ufs     rw              2       2
/dev/ufs/USR            /usr            ufs     rw              2       2
/dev/acd0               /cdrom          cd9660  ro,noauto       0       0
/geli/etc/rc.conf ergänzen
dumpdev="/dev/ad0s1b" # unencrypted swapspace 

Rebooten[Bearbeiten]

Einfach mit "reboot" neu starten.

In den Kernel-Messages beim Booten sollte dann sinngemäß folgendes erscheinen:

[...]
Timecounter "TSC" frequency 1525848984 Hz quality 800
Timecounters tick every 1.000 msec
firewire0: 1 nodes, maxhop <= 0, cable IRM = 0 (me)
firewire0: bus manager 0 (me)
ad0: 38204MB <SAMSUNG MP0402H UC100-14> at ata0-master UDMA100
acd0: CDRW <QSI CD-RW/DVD-ROM SBW-241/VX11> at ata1-master UDMA33
Enter passphrase for ad0s2: 
GEOM_ELI: Device ad0s2.eli created.
GEOM_ELI: Encryption: AES-CBC 128
GEOM_ELI:     Crypto: software
GEOM_LABEL: Label for provider ad0s1a is ufsid/4a6bbf04331e3ba9.
GEOM_LABEL: Label for provider ad0s2.elia is ufsid/4a6c7ef8e582dc1d.
GEOM_LABEL: Label for provider ad0s2.elia is ufs/ROOT.
GEOM_LABEL: Label for provider ad0s2.elid is ufsid/4a6c7f024e59d562.
GEOM_LABEL: Label for provider ad0s2.elid is ufs/USR.
GEOM_LABEL: Label for provider ad0s2.elie is ufsid/4a6c7f0a80b74113.
GEOM_LABEL: Label for provider ad0s2.elie is ufs/VAR.
Trying to mount root from ufs:/dev/ad0s2.elia
GEOM_LABEL: Label ufs/ROOT removed.
GEOM_LABEL: Label ufsid/4a6c7ef8e582dc1d removed.
GEOM_LABEL: Label for provider ad0s2.elia is ufsid/4a6c7ef8e582dc1d.
GEOM_LABEL: Label for provider ad0s2.elia is ufs/ROOT.
GEOM_LABEL: Label ufsid/4a6c7f0a80b74113 removed.
GEOM_LABEL: Label ufsid/4a6c7f024e59d562 removed.
GEOM_LABEL: Label ufs/ROOT removed.
GEOM_LABEL: Label ufsid/4a6c7ef8e582dc1d removed.
GEOM_LABEL: Label ufsid/4a6bbf04331e3ba9 removed.
Erläuterung
Nachdem die Platte ad0 erkannt wird, erkennt das Kernelmodul geom_eli (was im Bootloader geladen wird), dass es sich bei ad0s2 um ein geli-device mit dem init-Flag "-b" handelt. Deswegen fragt der Kernel hier nach der Passphrase.
Man hat hier bis zu 3 Versuche (konfigurierbar)
Schlägt alles fehl, kann der Kernel das vom Bootloader angegebene Filesystem /dev/ad0s2.elia nicht mounten, es kommt dann ein "mountroot>"-Prompt. Hier kann man das Maintenance-System auf ad0s1a angeben:
mountroot> ufs:ad0s1a
... wobei ":" im US-Layout da liegt, wo man mit einer Deutschen Tastatur Shift-Ö tippen muss.


Afterboot[Bearbeiten]

  • Nach dem Booten sollte, wenn alles geklappt hat, das ganze so aussehen:
# mount
/dev/ad0s2.elia on / (ufs, local)
devfs on /dev (devfs, local)
/dev/ufs/VAR on /var (ufs, local, soft-updates)
/dev/ufs/USR on /usr (ufs, local, soft-updates)
/dev/ad0s1a on /mnt (ufs, local)

# swapinfo
Device          1K-blocks     Used    Avail Capacity
/dev/ad0s2.elib   2097152        0  2097152     0%
  • Aus der Bootmessage wissen wir ...
GEOM_LABEL: Label for provider ad0s2.elid is ufs/USR.
GEOM_LABEL: Label for provider ad0s2.elie is ufs/VAR.

... dass /dev/ufs/USR und /dev/ufs/VAR Labels auf /dev/ad0s2.eli sind und somit verschlüsselt sind.

Nachbetrachtungen[Bearbeiten]

Im Maintenance-System[Bearbeiten]

  • Will man (einmalig) direkt in Maintenance-System booten, kann man auch die Passphrase absichtlich mehrfach falsch eingeben oder den Parameter im Bootmenü ändern.
  • Will man im Maintenance-System auf die verschlüsselten Dateisysteme zugreifen, so muss man /dev/ad0s2 manuell attachen:
# geli attach /dev/ad0s2
(Passphrase eingeben)

Auf der Konsole werden hier alle Filesysteme angezeigt, die auf ad0s2 liegen, diese können wir normale Filesysteme verwendet werden.

Im Normalsystem[Bearbeiten]

  • Will man das Maintenance-System bearbeiten, so kann das einfach gemountet werden:
# mount /dev/ad0s1a /mnt
Wichtig
Bei einem Update muss ad0s1a:/boot manuell aktualisiert werden, d.h. nach "make installkernel" ist folgendes zu tun:
(in /usr/src)
# make installkernel
# mount /dev/ad0s1a /mnt
# cpdup /boot/kernel/ /mnt/boot/kernel/
Wichtig
jegliche Bootkonfiguration muss auf ad0s1a:/boot stattfinden, denn ad0s2.elia:/boot wird nicht verwendet. Es bietet sich daher an, dieses als Sicherheitskopie zu verwenden:
# mount /dev/ad0s1a /mnt
# cpdup /mnt/boot/ /boot/

Weblinks[Bearbeiten]