Встановлення Debian на raid-масив із LUKS шифруванням, кореневою файловою системою ZFS та завантаженням з UBS із detached header
Вступ здалеку
Нещодавно знову ностальгував у FreeBSD, все чудово, все звично, все зручно.
Лише один момент повністю виключає її з використання, принаймні в мене.
Майже на всіх моїх ноутбуках FreeBSD не підтримує ні режим сну, ні режим очікування (s2ram/s2disk).
І зробити я з цим нічого не зміг, а перепробував багато чого.
Без режиму очікування абсолютно неможливо користуватися ноутбуком, так як після транспортування необхідно по новому все завантажувати, включати, відкривати.
Та й перезавантажую робочі станції лише після оновлень, які цього вимагають.
З багатьох приємних дрібниць, які є у Фряхі, і які відсутні в Debian це ZFS Boot Environments, що зручніше, ніж, скажімо, снапшоти LVM.
А друге це GEOM_ELI, який підтримує не лише, як LUKS, режим АБО пароль, АБО ключ, але також підтримує режим І пароль, І ключ.
Подумав, подумав, та й вирішив розгорнути Debian з нуля з урахуванням усіх інструментів, які використовую, досвіду, і, що важливо, звичок.
Debian поки що залишається основною моєю системою, тому єдиний спосіб отримання хардварного (фізичного) ключа шифрування на додаток до паролю - це зробити його з хедера і розмістити на USB-флешці.
Звички
Миритись краще зі знайомим злом, Ніж навмання тікати в невідомість!
mdadm raid1
Це основний шар всіх моїх дискових систем і це звичка якої складно позбутися.
Навіть якщо у робочій станції лише один диск, то на ньому в основі буде деградуючий raid1.
Хоча завжди в системах щонайменше два диски.
Це дозволяє буквально за лічені хвилини робити завантажувальну та працездатну копію системи та даних.
1 2 3 4 5 | mdadm --grow /dev/md1 --raid-devices=3 mdadm --manage /dev/md1 --add /dev/sdx1 # watch -n1 cat /proc/mdstat mdadm --manage /dev/md1 --fail /dev/sdx1 mdadm --manage /dev/md1 --remove /dev/sdx1 |
Диск може бути підключений за будь-якою шиною, мені доводилося клонувати дзеркало і на eSATA, і на USB2/3, і на EXPRESSCARD 54, і на Thunderbolt, і навіть на loop-файл.
Розгорнута на гарному обладнанні та налаштована під себе система, якій ти можеш довіряти, цінується на рівні з даними.
Тому що на написання невеликого проекту може знадобитися 2-3 місяці роботи, а на налаштування системи у процесі може піти й півроку.
Відразу зауважу, ніякі dd, rsync, cpio та інше не зможе коректно зробити бекап працюючої системи.
LUKS
Це другий рівень, одразу поверх Raid дзеркала.
Його призначення пояснювати не треба.
LVM
Іноді буває потрібен “режим сну” (s2disk|Hibernation), тому потрібен SWAP, а оскільки пароль хочеться мати один, то lvm необхідний.
Так, mdadm, LVM та LUKS можна замінити однією ZFS, але це ж звички.
За добрих півтора десятка років із ними не було жодної проблеми.
Були збої живлення/ресети ноутбука, множинні оновлення релізів Debian, сипалися HDD, але система завантажувалася завжди.
Забігаючи вперед
За підсумками дискова система виглядатиме так:
1 2 3 4 5 6 7 8 9 10 11 12 13 | # usb sda 8:16 1 14.9G 0 disk ├─sda1 8:17 1 1000K 0 part ├─sda2 8:18 1 512M 0 part /boot/efi └─sda3 8:19 1 4G 0 part /boot # nvme nvme0n1 259:0 0 3.6T 0 disk └─nvme0n1p1 259:1 0 904G 0 part └─md1 9:1 0 903.9G 0 raid1 └─md1_crypt 253:0 0 903.9G 0 crypt ├─lvm_system-swap 253:1 0 96G 0 lvm └─lvm_system-zfs 253:2 0 807.9G 0 lvm zroot |
Встановлення
Інсталятор Debian не надає можливості кастомної установки з урахуванням усіх вимог.
Тому було вирішено встановлювати використовуючи старий добрий debootstrap з-під LiveCD системи.
У моєму випадку це debian-live-13.3.0-amd64-kde.iso.
LiveCD-образ завантажен, всі хеші та gpg підписи перевірені.
Debian LiveCD
sudo -i
apt install apt-transport-https
nano /etc/apt/sources.list
1 2 3 4 | # trixie
deb https://deb.debian.org/debian/ trixie main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security/ trixie-security main contrib non-free non-free-firmware
deb https://deb.debian.org/debian/ trixie-updates main contrib non-free non-free-firmware
|
1 2 3 4 5 6 7 8 9 10 | apt update apt install cryptsetup mdadm \ lvm2 \ linux-headers-amd64 \ debootstrap \ gdisk \ zfsutils-linux \ openssh-server \ linux-headers-6.12.63+deb13-amd64 \ linux-headers-6.12.63+deb13-common |
Якщо ви хочете продовжити встановлення по ssh:
1 2 3 4 | # nano /etc/ssh/sshd_config printf '%s\n' "PermitRootLogin yes" >> /etc/ssh/sshd_config systemctl restart sshd.service passwd |
Перед установкою весь диск було перезаписано urandom, можете пропустити цей крок.
1 | dd if=/dev/urandom of=/dev/nvme0n1 bs=1M count=4096 oflag=sync status=progress |
Розмічання диску
1 2 3 4 5 6 7 8 | parted -a optimal /dev/nvme0n1 mklabel gpt unit MiB p free mkpart 'raid' 1 925697 set 1 raid on align-check optimal 1 align-check minimal 1 |
mdadm
1 2 | mdadm --verbose --create /dev/md1 --level=1 --raid-devices=2 missing /dev/nvme0n1p1 mdadm --detail --scan |
luks2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | mkdir /tmp/keys chmod 700 /tmp/keys sync dd if=/dev/random of=/tmp/keys/md1_header bs=1M count=16 sync printf '3' > /proc/sys/vm/drop_caches chmod 400 /tmp/keys/md1_header # Wipe 1Gb and test /dev/md1 dd if=/dev/urandom of=/dev/md1 bs=1M count=1024 oflag=sync status=progress # LUKS2 init cryptsetup --verbose \ --cipher "aes-xts-plain64" \ --key-size=512 \ --hash=sha512 \ --use-random \ --iter-time=3000 \ --type luks2 \ --pbkdf argon2id \ --pbkdf-memory 4194304 \ --pbkdf-parallel 4 \ --verify-passphrase \ luksFormat /dev/md1 \ --header /tmp/keys/md1_header \ --align-payload=8192 # Check cryptsetup luksDump /tmp/keys/md1_header # Open cryptsetup luksOpen /dev/md1 --allow-discards --header /tmp/keys/md1_header md1_crypt |
LVM
1 2 3 4 5 6 7 8 9 10 11 12 | pvcreate /dev/mapper/md1_crypt pvdisplay -v vgcreate lvm_system /dev/mapper/md1_crypt vgdisplay vgscan # vgchange -a y # swap partition lvcreate -L98304 -n swap lvm_system vgdisplay lvm_system # zroot partition lvcreate -l100%FREE -n zfs lvm_system vgdisplay lvm_system |
ZFS
modprobe zfs
Якщо у вас з’являється помилка, то, ймовірно, немає linux-headers.
1 2 3 4 5 6 7 8 | modprobe: FATAL: Module zfs not found in directory /lib/modules/6.12.63+deb13-amd64 apt install linux-headers-amd64 # or # apt install linux-headers-6.12.63+deb13-amd64 linux-headers-6.12.63+deb13-common apt reinstall zfs-dkms modprobe zfs |
Створення файлових систем ZFS.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | zpool create -o ashift=12 \ -o autotrim=on \ -O acltype=posixacl \ -O xattr=sa \ -O dnodesize=auto \ -O compression=off \ -O normalization=formD \ -O utf8only=on \ -O checksum=fletcher4 \ -O dedup=off \ -O atime=off \ -O canmount=off \ -O mountpoint=/ \ -R /mnt \ zroot /dev/lvm_system/zfs zfs create -o canmount=off -o mountpoint=none zroot/ROOT zfs create -o canmount=noauto -o mountpoint=/ zroot/ROOT/trixie zfs mount zroot/ROOT/trixie zfs create -o canmount=on -o atime=off zroot/data zfs create -o atime=on zroot/home zfs create -o mountpoint=/root -o atime=on zroot/home/root zfs create -o canmount=off zroot/usr zfs create -o mountpoint=/usr/local zroot/usr/local zfs create -o mountpoint=/usr/src -o exec=off -o setuid=off -o compression=lz4 zroot/usr/src zfs create -o canmount=off zroot/var zfs create -o mountpoint=/var/log -o exec=off -o compression=lz4 zroot/var/log zfs create -o mountpoint=/var/mail -o atime=on -o exec=off zroot/var/mail |
1 2 3 4 | chmod 700 /mnt/root mkdir /mnt/run mount -t tmpfs tmpfs /mnt/run mkdir /mnt/run/lock |
Розмічання USB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # Wipe USB dd if=/dev/urandom of=/dev/sda bs=1M count=4096 oflag=sync status=progress sgdisk -Z sgdisk -o /dev/sda # sgdisk --list-types sgdisk -a1 -n1:24K:+1000K -t1:EF02 /dev/sda sgdisk -n2:1M:+512M -t2:EF00 /dev/sda sgdisk -n3:514M:+4G -t3:8300 /dev/sda sgdisk -c 1:boot /dev/sda sgdisk -A 1:set:2 /dev/sda # /boot - ext4 mkfs.ext4 /dev/sda3 mkdir /mnt/boot mount /dev/sda3 /mnt/boot mkdir /mnt/boot/efi # (/boot/efi)/EFI - fat32 mkdosfs -F 32 -s 1 -n EFI /dev/sda2 mount /dev/sda2 /mnt/boot/efi |
debootstrap та первинне налаштування
debootstrap trixie /mnt
1 2 3 4 5 6 7 8 | mkdir /mnt/etc/zfs cp /etc/zfs/zpool.cache /mnt/etc/zfs/ # У мене не було цього кешу # cp: cannot stat '/etc/zfs/zpool.cache': No such file or directory hostname deb hostname > /mnt/etc/hostname printf '127.0.1.1 deb' >> /mnt/etc/hosts |
ip addr show
nano /mnt/etc/network/interfaces.d/eth0
1 2 | auto eth0 iface eth0 inet dhcp |
nano /mnt/etc/apt/sources.list
1 2 3 4 | # trixie
deb http://deb.debian.org/debian/ trixie main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security/ trixie-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian/ trixie-updates main contrib non-free non-free-firmware
|
Монтуємо віртуальні файлові системи.
1 2 3 4 5 | # mkdir /mnt/dev /mnt/proc /mnt/sys mount --make-private --rbind /dev /mnt/dev mount --make-private --rbind /proc /mnt/proc mount --make-private --rbind /sys /mnt/sys mount -t devpts devpts /mnt/dev/pts |
Копіюємо luks header
1 2 3 4 5 6 7 8 9 | mkdir /mnt/etc/.crypto_data cp /tmp/keys/md1_header /mnt/etc/.crypto_data/md1_header chmod 700 /mnt/etc/.crypto_data chmod 400 /mnt/etc/.crypto_data/md1_header # Зробіть другу тимчасову копію md1_header у /boot на USB # Якщо ви не зможете завантажитись з першого разу # то вам не потрібно буде витягувати цей файл з образу initrd cp /tmp/keys/md1_header /mnt/boot/md1_header |
Чрутимся у встановлену систему
chroot /mnt bash --login
Переводимо sources на https.
apt update
apt install apt-transport-https ca-certificates
nano /etc/apt/sources.list
1 2 3 4 | # trixie
deb https://deb.debian.org/debian/ trixie main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security/ trixie-security main contrib non-free non-free-firmware
deb https://deb.debian.org/debian/ trixie-updates main contrib non-free non-free-firmware
|
Встановлюємо та налаштовуємо пакети:
1 2 3 4 5 6 7 8 9 | apt update apt install console-setup locales dpkg-reconfigure locales tzdata keyboard-configuration console-setup apt install linux-headers-amd64 linux-image-amd64 apt install cryptsetup mdadm lvm2 debootstrap gdisk zfsutils-linux openssh-server apt install dpkg-dev apt install zfs-initramfs echo REMAKE_INITRD=yes > /etc/dkms/zfs.conf |
Конфіги для mdadm та lvm
mdadm --detail --scan > /etc/mdadm/mdadm.conf
vgcfgbackup
Додаємо hook для initramfs
Цей скрипт додасть файл md1_header до initial ram disk (initrd).
nano /etc/initramfs-tools/hooks/crypto-header.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!/bin/sh PREREQ="" prereqs() { echo "$PREREQ" } case $1 in # get pre-requisites prereqs) prereqs exit 0 ;; esac . /usr/share/initramfs-tools/hook-functions copy_exec /etc/.crypto_data/md1_header /md1_header |
chmod 750 /etc/initramfs-tools/hooks/crypto-header.sh
fstab, crypttab, modules
Для ZFS нічого в fstab вказувати не треба.
nano /etc/fstab
1 2 3 | UUID=b5bd933b-51e9-4693-bf3b-d13307bbd885 /boot ext4 discard,noatime,nodiratime 0 2 UUID=4813-4190 /boot/efi vfat defaults 0 0 /dev/lvm_system/swap none swap sw 0 0 |
nano /etc/crypttab
1 2 | # <target name> <source device> <key file> <options> # ,x-initrd.attach md1_crypt /dev/md1 none luks,discard,header=/md1_header,initramfs |
nano /etc/initramfs-tools/modules
1 2 3 4 5 6 | md_mod
# raid1
zfs
spl
nls_cp437
nls_ascii
|
Коригування точок монтування ZFS
1 2 3 4 5 6 7 8 9 10 11 | mkdir /etc/zfs/zfs-list.cache touch /etc/zfs/zfs-list.cache/zroot zed -F & # Verify cat /etc/zfs/zfs-list.cache/zroot # Switch to foreground fg # Press Ctrl+C & remove '/mnt' sed -Ei "s|/mnt/?|/|" /etc/zfs/zfs-list.cache/* # Make snapshot zfs snapshot zroot/ROOT/trixie@install |
Налаштування GRUB та initrd
apt install cryptsetup cryptsetup-initramfs
apt install systemd-timesyncd
apt install grub-pc
apt install dosfstools
Якщо побачите цю помилку, то це нормально у випадку з ZFS root.
1 2 | cryptsetup: ERROR: Couldn't resolve device zroot/ROOT/trixie cryptsetup: WARNING: Couldn't determine root device |
update-initramfs -u -k all
nano /etc/default/grub
1 2 3 4 5 | GRUB_DEFAULT=0 GRUB_TIMEOUT=5 GRUB_DISTRIBUTOR=`( . /etc/os-release && echo ${NAME} )` GRUB_CMDLINE_LINUX_DEFAULT="" GRUB_CMDLINE_LINUX="root=ZFS=zroot/ROOT/trixie net.ifnames=0 biosdevname=0" |
update-grub
legacy BIOS MBR
grub-install /dev/sda
UEFI
1 2 3 4 5 6 7 8 | apt install grub-efi-amd64 shim-signed update-grub grub-install \ --target=x86_64-efi \ --efi-directory=/boot/efi \ --bootloader-id=debian \ --recheck \ --no-floppy |
Користувачі
1 2 3 4 5 6 7 8 | # Root password passwd root # Regular user groupadd --gid 1000 youruser adduser --home /home/youruser --ingroup youruser --uid 1000 youruser chmod -R ugo-xX,u=rwX,go-rwXx /home/youruser usermod -aG cdrom,floppy,audio,dip,video,plugdev,netdev,scanner,bluetooth,lpadmin youruser |
Exit & reboot
^D або Ctrl+D
Ви вийшли з чруту встановленої системи та знову в LiveCD. Розмонтуйте всі файлові системи ZFS.
1 2 3 4 | mount | grep -v zfs | tac | awk '/\/mnt/ {print $3}' | xargs -i{} umount -lf {} zfs umount -a umount /mnt zpool export -a |
reboot і можливо ви зможете завантажитись у вашу нову систему з завантажувальної USB-флешки.
Трохи детальніше про GRUB UEFI
Завантажувальна USB-флешка
blkid /dev/sda*
1 2 3 4 | /dev/sdb: PTUUID="70f483d1-859e-44de-9a93-ea46acdc886b" PTTYPE="gpt"/dev/sdb1: PARTLABEL="boot" PARTUUID="da022c89-87be-421a-bc48-cfd30136666e" /dev/sdb1: PARTLABEL="boot" PARTUUID="110dda04-a5e1-4c56-832c-9573c82c59ee" /dev/sdb2: LABEL_FATBOOT="EFI" LABEL="EFI" UUID="4813-4190" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="a88f91e5-2f12-411f-8d32-2ea944c231b6" /dev/sdb3: UUID="b5bd933b-51e9-4693-bf3b-d13307bbd885" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="0bae36b2-e05a-42d9-9567-589b9499d114" |
Зміст файлової системи vfat для /EFI
tree /boot/efi
1 2 3 4 5 6 7 8 9 10 11 12 13 | /boot/efi
└── EFI
├── BOOT
│ ├── BOOTX64.EFI
│ ├── grubx64.efi
│ └── mmx64.efi
└── debian
├── BOOTX64.CSV
├── fbx64.efi
├── grub.cfg
├── grubx64.efi
├── mmx64.efi
└── shimx64.efi
|
cat /boot/efi/EFI/debian/grub.cfg
1 2 3 | search.fs_uuid b5bd933b-51e9-4693-bf3b-d13307bbd885 root hd1,gpt3 set prefix=($root)'/grub' configfile $prefix/grub.cfg |
fs_uuid відповідає /dev/sdb3.
Якщо ви завантажилися успішно
Ви можете видалити md1_header з /boot, тому що він і так міститься всередині всіх /boot/initrd.img*.
rm -f /boot/md1_header
І зробити деяку кількість копій вашої завантажувальної флешки.
Самі вирішуйте, dd або копіювання файлів, пам’ятайте про grub-install.
Без цієї флешки, а точніше без md1_header ваші дані перетворяться на цеглу.
Якщо ви не змогли завантажитись
Завантажуєтесь знову у LiveCD.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | nano /etc/apt/sources.list # trixie deb http://deb.debian.org/debian/ trixie main contrib non-free non-free-firmware deb http://security.debian.org/debian-security/ trixie-security main contrib non-free non-free-firmware deb http://deb.debian.org/debian/ trixie-updates main contrib non-free non-free-firmware apt update apt install cryptsetup mdadm lvm2 linux-headers-generic debootstrap gdisk openssh-server linux-headers-6.12.63+deb13-amd64 linux-headers-6.12.63+deb13-common apt install linux-headers-6.12.63+deb13-amd64 linux-headers-6.12.63+deb13-common apt install zfsutils-linux zfs-dkms # nano /etc/ssh/sshd_config # printf '%s\n' "PermitRootLogin yes" >> /etc/ssh/sshd_config # systemctl restart sshd.service mdadm --detail --scan mdadm --stop /dev/md127 mdadm --assemble /dev/md1 /dev/nvme0n1p1 mkdir /tmp/usb mount /dev/sda3 /tmp/usb cp /tmp/usb/md1_header /tmp/md1_header umount /dev/sda3 cryptsetup luksOpen /dev/md1 --allow-discards --header /tmp/md1_header md1_crypt pvscan vgchange -a y modprobe zfs zpool import -f zroot # zpool import -d /dev/mapper/md1_crypt zroot zfs set mountpoint=legacy zroot/ROOT/debian mount -t zfs zroot/ROOT/debian /mnt # or # zfs mount zroot/ROOT/debian mount --rbind /dev /mnt/dev mount --rbind /proc /mnt/proc mount --rbind /sys /mnt/sys mount -t devpts devpts /mnt/dev/pts mount /dev/sda3 /mnt/boot mount /dev/sda2 /mnt/boot/efi chroot /mnt bash --login |
І виконайте необхідні кроки.
Debuging initrd.img
Щоб переконатися, що /md1_header був скопійований hook-скриптом до initrd, можна використати unmkinitramfs.
1 2 3 4 5 6 | mkdir /tmp/debug cp /boot/initrd.img-6.12.63+deb13-amd64 /tmp/debug/ cd /tmp/debug/ unmkinitramfs -v initrd.img-6.12.63+deb13-amd64 . # header exists? ls -la ./md1_header |
Сподіваюся, що нічого не забув. За мотивами Debian Trixie Root on ZFS.