Przejdź do treści
Lekcja 61 z 117

Kurs › Moduł 6 › Lekcja 61

LVM i szyfrowanie dysków

⏱ ok. 13 min czytania· moduł 6: Dyski i systemy plików

Po tej lekcji: kursant buduje LVM od zera (PV, VG, LV), powiększa wolumin razem z systemem plików, robi migawkę, a na koniec zakłada zaszyfrowany kontener LUKS i podpina go przy starcie przez /etc/crypttab.

Wstęp

df -h, partycja /var zajęta w 98%

Baza danych rośnie, /var jest na swojej partycji i zaraz się skończy. Dokładasz do maszyny nowy dysk, 100 GB, bez problemu. Tylko że partycja to ściana z cegły. Nowy dysk stoi obok jak osobny budynek. Nie dokleisz go do /var.

Stara szkoła: kopiujesz wszystko na nowy dysk, zmieniasz punkty montowania, modlisz się, żeby baza nie zapisała nic w trakcie, i robisz to w nocy z niedzieli na poniedziałek.

Nowa szkoła, a właściwie szkoła z ostatnich dwudziestu kilku lat: dokładasz dysk do puli, jedna komenda powiększa wolumin razem z systemem plików. Na żywo, bez odmontowywania. Baza nawet nie zauważa. Tak działa LVM. A na koniec zamkniemy dysk w sejfie, żeby złodziej laptopa dostał drogi przycisk do papieru.

LVM, czyli regały na kółkach

Wyobraź sobie magazyn. W starym magazynie regały są przykręcone do podłogi i do ścian. Chcesz powiększyć dział z farbami? Odkręcasz, przenosisz towar, przykręcasz od nowa. To są partycje.

W nowym magazynie regały stoją na kółkach. Podłoga jest podzielona na równe kafelki. Dział z farbami dostaje tyle kafelków, ile trzeba, a jak mu brakuje, dostawiasz kolejne. Możesz nawet dobudować nowe skrzydło hali i regały pojadą dalej. To jest LVM, Logical Volume Manager, menadżer woluminów logicznych.

Trzy słowa, które musisz zapamiętać, od dołu do góry:

  • PV, physical volume, wolumin fizyczny. Dysk albo partycja oddana do LVM. Kawałek podłogi w magazynie.
  • VG, volume group, grupa woluminów. Cała hala złożona z jednego lub wielu PV. Wspólna pula miejsca.
  • LV, logical volume, wolumin logiczny. Wydzielony dział w hali. Na nim robisz system plików i montujesz go jak partycję.

A kafelki podłogi mają nazwę: extent, domyślnie po 4 MiB. LVM nie myśli w bajtach, tylko w kafelkach. Wolumin 500 MB to dla niego 125 kafelków.

Pakiet nazywa się tak samo w obu rodzinach: lvm2. [RHEL] Instalator Anaconda przy automatycznym podziale domyślnie stawia system na LVM, z osobnymi woluminami na /, /home i swap. [Ubuntu] Instalator serwera też proponuje LVM, z grupą ubuntu-vg i woluminem ubuntu-lv, ale często nie daje mu całego dysku. Klasyk: dysk 200 GB, a df -h pokazuje dużo mniej, bo reszta czeka wolna w grupie. Po dzisiejszej lekcji naprawisz to jedną komendą.

Budujemy: PV i VG

pvcreate zapisuje na dysku nagłówek LVM. Pomyłka w nazwie dysku i dane idą do piachu. Maszyna wirtualna, nowy pusty dysk, lsblk przed każdą komendą.

Na mojej maszynie ćwiczebnej dwa puste dyski po 1 GB. U Ciebie mogą się nazywać /dev/sdb albo /dev/vdb, u mnie to /dev/loop1 i /dev/loop2. Kto nie ma drugiego dysku, może zrobić udawany z pliku: sudo losetup -f --show dysk.img.

lsblk
sudo pvcreate /dev/loop1
sudo vgcreate dane_vg /dev/loop1
sudo vgs
  Physical volume "/dev/loop1" successfully created.
  Volume group "dane_vg" successfully created
  VG      #PV #LV #SN Attr   VSize    VFree
  dane_vg   1   0   0 wz--n- 1020.00m 1020.00m

