Schlagwort-Archive: LUKS

LVM: Logical Volumes (LV) in andere Volume Group (VG) verschieben und andere Arbeiten

Der folgende Text dient mir als Dokumentation. Ich halte darin fest, wie ich LVs von einer VG in eine andere VG verschiebe und die Partitionstabelle der Festplatte mit der Quell-VG bearbeite. Der Verschiebe-Vorgang setzt sich dabei aus den zwei Vorgängen Kopieren und Löschen zusammen.

Der Text mag euch unterhalten und ggf. könnt ihr darauf zurückgreifen, wenn ihr ähnliche Arbeiten an euren Linux-Dateisystemen plant. Euch erwartet jedoch kein Tutorial, das in einzelne Themen oder Programme einführt. Falls ihr von hieran weiterlest, wünsche ich euch viel Spaß mit dem Text.

Ausgangslage

Es geht um meinen Desktop-PC. Dieser besitzt neben einer Geschichte auch einige Altlasten. Nun ist mir meine /boot-Partition zu klein. Da der Platz hinter der Partition jedoch von einer LUKS-verschlüsselten Partition mit LVM belegt ist, muss ich hier erst Platz schaffen, um die /boot-Partition vergrößern zu können.

Folgender Code-Block gibt einen Überblick über die Block-Geräte meines PCs, die darauf befindlichen Partitionen sowie deren Einhängepunkte in /etc/fstab und /etc/crypttab. Identifizierende Merkmale wie UUIDs wurden gekürzt, verändert oder Platzhalter an ihrer Stelle verwendet.

$ lsblk
NAME                          MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
sda                             8:0    0 931,5G  0 disk  
└─sdb_crypt                   253:4    0 931,5G  0 crypt 
  └─tower--pc--vg2-lv--images 253:5    0   360G  0 lvm   /var/lib/libvirt/images
sdb                             8:16   0 238,5G  0 disk  
├─sdb1                          8:17   0   243M  0 part  /boot
├─sdb2                          8:18   0     1K  0 part  
└─sdb5                          8:21   0 238,2G  0 part  
  └─sda5_crypt                253:0    0 238,2G  0 crypt 
    ├─tower--pc--vg-root      253:1    0  27,9G  0 lvm   /
    ├─tower--pc--vg-swap_1    253:2    0     4G  0 lvm   [SWAP]
    └─tower--pc--vg-home      253:3    0 204,3G  0 lvm   /home
sr0

$ cat /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
/dev/mapper/tower--pc--vg-root /               ext4    errors=remount-ro 0       1
# /boot was on /dev/sda1 during installation
UUID=a3809eb1-fc3d191e2ae9 /boot           ext2    defaults        0       2
/dev/mapper/tower--pc--vg-home /home           ext4    defaults        0       2
/dev/mapper/tower--pc--vg-swap_1 none            swap    sw              0       0
/dev/sr0        /media/cdrom0   udf,iso9660 user,noauto     0       0

# 1 TB SSD SANDisk
/dev/mapper/tower--pc--vg2-lv--images	/var/lib/libvirt/images	ext4	defaults	0	0

$ cat /etc/crypttab 
sda5_crypt UUID=07f0d6c5-257591190166 none luks,discard
sdb_crypt UUID="e605980c-307daf28b717" none luks,discard

$ sudo blkid
/dev/sdb1: UUID="a3809eb1-fc3d191e2ae9" BLOCK_SIZE="1024" TYPE="ext2" PARTUUID="6ee39e6a-01"
/dev/sdb5: UUID="07f0d6c5-257591190166" TYPE="crypto_LUKS" PARTUUID="6ee39e6a-05"
/dev/sda: UUID="e605980c-307daf28b717" TYPE="crypto_LUKS"
/dev/mapper/sda5_crypt: UUID="AZKTuQ-rVeB5S" TYPE="LVM2_member"
/dev/mapper/tower--pc--vg-root: UUID="be0ff8fd-7aee7ce75f3b" BLOCK_SIZE="4096" TYPE="ext4"
/dev/mapper/tower--pc--vg-swap_1: UUID="90823267-b6828aeca9b9" TYPE="swap"
/dev/mapper/tower--pc--vg-home: UUID="d410241d-04214b690522" BLOCK_SIZE="4096" TYPE="ext4"
/dev/mapper/sdb_crypt: UUID="Ff4Lt0-RKJrGd" TYPE="LVM2_member"
/dev/mapper/tower--pc--vg2-lv--images: UUID="3af3b461-cdd7b2bc9710" BLOCK_SIZE="4096" TYPE="ext4"

Ziel

Mein Ziel ist, die /boot-Partition auf 2 GB zu vergrößern, ohne das System neuinstallieren zu müssen oder die Daten in den vorhandenen Partitionen zu verlieren.

Mögliche Vorgehensweisen

Bei meiner Internet-Recherche bin ich auf folgende Lösungsmöglichkeiten gestoßen:

Wenn man diese Diskussionen und den Wiki-Artikel liest, erkennt man, dass es mehrere Wege zum Ziel gibt. Ich habe mich für folgendes Vorgehen entschieden, da es auf mich den Eindruck macht, unkompliziert zu sein und nur ein geringes Risiko für Datenverlust birgt:

  1. Datensicherung
  2. LUKS-Devices umbenennen
  3. LV und Dateisystem der /home-Partition verkleinern
  4. Neue LVs in zweiter VG erstellen
  5. Partitionen mit partclone kopieren
  6. Grub Neukonfigurieren (2x)

