Shrinking an encrypted partition with LVM on LUKS

Whilst experimenting with with encrypted partitions I wanted to shrink an "oversized" LUKS-encrypted partition. I was a bit astonished over the amount of steps required; in all the documentations I read some point was always missing. In addition I als stumbled over the mess of GiB and GB units used in different tools. Safety considerations taking into account the difference are important to avoid data loss. A big trap may be the fact that parted expects an end point on the disk given in GB when resizing. I nearly did it wrong.

Otherwise the sequence of steps described below worked flawlessly in my case. I could reboot the resized root-system enclosed in the encrypted partition after having resized everything. I list up the necessary steps below in a rather brief form, only. I warn beginners: This is dangerous stuff and the risk for a full data loss not only in the partition you want to resize is very high. So, if you want to experiment yourself - MAKE A BACKUP of the whole disk first. Read carefully through the steps before you do anything. If you are unsure about what the commands mean and what consequences they have do some research on the Internet ahead of any practical steps. Likewise in case of trouble or error messages. You should in general be familiar with partitioning, LVM, dm-crypt and LUKS. I take no responsibility for any damage or data loss and cannot guarantee the applicability of the described steps in your situation - you have been warned.

My layout for the main installation was

SSD --> partition 3 --> LUKS --> LVM --> Group "vg1" --> Volume "lvroot" --> ext4 fs

SSD --> partition 3 --> LUKS --> LVM --> Group "vg1" --> Volume "lvswap" --> swap fs

The partition had a size around 104 GiB before shrinking. The filesystem at the top included a bootable root filesystem of 80 GiB in size. The swap volume (2 GiB) helps to demonstrate that shrinking may lead to gaps between logical LVM volumes. We shall shrink the file system, its volume, the volume group and also the encrypted the partition in the end.

In my case I could attach the disk in question to another computer where I performed the resizing operation. If you have just one computer available use a Live System from an USB stick or a DVD. [I recommend always to have a second small bootable installation available on the very same disk of your PC/laptop besides the main installation for daily work :-). This second installation can reside in an encrypted LVM volume (LUKS on LVM), too. It may support administration and save your life one day in case your main installation becomes broken. There you may also keep copies of the LUKS headers and keyfiles ...].

Resizing will be done by a sequence of 14 steps - following the disk layout in reverse order as shown above; i.e. we proceed with resizing from the filesystem to the LVM structure down to the partition.

You open an encrypted partition with LVM on LUKS just as any dm-crypt/LUKS-partition by

cryptsetup open /dev/YOUR_DEVICE... MAPPING-Name

For the mapping name I shall use "cr-ext". Note that closing the encrypted device requires to deactivate the volume groups in the kernel first; in our case

vgchange -a n vg1;
cryptsetup close cr-ext

Otherwise you may not be able to close your device.

Step 1: Get an overview over your block devices

You should use

lsblk

In my case the (external) disk appeared as "/dev/sdg" - the encrypted partition was located on "/dev/sdg3".

Step 2: Open the encrypted partition

cryptsetup open /dev/sdg3 cr-ext

Check that the mapping is done correctly by "la /dev/mapper" (la = alias for "ls -la"). Watch out not only for the "cr-ext"-device, but also for LVM-volumes inside the encrypted partition. They should appear automatically as distinct devices.

Step 3: Get an overview on LVM structure

Use the following standard commands:

pvdisplay
vgdisplay
lvdisplay

"pvdisplay"/"vgdisplay" should show you a PV device "/dev/mapper/cr-ext" with volume group "vg1" (taking full size). If the volume groups are not displayed you may make it available by "vgchange --available y" (see the man pages).

"lvdisplay" should show you the logical volumes consistently with the entries in "/dev/mapper". Note: "lvdisplay" actually shows the volumes as "/dev/vg1/lvroot", whereas the link in "/dev/mapper" includes the name of the volume group: "/dev/mapper/vg1-lvroot". In my case the original size of "lvroot" was 80 GiB and the size of the swap "lvswap" was 2 GiB.

Step 4: Check the integrity of the filesystem

Use fsck:

mytux:~ # fsck /dev/mapper/vg1-lvroot 
fsck from util-linux 2.31.1
e2fsck 1.43.8 (1-Jan-2018)
/dev/mapper/vg1-lvroot: clean, 288966/5242880 files, 2411970/20971520 blocks

The filesystem should be clean. Otherwise run "fsck -f" - and answer the questions properly. "fsck" in write mode should be possible as we have not mounted the filesystem. We avoid doing so throughout the whole procedure.

Step 5: Check physical block size of the filesystem and used space

Use "fdisk -l" to get the logical and physical block sizes

Disk /dev/mapper/vg1-lvroot: 80 GiB, 85899345920 bytes, 167772160 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes 

Use tune2fs -l /dev/mapper/vg1-lvroot to get the number of total blocks (20971520), blocksize (4096) and free blocks (18559550) - in my case :
Total = 85899345920 Bytes = 85 GB = 80 GiB
free = 76019916800 Bytes = 76 GB = 70,8 GiB

If you mount df -h may will show you less available space due to a 5% free limit set => 67G. So, not much space was occupied by my (Opensuse) test installation inside the volume.

Step 6: Plan the reduced volume and filesystem sizes ahead - perform safety and limit considerations

Plan ahead the new diminished size of the LVM-Volume ("lvroot"). Let us say, we wanted 60G instead of the present 80G. Then we must reduce the filesystem [fs] size even more and use a factor of 0.9 => 54G. I stress:

Make the filesystem size at least 10% smaller than the planned logical volume size!

Why is this? There may be a difference for the meaning of "G" for the use of the resize commands: "resize2fs" and the "lvresize". It could be GB or GiB in either case. Have a look into the man pages. This difference is really dangerous! What would be the worst case that could happen? We resize the filesystem in GiB and the volume size in GB - then the volume size would be too small.

So, let us assume that "lvresize" works with GB - then the 60G would correspond to 60 * 1024 * 1000 * 1000 Bytes = 6144000000 Bytes. Assume further that "resize2fs" works with GiB instead. Then we would get 54 * 1024 * 1024 * 1024 Bytes = 57982058496 Bytes. We would still have a reserve! We would potentially through away disk space; however, we shall compensate for it afterwards (see below).

