Partitionierung eines komplett verschlüsselten Linux-Systems

Aus Linupedia
Wechseln zu: Navigation, Suche

Ausgangspunkt ist ein relativ weit verbreitetes Setup, bei welchem beinahe alle Dateisysteme in einem Crypt-Container (komplett 'md1' auf Basis von dm-crypt) liegen und somit ausreichend geschützt zu sein scheinen. Das Partitionierungsdiagramm verdeutlicht die gewählte Konfiguration:

Partitionierung mit einem großen Crypt-Container auf 'md1', aber 'md0' ist unverschlüsselt

Einzige Ausnahme bei diesem Setup ist das Dateisystem '/boot', welches unverschlüsselt auf einer relativ kleinen Partition liegt. Dort liegen:

  • der Boot-Manager GRUB 2
  • die Kernel und InitialRamDisks der installierten Betriebssysteme

Ein solches Setup sichert die Daten im verschlüsselten Bereich gut ab gegen Angriffsszenarien wie Diebstahl oder Verlust der Hardware.


Warum sollte '/boot' geschützt werden?

Sowohl Boot-Loader als auch Kernel scheinen auf den ersten Blick unkritisch, weil sie keine geheimen Daten enthalten. Es gibt aber mindestens zwei Angriffsszenarien, welche über Umwege letztlich zu einer Kompromittierung der eigentlich schützenswerten Daten unter '/home' führen können. Beide führen über eine Trojanisierung des Kernels dazu, dass die Passphrase für die Entschlüsselung des Crypt-Containers abgefangen wird. Hierzu wird der bestehende Kernel unbemerkt ausgetauscht durch eine Version mit bösartiger Zusatzfunktionalität.

Beim nächsten regulären Boot-Vorgang wird dann die vom User eingegebene Passphrase unbemerkt abgegriffen und weiter gegegeben - ab hier sind die Daten im Crypt-Container ungeschützt vor dem Angreifer.

Die Angriffsszenarien:

  • Es besteht physischer Zugriff auf das System ("Evil Maid"). Entsprechend vorbereitet reicht hierfür ein sehr kurzer Zeitraum aus.
  • Start eines unsicheren Betriebssystems in einer Multi-Boot-Umgebung (in diesem Beispiel nicht gegeben). Auf diese Weise ist eine Attacke auch remote möglich.

Details:

Schutzmaßnahmen

/boot auslagern

Ein erster (naiver) Ansatz wäre, die Boot-Partition ebenfalls zu verschlüsseln. Das scheitert aber daran, dass zumindest ein kleiner Bereich prinzipbedingt unverschlüsselt bleiben muss, sonst kann die Software nicht geladen werden. So könnte man zwar möglicherweise mit GRUB 2 den Kernel selbst in einen verschlüsselten Bereich auslagern, aber der Bootloader muss unverschlüsselt bleiben. Das würde das Problem somit nur verlagern und nicht lösen, weil ein Angriff über einen trojanisierten Bootloader den selben Effekt hätte wie mit einem trojanisiertem Kernel.

Dieses grundsätzliche Problem kann allein auf Software-Ebene nicht gelöst werden.

There's no security like physical security

What you have to do is make it so its impossible to edit the kernel. To do so, you have to keep the kernel on you at all
times. No, I dont mean sticking your laptop up your shirt to go to work, I mean installing your kernel and boot loader
onto a USB stick that you can carry around with you around your neck or in your pocket.

Diese Tatsache berücksichtigend, werden Bootloader und Kernel auf einen USB-Stick installiert. Dieser spezielle Boot-Stick wird bei diesen Gelegenheiten verwendet:

  • Boot-Vorgang
  • Suspend-To-Disk
  • Update von GRUB 2 oder Kernel

Ansonsten ist der Stick nicht gemountet und wird an sicherer Stelle aufbewahrt. Die Wirksamkeit dieser Sicherheitmaßnahme wird selbstverständlich durch die Sorgfalt bestimmt, mit der die verwendeten Boot-Sticks gegen unberechtigten Zugriff geschützt werden.

Bei Bedarf (und wenn in Zeiten von 'Prism' noch ausreichendes Vertrauen zu Hardware-Herstellern besteht) kann natürlich auch ein spezieller Boot-Stick mit Hardware-Verschlüsselung verwendet werden.

Partitionierungs-Schema mit ausgelagertem '/boot'-Device (sdc1) - 'md0' ist verschlüsselt

Einschränkungen

Auf den ersten Blick erscheint die Vorgehensweise umständlich und ist in Abhängigkeit von der verwendeten Hardware auch relativ langsam. Im konkreten Fall eines Notebooks fallen diese Kriterien aber im laufenden Betrieb kaum ins Gewicht, insbesondere weil das System relativ selten tatsächlich gebootet wird. Stattdessen kommt sehr häufig 'Suspend-To-RAM (STR)' zum Einsatz, bei welchem ein Bootvorgang nicht notwendig ist.

Hinweis: Suspend-To-RAM (STR) birgt ein gewisses Risiko. Hier wird der Inhalt des RAM aktiv gehalten, was zusätzliche Angriffsvektoren offen hält. Das Risiko besteht auch bei einem laufendem System und ist nicht spezifisch für diese Absicherungsmaßnahme, aber die Verwendung von STR verlängert den Zeitraum, in dem das Risiko besteht. Mehr Sicherheit bietet daher ein sauberer Shutdown oder auch STD.

Hingegen funktioniert ein 'Suspend-To-Disk (STD)' nur, wenn der Boot-Stick gemountet ist. Fehlermeldung, falls das nicht der Fall ist:

2013-07-12T12:15:45.284231+02:00 user-w520 systemd[1]: systemd-hibernate.service: main process exited, code=exited, status=1/FAILURE
2013-07-12T12:15:45.290516+02:00 user-w520 systemd[1]: Failed to start Hibernate.
2013-07-12T12:15:45.290862+02:00 user-w520 systemd[1]: Dependency failed for Hibernate.
2013-07-12T12:15:45.291088+02:00 user-w520 systemd[1]: Job hibernate.target/start failed with result 'dependency'.
2013-07-12T12:15:45.291316+02:00 user-w520 systemd[1]: Service sleep.target is not needed anymore. Stopping.
2013-07-12T12:15:45.291584+02:00 user-w520 systemd[1]: Unit systemd-hibernate.service entered failed state
2013-07-12T12:15:45.291777+02:00 user-w520 systemd[1]: Stopping Sleep.
2013-07-12T12:15:45.291952+02:00 user-w520 systemd[1]: Stopped target Sleep.

Deaktivierung von Firewire

Ein weiteres Angriffsszenario auf den Schlüssel besteht bei lokalem Zugriff über einen Firewire-Anschluss. Dieser soll einen direkten Zugriff auf das RAM und damit auf den Schlüssel ermöglichen. Sicherheitshalber wird Firewire daher deaktiviert:

user-w520:~ # echo "blacklist ieee1394" >> /etc/modprobe.d/50-blacklist.conf
user-w520:~ # echo "blacklist firewire-core" >> /etc/modprobe.d/50-blacklist.conf

Hinweis: Unter Opensuse 12.3 befindet sich out-of-the-box dort schon ein Eintrag:

# If you really need firewire direct networking, then remove this entry
blacklist eth1394

Prozessbeschreibung Systemupdates

  • Während eines Systemupdates von 'grub2' oder 'kernel' muss der Stick gemountet sein (s. Abhängigkeit zum Patch-Prozess).
  • Unmittelbar nach dem Update wird im gecrypteten Bereich ein Image des Sticks als Archiv abgelegt, woraus zu jedem beliebigen Zeitpunkt ein neuer Boot-Stick erzeugt werden kann:
user-w520:~ # today=`date +%Y-%m-%d`; f=/home/user/sys/boot/boot-$today.img; dd if=/dev/sdc of=$f
3915776+0 records in
3915776+0 records out
2004877312 bytes (2.0 GB) copied, 99.6817 s, 20.1 MB/s
Achtung:

Unbedingt die Benennung des richtigen Devices beachten. Die Ausführung von dd auf das falsche Laufwerk kann alle Daten dort zerstören!


  • Es müssen alle (sicher deponierten!) Boot-Sticks aktualisiert werden:
user-w520:~ # dd if=$f of=/dev/sdd
3915776+0 records in
3915776+0 records out
2004877312 bytes (2.0 GB) copied, 625.637 s, 3.2 MB/s

Abschluss:

user-w520:~ # gzip $f

Verlust des Boot-Sticks / Verdacht auf Kompromittierung

Im Notfall (Verlust des Boot-Sticks oder vermutete Kompromittierung) kann ein passender Boot-Stick auf Basis des im gecrypteten Bereich abgelegten Images neu erstellt werden. Hierzu kann ein beliebiges, frisch heruntergeladenes USB-Image einer Live-Distribution zum Booten verwendet werden (checksum prüfen!), welches sowohl dm-crypt als auch lvm unterstützt.

Vorweg: Der Live-Stick von OpenSUSE 12.3 / KDE beherrscht das Mounten des verschlüsselten Bereiches schon out-of-the-box. Hier soll zur Verdeutlichung trotzdem der gesamte Prozess dokumentiert werden. Vorweg werden die Schritte des Live-Sticks zurückgenommen:

linux:/home/linux # losetup --detach loop0
linux:/home/linux # mdadm --stop /dev/md127
mdadm: stopped /dev/md127
linux:/home/linux # losetup -a

Das RAID1 aktivieren:

linux:/home/linux # mdadm --assemble --scan
mdadm: /dev/md0 has been started with 2 drives.
linux:/home/linux # cat /proc/mdstat
Personalities : [raid1] 
md0 : active raid1 sda1[0] sdb1[1]
      488385344 blocks super 1.0 [2/2] [UU]
      bitmap: 0/4 pages [0KB], 65536KB chunk

unused devices: <none>

Cryptbereich entschlüsseln:

linux:/home/linux # losetup -f
/dev/loop0
linux:/home/linux # losetup /dev/loop0 /dev/md0
linux:/home/linux # cryptsetup luksOpen /dev/loop0 md0
Enter passphrase for /dev/md0: 

LVM initialisieren und Mounten:

linux:/home/linux # vgchange -a y
  6 logical volume(s) in volume group "system" now active
linux:/home/linux # lvs
  LV     VG     Attr      LSize   Pool Origin Data%  Move Log Copy%  Convert
  backup system -wi-a---- 100.00g                                           
  home   system -wi-a---- 310.00g                                           
  os1    system -wi-a----  10.00g                                           
  os2    system -wi-a----  10.00g                                           
  os3    system -wi-a----  10.00g                                           
  swap   system -wi-a----  16.00g                                           

linux:/home/linux # mkdir /root/home
linux:/home/linux # mount /dev/mapper/system-home  /root/home

Jetzt kann das archivierte Image auf den Boot-Stick geschrieben werden:

linux:/home/linux # dd if=/root/home/user/sys/boot/boot-2013-07-11.img of=/dev/sdc
3915776+0 records in
3915776+0 records out
2004877312 bytes (2.0 GB) copied, 269.878 s, 7.4 MB/s

linux:/home/linux # umount /root/home
Achtung:

Unbedingt die Benennung des richtigen Devices beachten. Die Ausführung von dd auf das falsche Laufwerk kann alle Daten dort zerstören!


Links