Schritt 1: Datensicherung durchführen

Bevor ich irgendwelche Änderungen an der Partitionstabelle von /dev/sdb durchführe, erstelle ich eine Datensicherung. Dazu verwende ich die freie Software Clonezilla, um die Partitionen von /dev/sdb in eine Image-Datei auf einer externen Festplatte zu sichern.

Das Programm ist einfach in der Bedienung und ermöglicht mir im Fehlerfall, die Partitionen der zu bearbeitenden Festplatte wiederherzustellen.

Schritt 2: LUKS-Devices umbenennen

Im IST-Zustand befindet sich das LUKS-Device sdb_crypt auf dem Gerät /dev/sda, während sich sda5_crypt auf dev/sdb5 befindet. Dies ist unschön und lässt sich wie folgt ändern:

root:~# dmsetup rename sda5_crypt sd_temp
root:~# dmsetup rename sdb_crypt sda5_crypt
root:~# dmsetup rename sd_temp sdb_crypt

Nun wird die Datei /etc/crypttab entsprechend angepasst (vgl. mit IST-Zustand):

root:~# cat /etc/crypttab 
sdb_crypt UUID=07f0d6c5-257591190166 none luks,discard
sda5_crypt UUID="e605980c-307daf28b717" none luks,discard

Damit die Partitionen beim Start des Rechners korrekt entschlüsselt und eingebunden werden, wird abschließend initramfs aktualisiert:

root:~# update-initramfs -u -k all
update-initramfs: Generating /boot/initrd.img-5.10.0-15-amd64
update-initramfs: Generating /boot/initrd.img-5.10.0-13-amd64

Nach einem Neustart ergibt sich das gewünschte Bild:

$ lsblk
NAME                          MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
sda                             8:0    0 931,5G  0 disk  
└─sda5_crypt                  253:4    0 931,5G  0 crypt 
  └─tower--pc--vg2-lv--images 253:5    0   360G  0 lvm   /var/lib/libvirt/images
sdb                             8:16   0 238,5G  0 disk  
├─sdb1                          8:17   0   243M  0 part  /boot
├─sdb2                          8:18   0     1K  0 part  
└─sdb5                          8:21   0 238,2G  0 part  
  └─sdb_crypt                 253:0    0 238,2G  0 crypt 
    ├─tower--pc--vg-root      253:1    0  27,9G  0 lvm   /
    ├─tower--pc--vg-swap_1    253:2    0     4G  0 lvm   [SWAP]
    └─tower--pc--vg-home      253:3    0 204,3G  0 lvm   /home

Schritt 3: LV und Dateisystem der /home-Partition verkleinern

Meine /home-Partition ist mir mit 204 GB etwas groß geraten. Daher möchte ich sie um 100 GB verkleinern. Um das Dateisystem verkleinern zu können, darf die Partition nicht eingehängt sein. Um die folgenden Schritte durchzuführen, nutze ich diesmal das Linux-System System Rescue. Dabei handelt es sich um ein Live-System, mit jeder Menge Werkzeugen, um einen (beschädigten) Rechner zu bearbeiten.

Der folgende Code-Block zeigt, wie zuerst das verschlüsselte LUKS-Device geöffnet und anschließend das LV der /home-Partition verkleinert wird. Der dabei verwendete Befehl führt die Verkleinerung des Dateisystems und des LV in einem Schritt aus:

# LUKS-Device öffnen
# cryptsetup open <device> <name> --type <device_type> see cryptsetup(8)

root@sysrescue ~]# cryptsetup open /dev/sda5 crypt_disk --type luks2
Enter passphrase for /dev/sda5: 
[root@sysrescue ~]# lsblk
NAME                       MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
loop0                        7:0    0 647.7M  1 loop  /run/archiso/sfs/airootfs
sda                          8:0    0 238.5G  0 disk  
├─sda1                       8:1    0   243M  0 part  
├─sda2                       8:2    0     1K  0 part  
└─sda5                       8:5    0 238.2G  0 part  
  └─crypt_disk             254:0    0 238.2G  0 crypt 
    ├─tower--pc--vg-root   254:1    0  27.9G  0 lvm   
    ├─tower--pc--vg-swap_1 254:2    0     4G  0 lvm   
    └─tower--pc--vg-home   254:3    0 204.3G  0 lvm   
sdb                          8:16   0 931.5G  0 disk

# Dateisystem und LV in einem Schritt verkleinern
# Aufgrund der gewählten Größe dauert dieser Vorgang einige Minuten
# lvresize --size [+|-]Size[m|UNIT] --resizefs <lv name> see lvresize(8)

[root@sysrescue ~]# lvresize --size -100G --resizefs /dev/tower-pc-vg/home 
fsck from util-linux 2.38
/dev/mapper/tower--pc--vg-home: Inode 393223 extent tree (at level 1) could be narrower.  IGNORED.
/dev/mapper/tower--pc--vg-home: Inode 12847282 extent tree (at level 1) could be narrower.  IGNORED.
/dev/mapper/tower--pc--vg-home: 20959/13393920 files (1.2% non-contiguous), 14367863/53551104 blocks
resize2fs 1.46.5 (30-Dec-2021)
Resizing the filesystem on /dev/mapper/tower--pc--vg-home to 27336704 (4k) blocks.
The filesystem on /dev/mapper/tower--pc--vg-home is now 27336704 (4k) blocks long.

  Size of logical volume tower-pc-vg/home changed from 204.28 GiB (52296 extents) to 104.28 GiB (26696 extents).
  Logical volume tower-pc-vg/home successfully resized.