If you believe present man-pages: For "resize2fs" the "size" parameter can actually be given in units of "G" - but internally GiB are used. For "lvresize", however, the situation is unclear.

In addition we have to check the potential reduction range against the already used space! In our case there is no problem (see step 5). However, how far could you maximally shrink if you needed to?
Minimum-consideration: Give the 10 GiB used according to step 5 a good 34% on top. (We always want a free space of 25%). Multiply by a factor of 1.1 to account for potential GB-GiB differences => 15 GiB. This is a rough minimum limit for the minimum size of the filesystem. The logical volume size should again be larger by a factor of 1.1 at least => 16.5 GB.

Having your minimum you think the other way round: You reduce the volume size by something between the 80 GiB and the 16.5 GiB. You set a number - let us say 60 GiB - and then you reduce the filesystem by a factor 0.9 more => 54 GB.

Step 7: Shrink the filesystem

Check first that the fs is unmounted! Otherwise you may run into trouble:

mytux:~ # resize2fs /dev/mapper/vg1-lvroot 60G
resize2fs 1.43.8 (1-Jan-2018)
Filesystem at /dev/mapper/vg1-lvroot is mounted on /mnt2; on-line resizing required
resize2fs: On-line shrinking not supported

So unmount, run fsck again and then resize:

maytux:~ # umount /mnt2
mytux:~ # e2fsck -f /dev/mapper/vg1-lvroot
e2fsck 1.43.8 (1-Jan-2018)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/vg1-lvroot: 288966/5242880 files (0.2% non-contiguous), 2411970/20971520 blocks
mytux:~ # resize2fs /dev/mapper/vg1-lvroot 54G
resize2fs 1.43.8 (1-Jan-2018)
Resizing the filesystem on /dev/mapper/vg1-lvroot to <pre style="padding:8px;"> (4k) blocks.
The filesystem on /dev/mapper/vg1-lvroot is now 14155776 (4k) blocks long.
mytux:~ # e2fsck -f /dev/mapper/vg1-lvroot
e2fsck 1.43.8 (1-Jan-2018)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/vg1-lvroot: 288966/3538944 files (0.3% non-contiguous), 2304043/14155776 blocks

Step 8: Shrink the logical volume

We can use "lvreduce" to resize the LVM volume; the option parameter "L" together with a "size" determines how big the volume will become. [ Note that there is a subtle difference if you give the size with a negative "-" sign! See the man page for the difference!]

mytux:~ # lvreduce -L 60G /dev/mapper/vg1-lvroot 
  WARNING: Reducing active logical volume to 60.00 GiB.
  THIS MAY DESTROY YOUR DATA (filesystem etc.)
Do you really want to reduce vg1/lvroot? [y/n]: y
  Size of logical volume vg1/lvroot changed from 80.00 GiB (20480 extents) to 60.00 GiB (15360 extents).
  Logical volume vg1/lvroot successfully resized.
mytux:~ # 

Hey, we worked in GiB - good to know!

Step 9: Extend the fs to the volume size again

We compensate for the lost space of almost 6 GiB:

mytux:~ # resize2fs /dev/mapper/vg1-lvroot 
resize2fs 1.43.8 (1-Jan-2018)
Resizing the filesystem on /dev/mapper/vg1-lvroot to 15728640 (4k) blocks.
The filesystem on /dev/mapper/vg1-lvroot is now 15728640 (4k) blocks long.

Run gparted to get an overview over the present situation.

Step 10: Check for gaps between the volumes of your LVM volume group

We had a swap volume, too! As we have not changed it there would be a gap now - and indeed:

mytux:~ # pvs -v --segments /dev/mapper/cr-ext
    Wiping internal VG cache
    Wiping cache of LVM-capable devices
  PV                 VG  Fmt  Attr PSize   PFree  Start SSize LV     Start Type   PE Ranges                     
  /dev/mapper/cr-ext vg1 lvm2 a--  103.96g 41.96g     0 15360 lvroot     0 linear /dev/mapper/cr-ext:0-15359    
  /dev/mapper/cr-ext vg1 lvm2 a--  103.96g 41.96g 15360  5120            0 free                                 
  /dev/mapper/cr-ext vg1 lvm2 a--  103.96g 41.96g 20480   512 lvswap     0 linear /dev/mapper/cr-ext:20480-20991
  /dev/mapper/cr-ext vg1 lvm2 a--  103.96g 41.96g 20992  5623            0 free                                 
mytux:~ # 

Now - note the information "/dev/mapper/cr-ext:20480-20991" and use this exactly in "pvmove":

mytux:~ # pvmove --alloc anywhere /dev/mapper/cr-ext:20480-20991
  /dev/mapper/cr-ext: Moved: 0.20%
  /dev/mapper/cr-ext: Moved: 100.00%
mytux:~ # pvs -v --segments /dev/mapper/cr-ext                  
    Wiping internal VG cache
    Wiping cache of LVM-capable devices
  PV                 VG  Fmt  Attr PSize   PFree  Start SSize LV     Start Type   PE Ranges                     
  /dev/mapper/cr-ext vg1 lvm2 a--  103.96g 41.96g     0 15360 lvroot     0 linear /dev/mapper/cr-ext:0-15359    
  /dev/mapper/cr-ext vg1 lvm2 a--  103.96g 41.96g 15360  5632            0 free                                 
  /dev/mapper/cr-ext vg1 lvm2 a--  103.96g 41.96g 20992   512 lvswap     0 linear /dev/mapper/cr-ext:20992-21503
  /dev/mapper/cr-ext vg1 lvm2 a--  103.96g 41.96g 21504  5111            0 free                                 

You may have to apply this several times with the changed position parameters - be careful !!! (Are your backups OK???). Eventually, we have some continuous alignment:

mytux:~ # pvmove --alloc anywhere /dev/mapper/cr-ext:20992-21503
  /dev/mapper/cr-ext: Moved: 1.76%
  /dev/mapper/cr-ext: Moved: 100.00%
