LVM i szyfrowanie dyskó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.00mCzemu 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.99gvgextend 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 -aPowiększanie: jedna komenda
I teraz to, po co ludzie kochają LVM:
sudo lvextend -r -L +200M dane_vg/www
df -h /srv/wwwTak 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-lvCał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 lvsWynik 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.00Sprytne 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 --mergecofa 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.lvremovewyrzuca 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/loop3WARNING!
========
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 /sejfopen 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 sejfCo jest w nagłówku sejfu:
sudo cryptsetup luksDump /dev/loop3LUKS header information
Version: 2
...
cipher: aes-xts-plain64
...
Keyslots:
0: luks2
Key: 512 bits
PBKDF: argon2idLUKS 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.binKopia 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/loop3559bd602-1b3b-4959-9c67-95f4600a23f9W /etc/crypttab:
sejf UUID=559bd602-1b3b-4959-9c67-95f4600a23f9 none luksA w /etc/fstab, jak zawsze:
/dev/mapper/sejf /sejf ext4 defaults 0 2Cztery 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
lsblklsblk 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
| Komenda | Flaga | Co robi |
|---|---|---|
pvcreate | URZĄDZENIE | robi z dysku lub partycji PV |
vgcreate | NAZWA PV... | tworzy grupę z podanych PV |
vgextend | VG PV | dokłada dysk do grupy |
lvcreate | -n NAZWA | nazwa woluminu |
lvcreate | -L 500M / -l 100%FREE | rozmiar w jednostkach / w kafelkach lub procentach |
lvcreate | -s | tworzy migawkę |
lvextend | -L +200M | powiększa o 200 MB (bez + ustawia rozmiar) |
lvextend | -r / --resizefs | od razu powiększa system plików |
lvconvert | --merge | cofa oryginał do stanu migawki |
pvs / vgs / lvs | krótkie podsumowania | |
pvdisplay / vgdisplay / lvdisplay | długie opisy | |
cryptsetup | luksFormat | zakłada sejf LUKS (kasuje dane) |
cryptsetup | open / close | otwiera i zamyka sejf |
cryptsetup | luksDump | pokazuje nagłówek i sloty |
cryptsetup | luksAddKey / luksRemoveKey | dodaje i usuwa hasło |
cryptsetup | luksHeaderBackup | robi 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/wwwZabrakł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/wwwPierwsza 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:
- Załóż sejf LUKS, otwórz go pod nazwą
sejf, załóż na nim ext4 i zamontuj w/sejf. - Zapisz w nim plik, odmontuj i zamknij sejf. Sprawdź w
lsblk, że urządzeniesejfzniknęło. - Dodaj drugie hasło i pokaż w
luksDump, że zajęte są dwa sloty. - 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: luks2Dwa 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ć.