[root@sysrescue ~]# lsblk
NAME                       MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
loop0                        7:0    0 647.7M  1 loop  /run/archiso/sfs/airootfs
sda                          8:0    0 238.5G  0 disk  
├─sda1                       8:1    0   243M  0 part  
├─sda2                       8:2    0     1K  0 part  
└─sda5                       8:5    0 238.2G  0 part  
  └─crypt_disk             254:0    0 238.2G  0 crypt 
    ├─tower--pc--vg-root   254:1    0  27.9G  0 lvm   
    ├─tower--pc--vg-swap_1 254:2    0     4G  0 lvm   
    └─tower--pc--vg-home   254:3    0 104.3G  0 lvm   
sdb                          8:16   0 931.5G  0 disk

Zur Sicherheit führe ich noch eine Dateisystemüberprüfung aus:

[root@sysrescue ~]# fsck -t ext4 /dev/mapper/tower--pc--vg-home
fsck from util-linux 2.38
e2fsck 1.46.5 (30-Dec-2021)
/dev/mapper/tower--pc--vg-home: clean, 20959/6840320 files, 13956503/27336704 blocks

Da alles in Ordnung ist, fahre ich mit dem nächsten Schritt fort. Dazu nutze ich weiterhin die System Rescue Umgebung.

Schritt 4: LVs in zweiter VG erstellen

Da ich für die folgenden Vorgänge Zugriff auf die zweite VG benötige, öffne ich zuerst das LUKS-Device, in dem sich diese befindet:

[root@sysrescue ~]# cryptsetup open /dev/sdb crypt_disk2 --type luks2

Nun erstelle ich drei neue LVs, welche den Inhalt der existierenden LVs root, swap_1 und home aufnehmen sollen. Die Ziel-LVs müssen dazu mindestens gleich groß oder größer als die Quell-LVs sein. Um die erforderliche Größe zu ermitteln, lasse ich mir die Größe der Quell-LVs in Byte anzeigen. Ich wähle bewusst die Einheit Byte, da die Ausgabe bei größeren Einheiten auf zwei Nachkommastellen gerundet wird und ich mir keine Probleme durch die Rundung einhandeln möchte.

# Es werden nur die relevanten Informationen wiedergegeben
root:~# lvdisplay --unit b
LV Path                /dev/tower-pc-vg/root
LV Name                root
VG Name                tower-pc-vg
...
LV Size                29997662208 B
-----
LV Path                /dev/tower-pc-vg/swap_1
LV Name                swap_1
VG Name                tower-pc-vg
...
LV Size                4290772992 B
-----
LV Path                /dev/tower-pc-vg/home
LV Name                home
VG Name                tower-pc-vg
...
LV Size                111971139584 B

Mit diesen Informationen erstelle ich die neuen LVs in der zweiten VG:

:~# lvcreate --size 29997662208B /dev/tower-pc-vg2 --name root
  Logical volume "root" created.
:~# lvcreate --size 4290772992B /dev/tower-pc-vg2 --name swap_1
  Logical volume "swap_1" created.
:~# lvcreate --size 111971139584B /dev/tower-pc-vg2 --name home
  Logical volume "home" created.

Schritt 5: Partitionen mit partclone kopieren

Für diesen Schritt nutze ich die freie Anwendung Partclone. Da meine LVs weiterhin ausgehängt sind, muss ich mir um Schreib-Zugriffe anderer Prozesse während des Kopiervorgangs keine Sorgen machen:

# Manpage partclone(8)
# partclone.<fs_type> --dev-to-dev --source <Quelle> --output <Ziel>

[root@sysrescue ~]# partclone.ext4 --dev-to-dev --source /dev/tower-pc-vg/root --output /dev/tower-pc-vg2/root 
Partclone v0.3.20 http://partclone.org
Starting to back up device(/dev/tower-pc-vg/root) to device(/dev/tower-pc-vg2/root)
Elapsed: 00:00:01, Remaining: 00:00:00, Completed: 100.00%                      
Total Time: 00:00:01, 100.00% completed!
done!
File system:  EXTFS
Device size:   30.0 GB = 7323648 Blocks
Space in use:  20.8 GB = 5078551 Blocks
Free Space:     9.2 GB = 2245097 Blocks
Block size:   4096 Byte
Elapsed: 00:03:16, Remaining: 00:00:00, Completed: 100.00%, Rate:   6.37GB/min, 
current block:    7323648, total block:    7323648, Complete: 100.00%           
Total Time: 00:03:16, Ave. Rate:    6.4GB/min, 100.00% completed!
Syncing... OK!
Partclone successfully cloned the device (/dev/tower-pc-vg/root) to the device (/dev/tower-pc-vg2/root)
Cloned successfully.