mytux:~ # pvs -v --segments /dev/mapper/cr-ext
    Wiping internal VG cache
    Wiping cache of LVM-capable devices
  PV                 VG  Fmt  Attr PSize   PFree  Start SSize LV     Start Type   PE Ranges                     
  /dev/mapper/cr-ext vg1 lvm2 a--  103.96g 41.96g     0 15360 lvroot     0 linear /dev/mapper/cr-ext:0-15359    
  /dev/mapper/cr-ext vg1 lvm2 a--  103.96g 41.96g 15360   512 lvswap     0 linear /dev/mapper/cr-ext:15360-15871
  /dev/mapper/cr-ext vg1 lvm2 a--  103.96g 41.96g 15872 10743            0 free                                 
mytux:~ # 

Step 11: Resize/reduce the physical LVM

"pvresize" works in GiB. We shrink the physical LVM area down to 80G.

mytux:~ # pvresize --setphysicalvolumesize 80G /dev/mapper/cr-ext  
/dev/mapper/cr-ext: Requested size 80.00 GiB is less than real size 103.97 GiB. Proceed?  [y/n]: y
  WARNING: /dev/mapper/cr-ext: Pretending size is 167772160 not 218034943 sectors.
  Physical volume "/dev/mapper/cr-ext" changed
  1 physical volume(s) resized / 0 physical volume(s) not resized
mytux:~ # pvdisplay
....   
  --- Physical volume ---
  PV Name               /dev/mapper/cr-ext
  VG Name               vg1
  PV Size               80.00 GiB / not usable 3.00 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              20479
  Free PE               4607
  Allocated PE          15872
  PV UUID               eFf9we-......
   

Again, we obviously worked in GiB - good.

Step 12: Set new size of the encrypted region

It is disputed whether this step is required. LUKS never registers the size of the encrypted area. However, if you had an active mounted partition ... In our case, I think the step is not required, but .....

"cryptsetup resize" wants blocks as a size unit. We have to calculate a bit again based on the amount of blocks used:

mytux:~ # cryptsetup status cr-ext
/dev/mapper/cr-ext is active.
  type:    LUKS1
  cipher:  aes-xts-plain64
  keysize: 512 bits
  key location: dm-crypt
  device:  /dev/sdg3
  sector size:  512
  offset:  65537 sectors
  size:    218034943 sectors
  mode:    read/write

We have to determine the new size in blocks to reduce the size of the LUKS area. I chose:
185329702 blocks (rounded up) - this corresponds to around 88.4 G; according to our 10% safety rule this should be sufficient.

mytux:~ # cryptsetup -b 185329702 resize cr-ext
mytux:~ # cryptsetup status cr-ext             
/dev/mapper/cr-ext is active.
  type:    LUKS1
  cipher:  aes-xts-plain64
  keysize: 512 bits
  key location: dm-crypt
  device:  /dev/sdg3
  sector size:  512
  offset:  65537 sectors
  size:    185329702 sectors
  mode:    read/write

Step 13: Reduce the size of the physical partition - a pretty scary step!

This is one of the most dangerous steps. And irreversible ... Interestingly, gparted will not let you do a resize. Yast's partitioner allows for it after several confirmations. I use "parted":
But especially with parted you have to be extremely careful - parted expects an end position in GB. This means that to calculate the resulting size correctly you must care for the starting position - it is the difference that counts. Read the man pages and have a look into other resources.

mytux:~ # parted /dev/sdg
GNU Parted 3.2
Using /dev/sdg
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) print                                                            
Model: USB 3.0 (scsi)
Disk /dev/sdg: 512GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt
Disk Flags: 

Number  Start   End     Size    File system  Name     Flags
 1      1049kB  16.8MB  15.7MB               primary  bios_grub
 2      33.6MB  604MB   570MB                primary  boot, esp
 3      604MB   112GB   112GB                primary  legacy_boot, msftdata
 4      291GB   312GB   21.5GB                        lvm
 5      312GB   314GB   2147MB               primary  msftdata

(parted) resizepart 
Partition number? 3                                                       
End?  [112GB]? 89GB                                                       
Warning: Shrinking a partition can cause data loss, are you sure you want to continue?
Yes/No? Yes                                                               
(parted) print      
Model: USB 3.0 (scsi)
Disk /dev/sdg: 512GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt
Disk Flags: 

Number  Start   End     Size    File system  Name     Flags
 1      1049kB  16.8MB  15.7MB               primary  bios_grub
 2      33.6MB  604MB   570MB                primary  boot, esp
 3      604MB   89.0GB  88.4GB               primary  legacy_boot, msftdata
 4      291GB   312GB   21.5GB                        lvm
 5      312GB   314GB   2147MB               primary  msftdata

(parted) q                                                                
Information: You may need to update /etc/fstab.

As you see: We end up with a size of 88.4 GB and NOT 89 GB !!! In addition we shall see in a second that the GB are NOT GiB here! So our safety factor is really important to get close to the aspired 80 GiB.

Step 14: Set new size of the encrypted region

We set back the size of the encryption area to to the full partition size; though not required in our case - it does not harm:

mytux:~ # cryptsetup  resize cr-ext
mytux:~ # cryptsetup status cr-ext
/dev/mapper/cr-ext is active and is in use.
  type:    LUKS1
  cipher:  aes-xts-plain64
  keysize: 512 bits
  key location: dm-crypt
  device:  /dev/sdg3
  sector size:  512
  offset:  65537 sectors
  size:    172582959 sectors
  mode:    read/write

Step 15: Reset the PV size to the full partition size

We use "pvsize" again without any size parameter. The volume group will follow automatically.

mytux:~ # pvresize  /dev/mapper/cr-ext    
  Physical volume "/dev/mapper/cr-ext" changed
  1 physical volume(s) resized / 0 physical volume(s) not resized 
mytux:~ # pvdisplay
...  
  --- Physical volume ---
  PV Name               /dev/mapper/cr-ext
  VG Name               vg1
  PV Size               82.29 GiB / not usable 1000.50 KiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              21067
  Free PE               5195
  Allocated PE          15872
  PV UUID               eFf9we-......