Czemu 1020 MB, a nie 1024? Bo LVM zabiera kawałek na swoje notatki, czyli metadane, a resztę dzieli na pełne kafelki po 4 MiB. Biurokracja kosztuje, nawet w magazynie.

Teraz dobudowujemy skrzydło hali, czyli dokładamy drugi dysk do grupy:

sudo vgextend dane_vg /dev/loop2
sudo pvs
sudo vgs
  Volume group "dane_vg" successfully extended
  PV         VG      Fmt  Attr PSize    PFree
  /dev/loop1 dane_vg lvm2 a--  1020.00m 1020.00m
  /dev/loop2 dane_vg lvm2 a--  1020.00m 1020.00m
  VG      #PV #LV #SN Attr   VSize VFree
  dane_vg   2   0   0 wz--n- 1.99g 1.99g

vgextend sam zrobił z dysku PV, nie trzeba było osobnego pvcreate. Hala ma teraz prawie 2 GB i nikt już nie pamięta, że to dwa osobne dyski.

Budujemy: LV, system plików, montowanie

sudo lvcreate -n www -L 500M dane_vg
sudo lvs
sudo mkfs.ext4 /dev/dane_vg/www
sudo mkdir -p /srv/www
sudo mount /dev/dane_vg/www /srv/www
df -h /srv/www
  Logical volume "www" created.
  LV   VG      Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  www  dane_vg -wi-a----- 500.00m

-n to nazwa, -L rozmiar. Zamiast -L możesz dać małe -l i liczyć w kafelkach albo w procentach: -l 100%FREE znaczy „całe wolne miejsce w grupie”.

Wolumin ma dwie nazwy i obie działają: /dev/dane_vg/www i /dev/mapper/dane_vg-www. Pierwsza jest dla ludzi, druga to prawdziwa nazwa w jądrze. df i findmnt lubią pokazywać tę drugą, więc nie panikuj, że to coś innego.

Na stałe, tak jak w lekcji o montowaniu, przez UUID:

sudo blkid /dev/dane_vg/www
echo 'UUID=<tu-uuid>  /srv/www  ext4  defaults  0 2' | sudo tee -a /etc/fstab
sudo systemctl daemon-reload
sudo mount -a

Powiększanie: jedna komenda

I teraz to, po co ludzie kochają LVM:

sudo lvextend -r -L +200M dane_vg/www
df -h /srv/www

Tak wygląda wynik w dokumentacji Red Hata, przy powiększaniu woluminu z 2 do 3 GB:

  Size of logical volume myvg/mylv changed from 2.00 GiB (512 extents) to 3.00 GiB (768 extents).
  Logical volume myvg/mylv successfully resized.
resize2fs 1.45.6 (20-Mar-2020)
Resizing the filesystem on /dev/mapper/myvg-mylv to 786432 (4k) blocks.
The filesystem on /dev/mapper/myvg-mylv is now 786432 (4k) blocks long.

Dwie rzeczy się wydarzyły. Najpierw LVM dostawił kafelki do woluminu. Potem, dzięki -r, czyli --resizefs, sam zawołał narzędzie do powiększenia systemu plików: resize2fs dla ext4, xfs_growfs dla XFS. Wszystko na zamontowanym, działającym woluminie.

-L +200M znaczy „o 200 MB więcej”. -L 700M bez plusa znaczy „ustaw na 700 MB”. Jeden znak różnicy, a przy zmniejszaniu potrafi zrobić dużą krzywdę. A teraz ten klasyk z Ubuntu:

sudo lvextend -r -l +100%FREE ubuntu-vg/ubuntu-lv

Całe wolne miejsce z grupy idzie do głównego woluminu. Jedna linijka, a kolega z zespołu uważa Cię za czarodzieja.

A zmniejszanie? Ostrożnie. ext4 da się zmniejszyć przez lvreduce --resizefs, ale system plików musi zostać na chwilę odmontowany. XFS, domyślny system plików na RHEL, nie da się zmniejszyć w ogóle. Można tylko zrobić kopię, założyć mniejszy i odtworzyć. Dlatego dobra praktyka brzmi: dawaj woluminom tyle, ile trzeba teraz, a resztę zostaw wolne w grupie. Powiększyć zawsze zdążysz.