[root@sysrescue ~]# partclone.ext4 --dev-to-dev --source /dev/tower-pc-vg/home --output /dev/tower-pc-vg2/home 
Partclone v0.3.20 http://partclone.org
Starting to back up device(/dev/tower-pc-vg/home) to device(/dev/tower-pc-vg2/home)
Elapsed: 00:00:01, Remaining: 00:00:00, Completed: 100.00%                      
Total Time: 00:00:01, 100.00% completed!
done!
File system:  EXTFS
Device size:  112.0 GB = 27336704 Blocks
Space in use:  57.2 GB = 13956503 Blocks
Free Space:    54.8 GB = 13380201 Blocks
Block size:   4096 Byte
Elapsed: 00:12:22, Remaining: 00:00:00, Completed: 100.00%, Rate:   4.62GB/min, 
current block:   27336704, total block:   27336704, Complete: 100.00%           
Total Time: 00:12:22, Ave. Rate:    4.6GB/min, 100.00% completed!
Syncing... OK!
Partclone successfully cloned the device (/dev/tower-pc-vg/home) to the device (/dev/tower-pc-vg2/home)
Cloned successfully.

Die SWAP-Partition enthält keine Daten, die kopiert werden müssen. Hier formatiere ich das neue LV einfach als SWAP-Partition:

[root@sysrescue ~]# mkswap /dev/tower-pc-vg2/swap_1
Setting up swapspace version 1, size = 4 GiB (4290768896 bytes)
no label, UUID=f9181521-a06da5b8ade5

Schritt 6: Grub neukonfigurieren (2x)

An diesem Punkt habe ich meinen Rechner normal gestartet, um zu überprüfen, dass er wie gewohnt hochfährt. Die gute Nachricht lautet: „Er ist wie gewohnt gestartet.“

Nun verfüge ich über ein Clonezilla-Image der ersten Festplatte, dessen Wiederherstellbarkeit ich noch nicht durch Restore validiert habe und über die Kopien meiner Partitionen in der zweiten VG. Starten tut mein Rechner jedoch immer noch von den altbekannten Partitionen, da ich der Grub-Konfiguration noch nicht mitgeteilt habe, dass ein Wurzeldateisystem aus einer anderen Partition zu verwenden ist.

Leider habe ich es versäumt, mir während der Nutzung der System-Rescue-Umgebung Notizen zu machen. Daher kann ich die verwendeten Befehle an dieser Stelle nur unvollständig wiedergeben. Es ist mir jedoch gelungen, vom Wurzeldateisystem in /dev/tower-pc-vg2/root zu starten. Dies sieht man z.B. in der Ausgabe von lsblk:

:~$ lsblk
NAME                          MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
sda                             8:0    0 931,5G  0 disk  
└─sda5_crypt                  253:0    0 931,5G  0 crypt 
  ├─tower--pc--vg2-lv--images 253:1    0   360G  0 lvm   /var/lib/libvirt/images
  ├─tower--pc--vg2-root       253:2    0  27,9G  0 lvm   /
  ├─tower--pc--vg2-swap_1     253:3    0     4G  0 lvm   [SWAP]
  └─tower--pc--vg2-home       253:4    0 104,3G  0 lvm   /home
sdb                             8:16   0 238,5G  0 disk  
├─sdb1                          8:17   0     2G  0 part  /boot
├─sdb2                          8:18   0     1K  0 part  
└─sdb5                          8:21   0 234,2G  0 part  
  └─sdb_crypt                 253:5    0 234,2G  0 crypt 
    ├─tower--pc--vg-root      253:6    0  27,9G  0 lvm   
    ├─tower--pc--vg-swap_1    253:7    0     4G  0 lvm   
    └─tower--pc--vg-home      253:8    0 104,3G  0 lvm   
sr0

Wer den Code-Block genau studiert hat, wird festgestellt haben, dass meine /boot-Partition gegenüber dem Eingangs erwähnten IST-Zustand auf 2 GB angewachsen ist. Ich habe die Partitionstabelle zwischenzeitlich mit GParted bearbeitet, welches in der System-Rescue-Umgebung enthalten ist.

Damit habe ich mein Ziel erreicht. Der Artikel könnte an dieser Stelle enden. Ich möchte jedoch zukünftig wieder die Partitionen von /dev/sdb verwenden. Dazu muss ich nochmals Grub neukonfigurieren, welches ich diesmal in folgendem Code-Block zeige:

root@tower-pc:~# mount /dev/tower-pc-vg/root /mnt

# Die separate /boot-Partition muss ebenfalls mit eingehängt werden
root@tower-pc:~# mount /dev/sdb1 /mnt/boot

root@tower-pc:~# for DEVICE in /dev /dev/pts /proc /sys; do mount --bind $DEVICE /mnt$DEVICE; done
root@tower-pc:~# mount /dev/tower-pc-vg2/lv-images /mnt/var/lib/libvirt/images

# ID der Partition mit dem Wurzeldateisystem ermitteln
root@tower-pc:~# ls -l /dev/tower-pc-vg/root 
lrwxrwxrwx 1 root root 7 18. Jun 20:13 /dev/tower-pc-vg/root -> ../dm-6
root@tower-pc:~# ls -l /dev/disk/by-id/ | grep dm-6
lrwxrwxrwx 1 root root 10 18. Jun 20:13 dm-name-tower--pc--vg-root -> ../../dm-6

# In eine chroot-Umgebung wechseln
root@tower-pc:~# chroot /mnt
root@tower-pc:/# pwd
/