..
mytux:~ # vgdisplay
....
  --- Volume group ---
  VG Name               vg1
  System ID             
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  16
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                2
  Open LV               0
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               82.29 GiB
  PE Size               4.00 MiB
  Total PE              21067
  Alloc PE / Size       15872 / 62.00 GiB
  Free  PE / Size       5195 / 20.29 GiB
  VG UUID               dZakZi-......

Our logical volumes are alive, too, and have the right size.

mytux:~ # lvdisplay
...
  --- Logical volume ---
  LV Path                /dev/vg1/lvroot
  LV Name                lvroot
  VG Name                vg1
  LV UUID                5cDvmf-......
  LV Write Access        read/write
  LV Creation host, time install, 2018-11-06 15:33:52 +0100
  LV Status              available
  # open                 0
  LV Size                60.00 GiB
  Current LE             15360
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     1024
  Block device           254:17
   
  --- Logical volume ---
  LV Path                /dev/vg1/lvswap
  LV Name                lvswap
  VG Name                vg1
  LV UUID                lCU75L-......
  LV Write Access        read/write
  LV Creation host, time install, 2018-11-06 18:21:11 +0100
  LV Status              available
  # open                 0
  LV Size                2.00 GiB
  Current LE             512
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     1024
  Block device           254:18

And:

mytux:~ # pvs -v --segments /dev/mapper/cr-ext
    Wiping internal VG cache
    Wiping cache of LVM-capable devices
  PV                 VG  Fmt  Attr PSize  PFree  Start SSize LV     Start Type   PE Ranges                     
  /dev/mapper/cr-ext vg1 lvm2 a--  82.29g 20.29g     0 15360 lvroot     0 linear /dev/mapper/cr-ext:0-15359    
  /dev/mapper/cr-ext vg1 lvm2 a--  82.29g 20.29g 15360   512 lvswap     0 linear /dev/mapper/cr-ext:15360-15871
  /dev/mapper/cr-ext vg1 lvm2 a--  82.29g 20.29g 15872  5195            0 free                                 

We also check with gparted:

Everything all right!

Step 16: Closing and leaving the encrypted device

mytux:~ # vgchange -a n vg1

  0 logical volume(s) in volume group "vg1" now active
mytux:~ # 
mytux:~ # cryptsetup close cr-ext
mytux:~ # 

Links

https://www.rootusers.com/lvm-resize-how-to-decrease-an-lvm-partition/
https://wiki.archlinux.org/index.php/Resizing_LVM-on-LUKS
https://blog.shadypixel.com/how-to-shrink-an-lvm-volume-safely/
https://unix.stackexchange.com/questions/41091/how-can-i-shrink-a-luks-partition-what-does-cryptsetup-resize-do
LVM-fragmentation
See the discussion in the following link:
https://askubuntu.com/questions/196125/how-can-i-resize-an-lvm-partition-i-e-physical-volume
https://www.linuxquestions.org/questions/linux-software-2/how-do-i-lvm2-defrag-or-move-based-on-logical-volumes-689335/
Introduction into LVM
https://www.tecmint.com/create-lvm-storage-in-linux/
https://www.tecmint.com/extend-and-reduce-lvms-in-linux/

DSGVO, Freelancer, E-Mails und Umzug KVM-virtualisierter Linux-E-Mail-Server auf verschlüsselte Platten/Partitionen – III

Das Thema der vorhergehenden Artikel dieser Serie

DSGVO, Freelancer, E-Mails und Umzug KVM-virtualisierter Linux-E-Mail-Server auf verschlüsselte Platten/Partitionen – I
DSGVO, Freelancer, E-Mails und Umzug KVM-virtualisierter Linux-E-Mail-Server auf verschlüsselte Platten/Partitionen – II

war eine allgemeine Diskussion darüber, warum man sich spätestens nach der DSGVO als Freelancer um Schutzmaßnahmen für E-Mails und um entsprechende vertragliche Vereinbarungen kümmern sollte. Eine reine Verschlüsselung von Transportwegen ist meiner Meinung nach nicht hinreichend; eine Lagerung von Mails in verschlüsselten Dateicontainern ist mit zu vielen Gefahrenpunkten verbunden. An einer Verschlüsselung von Volumes oder Partitionen der mail- und datei-verarbeitenden Systeme führt bei der Aufbewahrung von Mails und Anhängen kein Weg vorbei.

Als Freelancer steht man also womöglich vor der Aufgabe, sowohl den eigenen Mail-Server im LAN als auch Clients zur Mail- und Auftragsbearbeitung auf einen Unterbau aus verschlüsselte Partitionen umzustellen. Als Linuxer, die auf effiziente Ressourcennutzung bedacht sind, greifen wir zur Lösung auf virtualisierte Systeme zurück. Sprich: Meine Reaktion auf die von etlichen Kunden an mich gestellten pauschalen DSGVO-Anforderungen ist, die Auftragsverarbeitung für Kunden nur noch über besonders geschützte virtualisierte Systeme auf verschlüsselten Volumes durchzuführen. Der aufmerksame Leser hat sicher bemerkt, dass dieser Gedanke über die Mail-Verarbeitung hinaus weist.

Ich gehe kurz auf die Grenzen eines solchen Vorgehens ein; anschließend kümmern wir uns (endlich) um den Umzug eines bereits virtualisierten Mailservers auf eine verschlüsselte HD/SSD-Plattform.

Ist Volume- und Partitionsverschlüsselung einer Systeminstallation für Datensicherheit hinreichend?

Der Grundgedanke einer Partitions- oder Volume-Verschlüsselung ist: Nur verschlüsselte Daten sollen über verschiedene Zugriffsschichten Plattencontroller und Magnet- wie Flash-Speicher erreichen; eine vollständige Entschlüsselung von Dateien soll ausschließlich im RAM des Betriebssystems [OS] stattfinden. So schön das sein mag - es hilft nicht, wenn sich jemand bereits unbefugt auf dem System eingenistet hat und munter mitliest:

Die Verschlüsselung von Datenträgern, Partitionen oder Volumes bietet keinen Schutz auf gehackten Systemen. Sie bietet "nur" Schutz gegen unbefugten Zugriff im nicht-entschlüsseltem und/oder nicht-gemountetem Zustand der Volumes also z.B. im heruntergefahrenen Zustand des Systems.