Migawki: zdjęcie stanu przed operacją

Migawka, po angielsku snapshot, to zdjęcie woluminu w danej sekundzie. Robisz ją przed aktualizacją, przed migracją bazy, przed czymkolwiek, po czym mówisz „co może pójść nie tak”.

sudo lvcreate -s -L 100M -n www_migawka dane_vg/www
sudo lvs

Wynik z dokumentacji Red Hata, tam oryginał nazywa się origin, a migawka snap:

LV     VG     Attr       LSize  Pool Origin Data%
origin vg001  owi-a-s--- 1.00g
snap   vg001  swi-a-s--- 100.00m      origin 0.00

Sprytne jest to, że migawka 100 MB może pilnować woluminu 1 GB. Na początku nic nie kopiuje. Dopiero kiedy ktoś zmienia blok w oryginale, LVM najpierw odkłada starą wersję tego bloku do migawki. To się nazywa copy-on-write, kopiuj przy zapisie. Jak fotograf, który nie robi zdjęcia całego pokoju, tylko pstryka każdy mebel w chwili, kiedy ktoś go przesuwa.

Kolumna Data% mówi, ile miejsca migawki już zużyto. Pilnuj jej, bo dokumentacja Red Hata mówi wprost: kiedy migawka dojdzie do 100%, staje się nieważna i bezużyteczna. Fotograf, któremu skończyła się karta pamięci, wyrzuca wszystkie zdjęcia.

Co z migawką robisz:

sudo mount -o ro /dev/dane_vg/www_migawka /mnt/migawka
sudo lvconvert --merge dane_vg/www_migawka
sudo lvremove dane_vg/www_migawka
  • Montujesz ją tylko do odczytu i robisz z niej spójną kopię zapasową, podczas gdy oryginał pracuje dalej.
  • lvconvert --merge cofa oryginał do stanu z migawki. Aktualizacja poszła źle? Wracasz do zdjęcia. Jeśli wolumin jest w użyciu, scalenie ruszy przy następnej aktywacji, czyli w praktyce po odmontowaniu albo restarcie.
  • lvremove wyrzuca migawkę, kiedy wszystko poszło dobrze.

Migawka to nie kopia zapasowa. Leży na tych samych dyskach. Padł dysk, padły oba.

LUKS, czyli sejf na dysk

Teraz zmiana tematu, ale nie piętra. Uprawnienia z lekcji o kluczach do pokojów chronią pliki przed innymi użytkownikami, kiedy system działa. Ale kiedy ktoś wyjmie dysk z serwera albo ukradnie laptopa, wkłada go do swojego komputera i czyta wszystko. Klucze do pokojów nic nie dają, kiedy ktoś wynosi cały budynek.

Rozwiązanie: sejf. Wszystko, co trafia na dysk, jest szyfrowane. Bez hasła dysk to szum. Standard szyfrowania dysków w Linuksie to LUKS, Linux Unified Key Setup, a narzędzie nazywa się cryptsetup. Pakiet cryptsetup w obu rodzinach.

luksFormat kasuje wszystko na urządzeniu. A zapomniane hasło to dane stracone na zawsze. Nie ma przycisku „nie pamiętam hasła”. Ćwicz na maszynie wirtualnej albo na pliku.

sudo cryptsetup luksFormat /dev/loop3
WARNING!
========
This will overwrite data on /dev/loop3 irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/loop3:
Verify passphrase:

Tak, trzeba wpisać YES wielkimi literami. Małe yes nie przejdzie. To jedyne miejsce w Linuksie, gdzie system każe Ci krzyczeć, żebyś na pewno wiedział, co robisz.

Teraz otwieramy sejf, robimy system plików i montujemy:

sudo cryptsetup open /dev/loop3 sejf
sudo mkfs.ext4 /dev/mapper/sejf
sudo mkdir -p /sejf
sudo mount /dev/mapper/sejf /sejf