In der chroot-Umgebung wird die Datei /etc/default/grub mit einem Editor geöffnet und die Zeile GRUB_CMDLINE_LINUX_DEFAULT= bearbeitet. Dort trage ich die ID der Partition meines Wurzeldateisystems ein. Die Zeile sieht anschließend wie folgt aus:

GRUB_CMDLINE_LINUX_DEFAULT="root=/dev/disk/by-id/dm-name-tower--pc--vg-root iommu='soft' quiet"

Der folgende Code-Block stellt die Befehle dar, mit denen Grub neukonfiguriert und installiert sowie initramfs aktualisiert wird.

root@tower-pc:/# grub-mkconfig -o /boot/grub/grub.cfg 
Generating grub configuration file ...
Found background image: /usr/share/images/desktop-base/desktop-grub.png
Found linux image: /boot/vmlinuz-5.10.0-15-amd64
Found initrd image: /boot/initrd.img-5.10.0-15-amd64
Found linux image: /boot/vmlinuz-5.10.0-13-amd64
Found initrd image: /boot/initrd.img-5.10.0-13-amd64
Found Debian GNU/Linux 11 (bullseye) on /dev/mapper/tower--pc--vg2-root
done

root@tower-pc:/# update-initramfs -u -k all
update-initramfs: Generating /boot/initrd.img-5.10.0-15-amd64
update-initramfs: Generating /boot/initrd.img-5.10.0-13-amd64
root@tower-pc:/# exit
exit
root@tower-pc:~# reboot NOW

Nach dem Neustart habe ich noch überprüft, dass der Rechner wirklich die ursprünglichen Partitionen eingehängt hat:

$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 931,5G 0 disk
└─sda5_crypt 253:4 0 931,5G 0 crypt
├─tower--pc--vg2-lv--images 253:5 0 360G 0 lvm /var/lib/libvirt/images
├─tower--pc--vg2-root 253:6 0 27,9G 0 lvm
├─tower--pc--vg2-swap_1 253:7 0 4G 0 lvm
└─tower--pc--vg2-home 253:8 0 104,3G 0 lvm
sdb 8:16 0 238,5G 0 disk
├─sdb1 8:17 0 2G 0 part /boot
├─sdb2 8:18 0 1K 0 part
└─sdb5 8:21 0 234,2G 0 part
└─sdb_crypt 253:0 0 234,2G 0 crypt
├─tower--pc--vg-root 253:1 0 27,9G 0 lvm /
├─tower--pc--vg-swap_1 253:2 0 4G 0 lvm [SWAP]
└─tower--pc--vg-home 253:3 0 104,3G 0 lvm /home
sr0 11:0 1 1024M 0 rom

Ende gut alles gut

Operation gelungen. Patient rechnet noch.

Mein Ziel habe ich erreicht und als Bonus Grub so konfiguriert, dass wieder meine ursprünglichen Partitionen verwendet werden. Die LVs in VG2 behalte ich vorerst. Sie stören nicht und ich kann die dortige Installation ebenfalls booten. Diese kann ich evtl. noch für zukünftige Experimente hernehmen.

Mir gefällt, dass ich frei verfügbare Informationen und Werkzeuge benutzen konnte, um alle notwendigen Aufgaben zu erledigen. So habe ich wieder einiges dazugelernt. Dies ist einer der Gründe, weshalb mir Freie Software und Open Source so gut gefallen.

Nun werde ich diesen Text noch verschlagworten, damit ich ihn in einer fernen Zukunft auch wiederfinde.

Network Bound Disk Encryption im Überblick

In diesem Artikel gebe ich euch einen Überblick, was Network Bound Disk Encryption (NBDE) ist und beschreibe einen konkreten Anwendungsfall. Am Ende des Artikels führe ich einige Verweise auf, mit deren Hilfe ihr NBDE bei Interesse selbst implementieren könnt.

Linux Unified Key Setup (LUKS)

Bevor ich auf NBDE eingehe, möchte ich kurz ein paar Worte zu LUKS verlieren.

Bei LUKS handelt es sich um das Standardverfahren zur Festplattenverschlüsselung unter Linux (siehe 1). Dieses erweitert dm-crypt um einen Header, welcher Slots zum Speichern von bis zu acht Schlüsseln bietet (siehe 2).

Ich benutze dieses Verfahren auf nahezu all meinen Rechnern. Ich möchte damit erreichen, dass meine Daten bei Diebstahl des Rechners bzw. der Festplatte möglichst lange vor unberechtigtem Zugriff geschützt sind.

Typischerweise wird zur Entschlüsselung einer Festplatte bzw. Partition während des Boot-Vorgangs die Eingabe eines Kennworts benötigt. Die Sicherheit des Verfahrens hängt dabei direkt von der Stärke des verwendeten Passworts ab (siehe 1).

Steht der Rechner im Büro und man ist täglich vor Ort, ist es kein Problem, bei Neustart des Rechners das LUKS-Kennwort einzugeben. Wenn man allerdings im Homeoffice arbeitet und Zugriff auf seinen Büro-Rechner braucht, sieht die Sache anders aus.

Möchte man den entfernten Rechner neustarten, z.B. nach der Installation von Updates, muss man dafür extra ins Büro fahren. Alternativ kann man ein zweites Kennwort einrichten, dieses einem Kollegen mitteilen und diesen bitten, es vor Ort einzugeben. Beides ist nicht komfortabel. Und hier kommt NBDE ins Spiel.