Volume-Verschlüsselung ist also nur eine - wenn auch eine wichtige Maßnahme - zur Ausschaltung bestimmter Risiken. Auch das sollte aus meiner Sicht in einem Vertrag mit einem Auftraggeber festgehalten werden. Natürlich muss man sich u.a. auch um die Integrität der Virtualisierungshosts selbst kümmern - wir reden da aber über Systeme mit einer sehr begrenzten Anzahl an OS-Komponenten, die selbst keine direkte Verbindung zum Internet aufnehmen müssen.

Man erkennt, dass ein vernünftiger DSGVO-bezogener Vertrag zum Schutz personenbezogener und anderer geheim zu haltender Daten im Endeffekt wesentlich mehr beinhalten muss als nur Hinweise auf die Mailbehandlung und zugehörige Krypto-Verfahren für Transport und Lagerung. U.a. wird man eine Begrenzung ein- und aus-gehender Kommunikation von (virtualisierten) Servern und Clients, die bei der Auftragsbearbeitung eingesetzt werden, auf nur sehr wenige erlaubte Adressen im Internet umsetzen müssen. Z.B. gilt: Völlig offene HTTP(S)- / SMTP(S) - / IMAP(S)- oder gar UDP-basierte Kanäle nach außen zu beliebigen Zieladressen sind im Zeitalter von strafbewehrten DSGVO-Verträgen überhaupt keine gute Idee! Zumindest nicht auf denjenigen Server- und Client-Systemen, auf denen man mit geheim zu haltenden Informationen operiert.

Virtuelle KVM/QEMU-Systeme auf verschlüsselten Volumes

Will man aus anderen grundlegenden Risikoerwägungen heraus nicht gleich alle "Volumes" auf allen Systemen im Haus-/Firmen-Netz verschlüsseln, bleibt nur der Weg über virtuelle Maschinen. Das betrifft dann Server- wie Client-Systeme gleichermaßen.

Im Besonderen Linux-E-Mail-Server sind dabei recht komplexe Systeme; eine Neuinstallation der vielen Einzel-Komponenten auf verschlüsselten Platten/Partitionen mag man sich daher wirklich ersparen. Es geht somit um System-Migration. Nachfolgend betrachte ich deshalb den Umzug eines (virtuellen) (E-Mail-) Servers auf einem KVM/QEMU-Host von unverschlüsselten Partitionen/Volumes auf verschlüsselte Volumes.

Ich gebe einige wichtige Befehle am Beispiel eines KVM/QEMU-Hosts unter Opensuse an. Das ist insofern nützlich, weil man hierfür mit YaST allein nicht auskommt und auf die Kommandozeile runter muss. Für einen Umzug voll ausgestatteter virtueller Clients (KVM/QEMU-Linux-Gastsysteme) zur Mail- und Auftragsbearbeitung gelten die Ausführungen dann analog.

Übrigens: Durch voll-virtualisierte KVM/QEMU-Systeme (für Mailserver und Clients),

  • die netzwerktechnisch weitgehend abgeschottet sind,
  • über die kein freier Internetzugang mit Browsern erlaubt ist
  • und die auch nur spezielle Mail-Accounts bedienen

kann man auch Hackern das Eindringen ein wenig erschweren!

Umzug eines physikalischen Linux-E-Mail-Servers in eine Virtualisierungsumgebung?

Das erste Problem besteht für manchen Leidensgenossen ggf. darin, einen schon vorhandenen physikalischen Server in eine Virtualisierungsumgebung zu bringen. Ehrlich gesagt, habe ich das noch nie selbst gemacht - und leider auch keine Zeit, das mal testweise auszuprobieren. Server für spezielle Aufgaben sind in meinem begrenzten Netz schon seit langem aus guten Gründen virtualisiert 🙂 .

Ich verweise für diese Aufgabe unter Linux deshalb auf sog. "P2V-Tools" (physical to virtual) und entsprechende Literatur. Die ganz unten aufgeführten Links geben hierzu Hinweise und Anleitungen. Für die nachfolgenden Schritte setze ich voraus, dass es bereits einen unter KVM/QEMU virtualisierten Server gibt - allerdings auf unverschlüsselten Partitionen/Volumes.

Vorüberlegung A: Wie sieht es mit der Performance und der Flexibilität auf verschlüsselten Plattformen aus?

Kann man sich auf seinen Systemen eigentlich eine Verschlüsselungsschicht zusätzlich zur Virtualisierung leisten? Das ist eine gute Frage, die man pauschal schlecht beantworten kann. Unter Linux kommt meist eine Kombination aus dm-crypt und LUKS zum Einsatz. Für Systeme mit Prozessoren der letzten 5 Jahre sieht es dabei hinsichtlich der reinen Krypto-Performance recht gut aus. Bei Virtualisierungshosts im Heim-Bereich (also eher mit begrenzten Ressourcen) sind aber ein paar zusätzliche Punkte zu beachten:

Schichtung
Hat man als Plattenunterbau Raid-Systeme im Einsatz, so stellt sich etwa die Frage der Schichtung der verschiedenen Zugriffsverfahren. Aus meiner Sicht ist folgende Reihenfolge für virtualisierte Serversysteme sinnvoll:

  • Plattenpartitionen für Raid   >>  
  • Raid 10   >>  
  • LVM   >>  
  • Volumes für KVM-Host-OS   >>  
  • dm-crypt/Luks für ein LVM-Raw-Volume   >>  
  • KVM/QEMU- und Gastsystem mit Zugriff auf das Raw-Volume als virtuelle Platte   >>  
  • LVM /Volumes (oder Partitionen) im Gastsystem   >>  
  • ext4-Filesysteme im Gastsystem

Verschlüsselung vor Raid scheint mir aus naheliegenden Gründen wenig performance-optimierend zu sein. Bzgl. der Reihenfolge "LVM <> dm-crypt/Luks" kann man streiten. Für die eine oder andere Wahl ist aus meiner Sicht dabei nicht die Performance sondern die Flexibilität ausschlaggebend. Bei der von mir gewählten Vorgehensweise verschlüsseln wir LVM-Raw-Volumes und nicht die sie tragenden Platten-Partitionen. Das erlaubt den Einsatz unterschiedlicher Krypto-Algorithmen und individueller Passphrases für die zu verschlüsselnden Volumes. Ein Nachteil ist, dass Größenänderungen der Volumes und Filesysteme danach nicht im Online-Betrieb möglich sind. Das stört im semi-professionellen Umfeld aber weniger (s.u.).
Siehe auch:
https://superuser.com/questions/1193290/best-order-of-raid-lvm-and-luks