open pyta o hasło i tworzy nowe urządzenie /dev/mapper/sejf. Ono jest zawsze odszyfrowane: co do niego zapisujesz, trafia na dysk zaszyfrowane. System plików zakładasz na nim, a nie na surowym dysku.

Zamykanie w odwrotnej kolejności:

sudo umount /sejf
sudo cryptsetup close sejf

Co jest w nagłówku sejfu:

sudo cryptsetup luksDump /dev/loop3
LUKS header information
Version:       	2
...
	cipher: aes-xts-plain64
...
Keyslots:
  0: luks2
	Key:        512 bits
	PBKDF:      argon2id

LUKS w wersji 2, szyfr AES w trybie XTS z kluczem 512 bitów. Red Hat potwierdza, że LUKS2 i ten szyfr to domyślne ustawienia na RHEL, a na Ubuntu wynik wygląda tak samo.

Tych slotów jest kilka, więc możesz mieć kilka haseł do jednego sejfu. Na przykład Twoje i zapasowe, które leży w kopercie w sejfie prawdziwym:

sudo cryptsetup luksAddKey /dev/loop3
sudo cryptsetup luksHeaderBackup /dev/loop3 --header-backup-file luks-naglowek.bin

Kopia nagłówka to polisa. Uszkodzony nagłówek to sejf bez zamka: hasło znasz, ale nie ma gdzie go wpisać. Tylko trzymaj tę kopię poza tym dyskiem.

Sejf otwierany przy starcie: /etc/crypttab

fstab mówi, co zamontować. Ale zaszyfrowany dysk trzeba najpierw otworzyć. Od tego jest /etc/crypttab, lista sejfów do otwarcia przy starcie:

sudo cryptsetup luksUUID /dev/loop3
559bd602-1b3b-4959-9c67-95f4600a23f9

W /etc/crypttab:

sejf  UUID=559bd602-1b3b-4959-9c67-95f4600a23f9  none  luks

A w /etc/fstab, jak zawsze:

/dev/mapper/sejf  /sejf  ext4  defaults  0 2

Cztery kolumny crypttab: nazwa po otwarciu, urządzenie, plik z kluczem i opcje. none w trzeciej kolumnie znaczy: zapytaj o hasło przy starcie. Na serwerze bez klawiatury to znaczy, że ktoś musi być przy konsoli. Dlatego w serwerowniach używa się pliku z kluczem albo odblokowywania przez układ TPM czy serwer kluczy, ale to temat na inna lekcja.

[RHEL] [Ubuntu] Obie rodziny czytają crypttab przez systemd przy starcie, format jest ten sam.

I LVM, i LUKS można łączyć: albo LVM w środku sejfu, albo sejf na woluminie LVM. Instalatory przy opcji „szyfruj dysk” robią zwykle to pierwsze: jeden sejf, a w nim regały na kółkach.

Jak to działa pod spodem

I LVM, i LUKS stoją na tym samym mechanizmie jądra: device mapper. To tłumacz adresów. Dla jądra wolumin logiczny to tabelka: „bloki od 0 do 1000 tego urządzenia leżą na dysku pierwszym od miejsca X, a dalsze na dysku drugim od miejsca Y”. Program pisze do /dev/mapper/dane_vg-www, a device mapper po cichu przekierowuje zapis tam, gdzie trzeba. Dlatego powiększenie woluminu to tylko dopisanie wiersza do tabelki. Nic się nie przenosi.

LUKS to ten sam tłumacz, tylko z dodatkowym krokiem: moduł dm-crypt szyfruje każdy blok w drodze na dysk i odszyfrowuje w drodze z dysku. Dlatego /dev/mapper jest tak tłoczny na wielu serwerach.

sudo dmsetup ls
sudo dmsetup table
lsblk

lsblk pokazuje całą wieżę: dysk, nad nim crypt, nad nim lvm. A notatki o tym, które kafelki do kogo należą, LVM trzyma w nagłówku na każdym PV, więc grupę da się przenieść z dyskami na inny serwer.

Ściąga flag