LUKS an Netzwerkressource binden

Network Bound Disk Encryption heißt auf Deutsch in etwa netzwerkgebundene Festplattenverschlüsselung und bedeutet, dass die Verschlüsselung an eine oder mehrere Ressourcen im Netzwerk gebunden ist.

Das Prinzip ist ganz einfach. Wenn ein Rechner mit einer verschlüsselten Festplatte oder Partition startet, sucht er nach einer bestimmten Ressource im Netzwerk. Kann der Rechner diese Netzwerkressource erreichen, wird die Festplatte bzw. Partition entschlüsselt und der Startvorgang fortgesetzt. Folgende Abbildung soll dies veranschaulichen.

nbde-network
Clevis-Client und Tang-Server zur Nutzung von NBDE im LAN

Im eigenen LAN werden zwei sogenannte Tang-Server positioniert (siehe 4 und 6). Diese stellen die Netzwerk-Ressource dar, welche erreichbar sein muss, damit ein an Tang gebundenes Gerät entschlüsselt werden kann. In diesem Beispiel werden zwei Tang-Server betrieben, um die Verfügbarkeit des Dienstes zu gewährleisten, wenn ein Server gewartet wird.

Auf dem Client kommt die Anwendung Clevis zum Einsatz (siehe 5, 6 und 7), bei welcher es sich um die Client-Komponente zum Tang-Server handelt. Diese empfängt einen Schlüssel vom Tang-Server und verwendet diesen, um einen Token in einem LUKS-Slot zu speichern (Details siehe 3, 6 und 7). Beim Start eines Rechners wird nun versucht, einen der Tang-Server zu erreichen, an die man sich gebunden hat.

Wird der Rechner bzw. seine Festplatte gestohlen, sind die Tang-Server nicht erreichbar und die Daten werden nicht automatisch entschlüsselt. Der Dieb muss nun die Verschlüsselung bzw. das verwendete Kennwort brechen.

Steht der Rechner jedoch an seinem Platz, kann er aus der Ferne neugestartet werden und den Startvorgang beenden, ohne dass jemand vor Ort ein LUKS-Kennwort eingeben muss.

Damit diese Konfiguration Sinn macht, dürfen die Tang-Server nicht weltweit erreichbar sein. Ihr Standort und die Netze, aus denen sie erreichbar sind, sind daher sorgfältig zu planen.

Zusammenfassung

Ohne NBDE muss an einem Rechner mit LUKS-Verschlüsselung bei jedem Startvorgang das LUKS-Kennwort eingegeben werden, was einen Neustart aus der Ferne enorm erschwert.

NBDE ist leicht zu implementieren und löst dieses Problem. Gleichzeitig bleiben die Daten im gleichen Maße bei einem Diebstahl des Rechners geschützt.

  1. LUKS im Wiki von Ubuntuusers.de. URL: https://wiki.ubuntuusers.de/LUKS/
  2. https://de.wikipedia.org/wiki/Dm-crypt#LUKS
  3. Automatic data encryption and decryption with Clevis and Tang. ADMIN 43/2018. URL: https://www.admin-magazine.com/Archive/2018/43/Automatic-data-encryption-and-decryption-with-Clevis-and-Tang
  4. https://github.com/latchset/tang
  5. https://github.com/latchset/clevis
  6. RHEL 8 Security Hardening Chapter 12. Configuring automated unlocking of encrypted volumes using policy-based decryption. URL: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/security_hardening/configuring-automated-unlocking-of-encrypted-volumes-using-policy-based-decryption_security-hardening
  7. RHEL 7 Security Guide 4.10.1. Network-Bound Disk Encryption. URL: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-policy-based_decryption#sec-Using_Network-Bound_Disk_Encryption
  8. How to set up Network-Bound Disk Encryption with multiple LUKS devices (Clevis+Tang unlocking). URL: https://access.redhat.com/articles/4500491. (Login erforderlich)

Datenträger unter Linux mit cryptsetup (LUKS) verschlüsseln

Ihr möchtet einen Datenträger wie z.B. eine Festplatte oder einen USB-Stick verschlüsseln, damit bei einem Verlust des Datenträgers nicht jeder ohne weiteres Zutun eure Daten lesen kann? Dann haben wir ein gemeinsames Ziel!

Im Folgenden beschreibe ich, wie unter Linux mit Hilfe des Programms cryptsetup eine Festplatte verschlüsselt werden kann. Dazu gehört die Beschreibung, wie das verschlüsselte Gerät anschließend zur Nutzung geöffnet wird und wie man es in die /etc/crypttab einträgt, um das Gerät automatisch beim Start des Rechners zu öffnen. Es handelt sich dabei um eine zusätzliche Festplatte. Wie die erste Festplatte eines Systems verschlüsselt werden kann ist hingegen nicht Gegenstand dieses Artikels. Hier hilft (hoffentlich) ein Blick in die Installationsanleitung der jeweiligen Linux-Distribution weiter.

Das Programm cryptsetup ist in allen gängigen Linux-Distributionen verfügbar. Falls nicht, kann es direkt von der Projekt-Homepage auf GitLab bezogen werden. Die hier gezeigten Kommandos funktionieren prinzipiell auf jedem Linux-System, auf dem cryptsetup verfügbar ist.