Einsatz von virtio-Treiber
Für optimale Performance setze ich auf dem KVM-Host für die Vermittlung des Zugriffs des KVM-Gast-Systems auf die als virtuelle HDs bereitgestellten Volumes den QEMU-eigenen "VirtIO"-Treiber ein. Das sieht im "virt-manager" dann etwa so aus:

Übernahme der Verschlüsselung durch den Virtualisierungs-Host!
Man erkennt an der oben angegebenen Schichtung, dass ich die Verschlüsselung vollkommen dem Virtualisierungs-Host überlasse. Das erscheint mir sinnvoll, da ihm normalerweise mehr CPU-Cores als dem Gastsystem zur Verfügung stehen.

Ich kann jedenfalls mit diesem Setup auf einem schon sehr betagten Host mit einem KVM-Gast-Mail-Server, der nur um die 10 Mails pro Minute verarbeiten muss, sehr gut leben. (Der Host beherbergt dabei noch mehr aktive virtualisierte Systeme!) Der Unterschied zur Situation ohne Verschlüsselung ist gefühlt klein. Soviel zum Mail-Server und Performance.

Vorüberlegung B: Verschlüsselung eines (LVM-) "Raw"-Devices? Verzicht auf "qcow2"?

Gem. der oben propagierten Schichtung möchte ich das Gastsystem für meinen E-Mail-Server offenbar auf einem "Raw-Volume" der LVM-Schicht betreiben - also direkt auf einem LVM-Volume, das vom Gast-System aus formatiert wurde, und nicht auf einem "qcow2"-Loopback-File eines übergeordneten Filesystems des Hosts. Was spricht gegen ein Vorgehen mit "qcow2"-Dateien auf einem KVM-Host für einen virtualisierten Server?

"qcow2"-Dateien - mit internem Filesystem für den Gast - sind zwar hochflexibel einsetzbar - der Zugriff des Gastes auf seine virtuelle Platte erfolgt dabei aber immer über die Filesystem-Schicht des KVM/QEMU-Hosts UND über die Filesystem-Schicht des KVM-Gastes; das kostet Performance!

Der entsprechende Overhead ist nicht unerheblich - vor allem dann nicht, wenn der Server ggf. von mehreren Clients gleichzeitig genutzt werden soll. Die QEMU-Leute haben deshalb schon immer vorgesorgt und erlauben den direkten Zugriff eines Gastes auch auf nicht gemountete Volumes oder Partitionen des Hosts.

Der zweite Grund entspringt ein wenig Sicherheitsüberlegungen.

Auf eine "qcow2"-Datei muss vom Gast-System über ein Mount-Verzeichnis des Host-Dateisystems aus zugegriffen werden. Die Datei liegt dann also bereits in einem unverschlüsselten Dateisystem, das auf einem Verzeichnis des Hosts gemountet ist, vor. Damit besteht aber auch - je nach Rechtesetzungen - die potentielle Gefahr, dass ihr Inhalt im laufenden Betrieb auch anderweitig ausgelesen werden kann (z.B. mit qemu-mount).

Die Situation ist im Fall von Raw-Devices komplexer. Das LVM-Volume wird nach einer Entsperrung des Verschlüsselungsverfahrens (s.u.) zwar wie eine Platte als Device unter "/dev/mapper" bereitgestellt. Aber dieses Device ist auch bei laufendem Gastsystem nicht direkt im Verzeichnisbaum des laufenden Host-Systems verankert. Ein evtl. durchgeführter Mountvorgang auf dem Host ist aber gar nicht so einfach zu verschleiern. Er wäre unnötig und würde bei entsprechender Protokollierung Alarmglocken auslösen.

Dennoch gilt:

Verschlüsselung von LVM-Volumes und Einsatz von qcow2 müssen bei hinreichenden Performance-Reserven kein Widerspruch sein.

Eine Schichtung

Raid 10   >>   LVM   >>   dm-crypt/Luks-Volume mit ext4   >>   Gemountetes LUKS/ext4-Volume mit qcow2-Datei auf dem KVM/QEMU-Host   >>   KVM/QEMU-Gast mit Zugriff auf qcow2-Loopback-Device   >>   LVM-Volumes des Gastsystems auf qcow2-Device   >>   ext4-Gast-Filesystem auf LVM-Volumes des Loop-Devices

funktioniert auf schnellen Hosts auch gut und bietet Verschlüsselung samt qcow2-Flexibilität. Ich nutze diese Variante u.a. auf Linux-Workstations für virtualisierte Clients.

Ich verfolge nachfolgend für unseren geplanten (Server-) Umzug aber die Variante ohne qcow2-Loopback-Device. Auch unser bisheriger virtualisierter (Mail-) Server mag bereits direkt auf einem unverschlüsselten Volume des Hosts verankert sein.

Vorüberlegung C: Größe des neuen kryptierten Raw-Volumes für den Umzug?

Wir können nun z.B. über den LVM-Volume-Manager von YaST oder über LVM-CLI-Kommandos (vgcreate, lvcreate) ein Raw-Volume kreieren, das nach seiner Verschlüsselung eine Kopie des alten Systems aufnehmen soll. Wie groß muss dieses logische Volume sein?

Naiverweise könnte man davon ausgehen, dass genau die Größe des alten Volumes (oder der alten Partition) in GiB hinreichend ist. Das wäre falsch. LUKS hinterlegt Informationen zum verschlüsselten Plattenplatz und zu 8 möglichen Passphrase-Keys in einem sog. "Verschlüsselungsheader". Dieser Header benötigt zusätzlichen Platz jenseits der verschlüsselten Nutzlast. Der Platzbedarf ist zwar nicht groß (ca. 2 MB) - aber er ist eben zu berücksichtigen. Man muss dem neuen Volume etwas mehr Platz als dem alten spendieren. Ich vergebe meist gleich 1 GB extra.