KomendaFlagaCo robi
pvcreateURZĄDZENIErobi z dysku lub partycji PV
vgcreateNAZWA PV...tworzy grupę z podanych PV
vgextendVG PVdokłada dysk do grupy
lvcreate-n NAZWAnazwa woluminu
lvcreate-L 500M / -l 100%FREErozmiar w jednostkach / w kafelkach lub procentach
lvcreate-stworzy migawkę
lvextend-L +200Mpowiększa o 200 MB (bez + ustawia rozmiar)
lvextend-r / --resizefsod razu powiększa system plików
lvconvert--mergecofa oryginał do stanu migawki
pvs / vgs / lvskrótkie podsumowania
pvdisplay / vgdisplay / lvdisplaydługie opisy
cryptsetupluksFormatzakłada sejf LUKS (kasuje dane)
cryptsetupopen / closeotwiera i zamyka sejf
cryptsetupluksDumppokazuje nagłówek i sloty
cryptsetupluksAddKey / luksRemoveKeydodaje i usuwa hasło
cryptsetupluksHeaderBackuprobi kopię nagłówka

⚠ Typowy błąd

Wolumin powiększony, a df -h dalej pokazuje stary rozmiar.

sudo lvextend -L +200M dane_vg/www
df -h /srv/www

Zabrakło -r. LVM dostawił kafelki, ale system plików o tym nie wie. Regał jest większy, tylko nikt nie przesunął ścianki działowej w szafce. Naprawa bez żadnego strachu, na zamontowanym systemie:

sudo resize2fs /dev/dane_vg/www
sudo xfs_growfs /srv/www

Pierwsza dla ext4, druga dla XFS. Uwaga na różnicę: resize2fs chce urządzenia, a xfs_growfs punktu montowania.

A drugi błąd z LUKS: złe hasło.

No key available with this passphrase.

Zanim zaczniesz panikować, sprawdź układ klawiatury. Hasło z polską literą, a na niemieckiej klawiaturze nawet hasło z z i y, bo tam te litery zamieniają się miejscami, wpisane przy starcie na innym układzie niż przy zakładaniu, to zupełnie inne hasło. Najlepiej trzymać się znaków, które są w tym samym miejscu na każdej klawiaturze.

✎ Zadanie

Na maszynie wirtualnej, na dodatkowym dysku albo na pliku podpiętym przez losetup:

  1. Załóż sejf LUKS, otwórz go pod nazwą sejf, załóż na nim ext4 i zamontuj w /sejf.
  2. Zapisz w nim plik, odmontuj i zamknij sejf. Sprawdź w lsblk, że urządzenie sejf zniknęło.
  3. Dodaj drugie hasło i pokaż w luksDump, że zajęte są dwa sloty.
  4. Otwórz sejf drugim hasłem i sprawdź, że plik dalej tam jest.
Pokaż rozwiązanie
sudo dd if=/dev/zero of=sejf.img bs=1M count=100
sudo losetup -f --show sejf.img
sudo cryptsetup luksFormat /dev/loop0
sudo cryptsetup open /dev/loop0 sejf
sudo mkfs.ext4 /dev/mapper/sejf
sudo mkdir -p /sejf
sudo mount /dev/mapper/sejf /sejf
echo "tajne plany" | sudo tee /sejf/plany.txt
sudo umount /sejf
sudo cryptsetup close sejf
lsblk /dev/loop0
sudo cryptsetup luksAddKey /dev/loop0
sudo cryptsetup luksDump /dev/loop0 | grep luks2
  0: luks2
  1: luks2

Dwa sloty zajęte, dwa hasła. Potem cryptsetup open z drugim hasłem, mount i cat /sejf/plany.txt: plan dalej jest. Po close w lsblk pod dyskiem nie ma już urządzenia sejf, został sam zaszyfrowany szum. losetup -f --show wypisało nazwę wolnego urządzenia, u mnie /dev/loop0, u Ciebie może być inna. Jeśli drugie hasło było „Hasło123”, to sejf jest, ale zamek z Biedronki.

Co dalej

LVM daje elastyczność, ale nie chroni przed awarią dysku. Jeśli regał stoi na dwóch dyskach i jeden padnie, padają oba. W następnej lekcji RAID: jak zrobić, żeby serwer przeżył śmierć dysku, i jak zawczasu zauważyć, że dysk zaczyna umierać.