Bevor es losgeht noch ein Hinweis. Ich möchte ein verschlüsseltes Gerät erstellen, mit dem Ziel, dass nicht jeder die Daten einfach lesen kann, dem das Gerät in die Hände fällt. Dabei denke ich an Szenarien wie Verlust, Diebstahl, Verkauf etc. Die Daten vor dem Zugriff durch Sicherheitsbehörden, Geheimdiensten oder Schurkenstaaten zu schützen erfordert einen deutlichen höheren Aufwand und ist nicht Gegenstand dieses Artikels.

Ich verwende im Folgenden LUKS2. Wer stattdessen lieber dm-crypt verwendet, sei auf die Manpage cryptsetup(8) verwiesen.

Die zu verschlüsselnde Festplatte wird in diesem Tutorial als /dev/sdX bezeichnet. Dieser Bezeichner muss auf das tatsächlich zu nutzende Gerät angepasst werden. Wichtig: Wird versehentlich das falsche Gerät verschlüsselt gehen vorhandene Daten unwiederbringlich verloren!

LUKS-Container erstellen

Zur Erstellung eines LUKS-Containers wird der folgende Befehl ausgeführt und die Bildschirmanweisungen befolgt. Für die dabei abgefragte Passphrase gilt grundsätzlich: „Je länger und komplizierter, desto sicherer. Wobei es mehr auf die Länge als die Komplexität ankommt.“

Weitere Hinweise zur Passwort-Sicherheit bietet der Wikipedia-Artikel zu Passsatz.

$ sudo cryptsetup luksFormat --type luks2 /dev/sdX
WARNING: Device /dev/sdX already contains a 'dos' partition signature.

WARNING!
========
This will overwrite data on /dev/sdX irrevocably.

Are you sure? (Type uppercase yes): YES
Enter passphrase for /dev/sdX: 
Verify passphrase:

Hinzufügen einer Backup-Passphrase

LUKS-Passphrasen werden in sogenannten Key-Slots gespeichert. Bei LUKS2 stehen 32 Key-Slots zur Verfügung, welche von 0-31 nummeriert sind. Bei LUKS1 waren es 8 Key-Slots. Die Passphrase aus dem vorigen Abschnitt wurde in Slot 0 gespeichert.

Vergisst man die Passphrase, wird der Key-Slot oder der LUKS-Header beschädigt, ist ein Zugriff auf die Daten nicht mehr möglich. Um mich gegen die ersten beiden Fälle abzusichern, erstellte ich zwei Backup-Passphrasen, welche ich in den Key-Slots 3 und 8 speicherte. Wie man sich gegen den Verlust des LUKS-Headers schützt, beschreibe ich im folgenden Abschnitt.

$ # Hinzufügen der ersten Backup-Passphrase in Key-Slot 3
$ sudo cryptsetup luksAddKey /dev/sdX --key-slot 3
Enter any existing passphrase: 
Enter new passphrase for key slot: 
Verify passphrase:

$ # Hinzufügen der zweiten Backup-Passphrase in Key-Slot 8
$ sudo cryptsetup luksAddKey /dev/sdX --type luks2 --key-slot 8
Enter any existing passphrase: 
Enter new passphrase for key slot: 
Verify passphrase:

Für die Backup-Passphrasen gilt selbstverständlich das im vorangegangenen Abschnitt Beschriebene. Die einzelnen Passphrasen sollten von gleicher Güte sein.

Die Backup-Passphrasen sind an einem sicheren Ort aufzubewahren. Ich verwende dazu bspw. einen Passwort-Tresor (vgl. Sichere Passwörter und wie man sie verwaltet).

LUKS-Header sichern

Nun nützen alle Backup-Passphrasen nichts, wenn der LUKS-Header beschädigt wird. Daher empfehle ich diesen mit Hilfe des folgenden Kommandos in eine Datei zu sichern.

$ sudo cryptsetup luksHeaderBackup /dev/sdX --header-backup-file /var/tmp/luksHeaderBackup_2020-10-18

Die so erstellte Datei ist sicher — am besten offline und vom Datenträger getrennt — aufzubewahren. Mit Hilfe dieser Datei und einer Passphrase, welche bei Erstellung des Backups gültig war, kann ein defekter LUKS-Header und damit der Zugriff auf ein verschlüsseltes Gerät wiederhergestellt werden.

Ändert man im Laufe der Zeit in Key-Slots gespeicherte Passphrasen, löscht alte oder fügt neue hinzu, so ist eine erneute Sicherung des LUKS-Headers sinnvoll und angeraten.

LUKS-Container öffnen und nutzen

Bis jetzt haben wir auf dem Block-Gerät /dev/sdX einen verschlüsselten LUKS-Container erstellt, Backup-Passphrasen hinzugefügt und den LUKS-Header gesichert. Der folgende Code-Block zeigt, wie der LUKS-Container geöffnet und damit nutzbar gemacht wird. Dabei ist sdX_crypt ein Bezeichner, welcher für den Device Mapper verwendet wird. Dieser Bezeichner kann von euch frei gewählt werden.

$ sudo cryptsetup open /dev/sdX sdX_crypt
$ lsblk | grep sdX
sdX              8:16   0 111,8G  0 disk  
└─sdX_crypt    254:3    0 111,8G  0 crypt