Verschlüsselung des Raw-Volumes

In unserem Beispiel heiße das neue logische LVM-Volume für das virtuelle Plattendevice des KVM-Gastes "lvimap_hd0" und sei Teil einer LVM-Volume-Group "volgrp4". Als Device erscheint dieses Volume dann unter "/dev/mapper" als "volgrp4-lvimap_hd0".

myserv:~ # la /dev/mapper 
...
lrwxrwxrwx  1 root root       8 Jun 10 09:40 volgrp4-lvimap_hd0 -> ../dm-14
...

Der zugehörige Link verweist im Beispiel dann ebenso wie "/dev/volgrp4/lvimap_hd0" auf "/dev/dm-14".

Wir setzen zur Kryptierung "dm-crypt" ein. "dm-crypt" nutzt LUKS über gut integrierte Module.

Die Aufgabe, ein (LVM-basiertes) "Raw-"-Device mit dmcrypt/LUKS zu verschlüsseln, lässt sich unter Opensuse Leap (42.2/42.3) entgegen jeder Erwartung mit YaST leider nicht erfolgreich durchführen. YaST wickelt die Anlage eines verschlüsselten Volumes nur dann korrekt ab, wenn das Filesystem bereits vorgegeben wird - also NICHT bei der Verschlüsselung für Raw-Devices innerhalb der Reihenfolge :

Partition   >>   LVM-Group   >>   Raw LVM-Volume   >>   dm-crypt/LUKS   >>   KVM-guest   >>   LVM im Gast   >>   Filesystem

Das ist bereits von anderen beklagt worden; siehe etwa:
https://forums.opensuse.org/showthread.php/528938-installation-with-LUKS-cryptsetup-installer-gives-error-code-3034

Man muss also auf der Kommandozeile arbeiten und das Kommando "cryptsetup" bemühen. Für unser Beispiel-Volume "lvimap_hd0" (erste virt. Platte des künftigen E-Mail-Servers) lautet ein mögliches Kommando zur Verschlüsselung dann:

myserv:~ # cryptsetup luksFormat --hash=sha512 --key-size=512 --cipher=aes-xts-plain64 --verify-passphrase /dev/volgrp4/lvimap_hd0

Für Details zu den verfügbaren Verschlüsselungs- und Hash-Verfahren werfe man einen Blick in die man-Seiten zum Kommando. Man muss die künftige Passphrase zweimal eingeben. Damit ist die Verschlüsselung aktiv. Ein anschließender Blick auf das Volume mit dem YaST-Partitioner zeigt entsprechend ein Verschlüsselungssymbol an.

Altes KVM-Gast-System mit "dd" kopieren oder mit "virt-manager" klonen?

Bzgl. des geplanten Umzugs unseres unter KVM/QEMU virtualisierten (Mail-) Servers auf das neue Krypto-Device stellt sich nun die Frage, wie wir das am besten bewerkstelligen:

Sollen wir "dd" einsetzen? Das ist zwar möglich, erfordert anschließend aber wegen kopierter UUIDs, MAC-Adressen etc. etliche manuelle Nacharbeiten im geklonten System und auf dem Host.

Besser ist deshalb aus meiner Sicht ein Cloning mit Hilfe von virt-manager! Dabei ist folgende Schrittfolge einzuhalten:

  • Schritt 1 : Öffnen des neuen dm-crypt-Devices unter einem verständlichen Namen
     
    myserv:~ # cryptsetup open /dev/mapper/volgrp4-lv_imap_hd0  cr_imap_encr

    Dabei muss natürlich die bereits gesetzte Passphrase für das Crypto-Device eingegeben werden. "cr_imap_encr" steht dann als ansprechbares Device unter "/dev/mapper/" bereit

  • Schritt 2 : virt-manager öffnen und in der Liste der Gäste mit der rechten Maustaste auf den zu klonenden Gast klicken. Dann die Option "Clone ..." wählen. Das führt uns dann zu einer Maske, die in etwa so aussieht und die zu klonende virtuelle Platte (vm2_hd1) des vorhandenen Gastes anbietet:
     

    Bzgl. der zu klonenden Disk öffnet man die Drop-Down Box und wählt "Details" :

  • Schritt 3 : In der sich neu öffnenden Maske trägt man den Pfad zum geöffneten "dm-crypt"-Decvice ein:
     

    Dann in der aktuellen Maske den "OK"-Button und anschließend in der Ausgangsmaske den Button "Clone" drücken.

Je nach Größe unseres virtuellen Servers und der Schnelligkeit der Plattensysteme wie des Prozessors dauert das etwas. Anschließend erhalten wir allerdings einen Clone, den man sofort booten kann. (Vorher den ursprünglichen Mail-Server natürlich runterfahren, um IP-Konflikte zu vermeiden. Das geklonte System hat immer noch die gleiche IP-Adresse wie das alte! )

Das war es im Wesentlichen schon. Wir haben erfolgreich ein virtualisiertes Server-System auf einen verschlüsselten LVM-Volume-Unterbau umgezogen!

Wie schließt man das verschlüsselte System manuell?

Unsere manuelle Vorgehensweise hat dazu geführt, dass das verschlüsselte Volume nicht in Systemdateien eingetragen wurde. Es steht daher nach einem Boot-Vorgang des Hosts nicht automatisch zu Verfügung. Auch das Passwort für die Entschlüsselung wird im Bootvorgang nicht automatsich abgefragt.

Ein aktivierter "libvirtd"-Service kann daher nach seinem Start im Zuge eines Bootens des Hosts auch nicht auf das Volume für den umgezogenen Gast zugreifen. Ein automatisches Hochfahren des Gastes über libvirt-Einstellungen ist somit ebenfalls nicht möglich. Das sind Probleme, um die wir uns in nachfolgenden Artikeln kümmern müssen.

An dieser Stelle möchte ich aber wenigstens den notwendigen manuellen Befehl für das Schließen des Crypto-Devices im Zuge eines Herunterfahrens angeben:

  • Schritt 1 - Herunterfahren des Gastsystems: Dies geschieht entweder über Standard-Befehle im Gast selbst oder z.B über virt-manager.
  • Schritt 2 - Schließen des Crypto-Devices :
     
    myserv:~ # cryptsetup close cr_imap_encr