Der so geöffnete LUKS-Container kann nun mit einem Dateisystem eurer Wahl formatiert werden. Folgender Code-Block zeigt ein Beispiel für ext4. Dies kann in Abhängigkeit zur Größe des LUKS-Containers einige Zeit dauern.

$ sudo mkfs.ext4 /dev/mapper/sdX_crypt
[...]
$ sudo blkid | grep sdX
/dev/sdX: UUID="Eine-furchbar-lange-UUID" TYPE="crypto_LUKS"
/dev/mapper/sdX_crypt: UUID="Eine-andere-furchbar-lange-UUID" TYPE="ext4"

Man beachte, dass der LUKS-Container direkt mit einem Dateisystem formatiert werden kann. Die Erstellung einer Partition ist nicht erforderlich.

Das erstellte Dateisystem kann anschließend wie gewohnt eingehängt werden.

$ sudo mount /dev/mapper/sdX_crypt /mnt

Mit den folgenden Kommandos wird das Dateisystem wieder ausgehängt und der LUKS-Container verschlossen. Damit liegen die Daten nur noch in verschlüsselter Form vor, bis sie das nächste Mal geöffnet werden.

$ sudo umount /dev/mapper/sdX_crypt
$ sudo cryptsetup close sdX_crypt
$ sudo cryptsetup status sdX_crypt
/dev/mapper/sdX_crypt is inactive.

Verschlüsseltes Dateisystem bei Startvorgang des Rechners öffnen und einhängen

Soll das erstellte Dateisystem /dev/mapper/sdX_crypt bereits beim Start des Rechners eingehängt werden, ist folgende Reihenfolge einzuhalten:

  1. LUKS-Container sdX_crypt mit Hilfe der /etc/crypttab öffnen
  2. Dateisysteme aus /etc/fstab einhängen

Die Einträge in den entsprechenden Dateien sehen in meinem Fall wie folgt aus. In /etc/crypttab wird dabei die UUID des Gerätes /dev/sdX verwendet.

$ sudo cat /etc/crypttab
sdX_crypt UUID="Eine-furchbar-lange-UUID" none luks,discard

$sudo cat /etc/fstab
/dev/mapper/sdX_crypt /mnt ext4 defaults 0 0

Man beachte, dass der Rechner nun den Startvorgang unterbricht und zur Eingabe der Passphrase zum Öffnen des LUKS-Containers auffordert. Anschließend wird der Startvorgang fortgesetzt.

Damit sind wir eigentlich am Ende des Tutorials angelangt. Wie fandet ihr es? War es verständlich genug, um folgen zu können und Eingangs erwähnte Ziele zu erreichen?

Wer noch Zeit und Lust hat, kann gerne weiterlesen. In den folgenden Abschnitten werde ich als Zugabe noch beschreiben, wie man Key-Slots löscht und einen LUKS-Header aus einem Backup wiederherstellt.

Key-Slots löschen

Mit dem folgenden Befehl werden sämtliche Key-Slots des LUKS-Containers gelöscht. Ein Zugriff auf den LUKS-Container ist anschließend nicht mehr möglich. Die Angabe eines Passworts ist nicht erforderlich.

Warnung: Dieser Vorgang kann nicht rückgängig gemacht werden.

$ sudo cryptsetup erase /dev/sdX

WARNING!
========
This operation will erase all keyslots on device /dev/sdb.
Device will become unusable after this operation.

Are you sure? (Type uppercase yes):

Das war’s.

LUKS-Header aus Sicherung wiederherstellen

Und nun halte ich noch fest, wie man einen LUKS-Header und die darin enthaltenen Key-Slots aus einer Datensicherung wiederherstellen kann.

$ sudo cryptsetup luksHeaderRestore /dev/sdX --header-backup-file /tmp/luksHeaderBackup_2020-10-18 

WARNING!
========
Device /dev/sdX already contains LUKS2 header. Replacing header will destroy existing keyslots.

Are you sure? (Type uppercase yes):

Uns schon kann man wieder auf seinen LUKS-Container zugreifen.

Reflexion

Um meine Festplatte zu verschlüsseln und diesen Beitrag zu schreiben, habe ich einige Zeit in der Manpage cryptsetup(8) und auf der Projekt-Seite gelesen. Nur mit der Manpage allein wäre mir eine Nutzung vermutlich erst nach deutlich längerer Zeit gelungen.

Dabei vermisse ich in der Manpage vor allem eine Inhaltsübersicht und Beispiele, mit denen man sich gängige Aufgaben schnell ins Gedächtnis rufen kann. Zwar existiert seit ca. zwei Jahren ein Ticket zur Überarbeitung der Manpage, doch fehlt es bei den am Projekt beteiligten Personen wie so oft an der Zeit. Diese wird primär zur Arbeit am Code genutzt. Für die Dokumentation bleibt keine Zeit übrig.

Aktuell erkundige ich mich auf der Mailling-Liste, wie man am besten dazu beitragen kann, die Manpage zumindest in Teilen zu verbessern. Mal sehen, was sich da machen lässt.

Da man vermutlich nicht täglich mit cryptsetup arbeitet, ist eine gute Dokumentation um so wichtiger, da vermutlich niemand alle notwendigen Befehle dauerhaft im Gedächtnis behält.

Mit diesem Tutorial habe ich mir meine eigene Dokumentation für meine häufigsten Anwendungsfälle geschaffen. Wenn ihr sie ebenfalls nützlich findet, freut mich dies umso mehr.