Ausblick

In folgenden Artikeln möchte ich im Nachgang zu unserem "Umzug" ein wenig auf das Thema eingehen, wie man das Hochfahren des KVM-Hosts mit Gastsystemen auf verschlüsselten Volumes gestalten kann. Zudem wollen wir den "Verschlüsselungsheader" sichern und uns mit den Themen Backup und "fstrim" für SSDs als Basis der beschriebenen Schichtung befassen. Sinnvoll ist auch ein Blick auf (Mail-) Client-Systeme: Von irgendwo aus muss ja auch mal grafisch auf die virtualisierten Systeme zugegriffen werden. Dann werden z.B. Spice oder X2GO-Clients samt zugehörigen Protokollen zu einem Sicherheitsthema auf dem System, von dem aus wir auf virtualisierte Clients für die Auftragsbearbeitung zugreifen. Verschieben wir mit der Virtualisierung im Client-Umfeld also nur die Sicherheitsebene?

Links

P2V-Tools
http://manuel.kiessling.net/2013/03/19/converting-a-running-physical-machine-to-a-kvm-virtual-machine/
http://libguestfs.org/virt-p2v.1.html
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/v2v_guide/chap-v2v_guide-p2v_migration_converting_physical_machines_to_virtual_machines
http://events17.linuxfoundation.org/sites/events/files/slides/virt-v2v-rjones-backup-slides.pdf
http://qemu-buch.de/de/index.php?title=QEMU-KVM-Buch/_Speichermedien/_Physical-to-Virtualp2v_migration_converting_physical_machines_to_virtual_machines
https://access.redhat.com/articles/1351473

dm-crypt/Luks und die Reihenfolge von Zugriffsschichten
https://superuser.com/questions/1193290/best-order-of-raid-lvm-and-luks
https://blog.raptor2101.de/2009/09/23/verschlusselung-von-raids/
http://www.andreas-janssen.de/cryptodisk.html
http://linux-club.de/wiki/opensuse/Verschluesselung:_dm-crypt/luks_unter_openSUSE
https://wiki.archlinux.org/index.php/Dm-crypt/Specialties

Opensuse 12.3-Upgrade – lvmetad-Warnung nach grub2-mkconfig

Ich bin ja gerade beim Upgraden diverser Seitensysteme (von Kunden wie im eigenen Netz) auf Opensuse Leap 42.2. Dabei kam mir auch ein unter KVM/qemu virtualisierter LAMP-Testserver unter Opensuse 12.3 unter die Finger. Beim Upgrade dieses KVM-Gastes waren zunächst die üblichen Hürden zu überwinden:
- Notwendige Abänderungen der Apache2-Konfiguration auf die aktuelle Syntax bzgl. des Zugangs zu Verzeichnissen (Wechsel zu Apache2-Versionen > 2.4)
- Manuelles Nacharbeiten des Upgrades der Mysql DB bzw. Maria DB zur Version 5.6 bzw. 10.0.30 mittels "mysql_upgrade -u root -p".

Meldung zu lvmetad

Dann aber stolperte ich im Rahmen der Upgrades über eine mir bislang unbekannte Warnung im Zusammenhang mit der grub2-Konfiguration während der Upgrades:

/run/lvm/lvmetad.socket: connect failed: No such file or directory
WARNING: Failed to connect to lvmetad. Falling back to internal scanning.

Das verhinderte zwar keinen Neustart der Zwischenversionen Opensuse 13.1, 13.2 Leap 42.1; aber sauber erschien mir das dann doch nicht. Ein manueller Test unter Leap 42.2 mittels "grub2-mkconfig -o /boot/grub2/grub.cfg" ergab dieselbe Meldung.

Was ist lvmetad?

lvm2-lvmetad ist offenbar ein Caching-Service für Metadaten ("central metadata cache"), die aus physikalischen Volumes [PV] einer LVM-Volume-Group ausgelesen werden. Siehe hierzu:
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Logical_Volume_Manager_Administration/metadatadaemon.html

Das Caching führt zu einer Beschleunigung der Ausführung von LVM bzw. LVM-Kommandos.

Dieser Service bzw. ein zugehöriger Socket sollten auf moderneren Opensuse-Systemen offenbar immer aktiviert sein. Ein Statuscheck auf von Scratch installierten Opensuse-Systemen der Versionen 13.1, 42.1, 42.2-Systemen ergab, dass diese Services/Sockets dort laufen - unabhängig davon, ob tatsächlich "Logical Volume Groups" und " Logical Volumes [LV]" genutzt werden oder nicht.

Auf meinem alten 12.3-System waren die entsprechenden Services aber offenbar nicht aktiviert ("enabled"). (Oder aber der Upgrade hat da was verbockt.)

Dass ein laufender lvmetad-Dienst/Socket vorausgesetzt wird, gilt offenbar selbst dann, wenn das Opensuse-System - wie in meinem Fall - virtualisiert ist und selbst gar kein LV auf den vom Host per virtio-(blk)-Treiber durchgereichten Blockdevices nutzt (also auch kein sog. "nested" LVM für den Fall, dass das Blockdevice selbst auf einem LV des Hostes beruht).

Problemlösung: Aktivieren von lvmetad

Die Lösung war jedenfalls trivial; es half die Durchführung folgender Kommandos

systemctl enable lvm2-lvmetad.socket
systemctl enable lvm2-lvmetad.service
systemctl start lvm2-lvmetad.socket
systemctl start lvm2-lvmetad.service

auf dem von OS 12.3 auf Leap 42.2 upgegradetem System. Ein "grub2-mkconfig -o /boot/grub2/grub.cfg" lief danach ohne jede Warnung oder Fehlermeldung durch.

Fühlbare Performance-Vorteile habe ich auf dem unter KVM virtualisierten System erwartungsgemäß nicht feststellen können; das nutzt zwar ein LV einer LVM Volume Group des KVM-Hostes als Raw-Device über virtio-(blk)-Treiber. In dieser Situation ist es viel wichtiger, dass lvmetad auf dem KVM-Host selbst läuft.