Установка Archlinux c полным шифрованием системы и LVM на LUKS
В данном посте вы прочитаете немного о моих странных изыскания во время вынужденного отпуска по болезни. Речь пойдёт сразу о нескольких вещах, которые не являются «best practice», но так же тоже можно! Итак, здесь будет туториал о том, как установить Archlinux(мой любимый дистр) так, чтобы:
- без отдельного /boot (просто в /root)
- / на lvm
- lvm внутри luks-контейнера
- с UEFI
- в виртуальной машине.
с secure boot(«сложна», в виртуалке вряд ли получится)
Если заинтересовались, — добро пожаловать под кат!
Сначала я настроил это всё на моём ноутбуке Lenovo X240, потом для написания статьи пользовался уже виртуальной машиной с OVMF в Proxmox.
Настройка тестового стенда:
Создаётся всё достаточно стандартно. Образом используется мой любимый арч, который можно всегда загрузить с яндекса.
Далее несколько моментов по виртуалке в Proxmox относительно UEFI. Чтобы протестировать работу стенда с UEFI(иначе не будет так интересно), нужно в свойствах виртуальной машины выставить OVMF вместо SeaBIOS:
Далее соответственно добавить UEFI-диск, чтобы получилось примерно так:
Теперь можем стартовать виртуальную машину и начинать процесс установки. В консоли виртуальной машины сразу стартуем сервис sshd, задаём пароль root и узнаём dhcp-адрес виртуальной машины:
Далее мы можем продолжить работу по ssh чтобы было удобнее.
Разметка дисков
Итак, уже подключившись по ssh мы для начала устанавливаем время, чтобы потом не оказалось, что файловые системы созданы в будущем:
timedatectl set-ntp true && timedatectl set-timezone Europe/Moscow
root@archiso ~ # timedatectl Local time: Tue 2018-08-14 13:42:03 MSK Universal time: Tue 2018-08-14 10:42:03 UTC RTC time: Tue 2018-08-14 10:42:04 Time zone: Europe/Moscow (MSK, +0300) System clock synchronized: yes NTP service: active RTC in local TZ: no
Теперь можем приступать к разметке диска. На данном этапе у меня есть диск /dev/vda, т.к. контроллер Virtio и это просто пустой диск без таблицы разделов:
root@archiso ~ # fdisk -l /dev/vda Disk /dev/vda: 15 GiB, 16106127360 bytes, 31457280 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes
Разбивать его будем на 2 партиции:
root@archiso ~ # gdisk /dev/vda GPT fdisk (gdisk) version 1.0.4 Command (? for help): o This option deletes all partitions and creates a new protective MBR. Proceed? (Y/N): y
Далее создаём первую партицию для EFI с типом EF00 (EFI System Partition):
Command (? for help): n Partition number (1-128, default 1): First sector (34-31457246, default = 2048) or size: Last sector (2048-31457246, default = 31457246) or size: +512M Current type is 'Linux filesystem' Hex code or GUID (L to show codes, Enter = 8300): EF00 Changed type of partition to 'EFI System'
Теперь создаём партицию для LUKS, где даже не будем заморачиваться с типом и оставим как есть:
Command (? for help): n Partition number (2-128, default 2): First sector (34-31457246, default = 1050624) or size: Last sector (1050624-31457246, default = 31457246) or size: Current type is 'Linux filesystem' Hex code or GUID (L to show codes, Enter = 8300): Changed type of partition to 'Linux filesystem'
Запишем изменения и закончим с разметкой партиций:
Command (? for help): w Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING PARTITIONS!! Do you want to proceed? (Y/N): y OK; writing new GUID partition table (GPT) to /dev/vda. The operation has completed successfully.
Создание LUKS-контейнера и файловых систем
C первым разделом(vda1) всё достаточно просто. Нам нужно его просто отформатировать и пока на этом всё:
root@archiso ~ # mkfs.vfat /dev/vda1 mkfs.fat 4.1 (2017-01-24)
Вторая партиция это контейнер, который нужно сначала подготовить. Форматируем партицию через cryptsetup и задаём парольную фразу:
root@archiso ~ # cryptsetup -v luksFormat /dev/vda2 WARNING! ======== This will overwrite data on /dev/vda2 irrevocably. Are you sure? (Type uppercase yes): YES Enter passphrase for /dev/vda2: Verify passphrase: Command successful.
*** я не стал заморачиваться с выбором шифров, с затиранием рандомом урандомом и прочим, а просто создал контейнер по умолчанию.
Далее открываем контейнер указывая ту же парольную фразу:
root@archiso ~ # cryptsetup luksOpen /dev/vda2 container Enter passphrase for /dev/vda2:
Теперь у нас есть открытый контейнер, доступной через device mapper:
root@archiso ~ # ls -l /dev/mapper | grep container lrwxrwxrwx 1 root root 7 Aug 14 14:01 container -> ../dm-0
Теперь мы можем продолжить с lvm(напишу по-быстрому, так как это не сабж):
root@archiso ~ # pvcreate /dev/mapper/container Physical volume "/dev/mapper/container" successfully created. root@archiso ~ # vgcreate rootvg /dev/mapper/container Volume group "rootvg" successfully created root@archiso ~ # lvcreate -L1G -n swap rootvg Logical volume "swap" created. root@archiso ~ # lvcreate -L5G -n root rootvg Logical volume "root" created. root@archiso ~ # lvcreate -L2G -n home rootvg Logical volume "home" created. root@archiso ~ # lvs LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert home rootvg -wi-a----- 2.00g root rootvg -wi-a----- 5.00g swap rootvg -wi-a----- 1.00g
Далее создадим файловые системы на наших lv:
root@archiso ~ # mkfs.ext4 -L root /dev/mapper/rootvg-root mke2fs 1.44.3 (10-July-2018) . Writing superblocks and filesystem accounting information: done [root@archiso ~]# mkfs.ext4 -L home /dev/mapper/rootvg-home mke2fs 1.44.3 (10-July-2018) Creating filesystem with 524288 4k blocks and 131072 inodes . Writing superblocks and filesystem accounting information: done [root@archiso ~]# mkswap -L swap /dev/mapper/rootvg-swap . LABEL=swap, UUID=98b0bc31-1c62-4fec-bb97-e1913d1e8cb4
Теперь это всё можно примонтировать для установки базовой системы. Точкой установки будет /mnt, где будет начинаться корень нашей будущей системы:
[root@archiso ~]# mount /dev/mapper/rootvg-root /mnt/ [root@archiso ~]# mkdir -p /mnt/
*** /boot/efi я создаю, чтобы сам /boot остался на /dev/mapper/rootvg-root, а папка efi уже для монтирования в неё /dev/vda1(fat32 efi partition):
[root@archiso ~]# mount /dev/vda1 /mnt/boot/efi/ [root@archiso ~]# mount /dev/mapper/rootvg-home /mnt/home/ [root@archiso ~]# swapon /dev/mapper/rootvg-swap
Проверим текуoие точки монтирования(всегда полезно):
[root@archiso ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT loop0 7:0 0 462.5M 1 loop /run/archiso/sfs/airootfs sr0 11:0 1 573M 0 rom /run/archiso/bootmnt vda 254:0 0 15G 0 disk ├─vda1 254:1 0 512M 0 part /mnt/boot/efi └─vda2 254:2 0 14.5G 0 part └─container 253:0 0 14.5G 0 crypt ├─rootvg-swap 253:1 0 1G 0 lvm [SWAP] ├─rootvg-root 253:2 0 5G 0 lvm /mnt └─rootvg-home 253:3 0 2G 0 lvm /mnt/home
Как мы видим, всё честно и теперь время ставить сам арч.
Установка базовой системы
Устанавливаем базовые пакеты из наборов base и base-devel используя пакет pacstrap( им можно поставить всё, что вы хотите и кроме этого):
pacstrap /mnt base base-devel
Всё прекрасно загрузилось, базовая система готова. Вывод я, естественно, убрал. Теперь мы можем настроить эту самую систему, чтобы она загрузилась и работала.
Из базовых вещей сразу сгенерируем fstab:
genfstab -pU /mnt >> /mnt/etc/fstab
Далее сделаем arch-chroot в эту новую систему:
[root@archiso ~]# arch-chroot /mnt
*** arch-chroot очень даже годная утилита, потому как она делает всё сама. Хотя вы всегда можете воспользоваться стандартным chroot, перед этим выполнив всё по инструкции gentoo-handbook wiki.gentoo.org/wiki/Handbook:AMD64/Installation/Base раздел «Mounting the necessary filesystems»
Cразу настроим системное время и hostname:
ln -s /usr/share/zoneinfo/Europe/Moscow /etc/localtime && \ hwclock --systohc && \ echo luks-test > /etc/hostname
[root@archiso /]# passwd root New password: Retype new password: passwd: password updated successfully
Раскомментируем нужные локали в /etc/locale.gen:
[root@archiso /]# vi /etc/locale.gen [root@archiso /]# grep -v '^#' /etc/locale.gen en_US ISO-8859-1 en_US.UTF-8 UTF-8 ru_RU.UTF-8 UTF-8 ru_RU ISO-8859-5
[root@archiso /]# locale-gen Generating locales. en_US.ISO-8859-1. done en_US.UTF-8. done ru_RU.UTF-8. done ru_RU.ISO-8859-5. done Generation complete
Сразу их настроим для системы и консоли:
[root@archiso /]# echo LANG=en_US.UTF-8 > /etc/locale.conf [root@archiso /]# echo KEYMAP=ru > /etc/vconsole.conf [root@archiso /]# echo FONT=cyr-sun16 >> /etc/vconsole.conf
Теперь настроим файл /etc/mkinitcpio.conf, который у нас отвечает за опции, хуки и прочее при генерации initramfs:
Самое главное здесь хуки и их порядок:
HOOKS=(base udev autodetect modconf block keymap encrypt lvm2 resume filesystems keyboard fsck)
*** хук resume для загрузки системы после гибернации из swap. На виртуалке он не нужен. Скопировал его с бука.
Теперь мы можем сгенерировать initramfs:
[root@archiso /]# mkinitcpio -p linux ==> Building image from preset: /etc/mkinitcpio.d/linux.preset: 'default' -> -k /boot/vmlinuz-linux -c /etc/mkinitcpio.conf -g /boot/initramfs-linux.img ==> Starting build: 4.17.14-arch1-1-ARCH -> Running build hook: [base] -> Running build hook: [udev] -> Running build hook: [autodetect] -> Running build hook: [modconf] -> Running build hook: [block] -> Running build hook: Arch linux установка habr -> Running build hook: [encrypt] -> Running build hook: [lvm2] -> Running build hook: [resume] -> Running build hook: [filesystems] -> Running build hook: Arch linux установка habr -> Running build hook: [fsck] ==> Generating module dependencies ==> Creating gzip-compressed initcpio image: /boot/initramfs-linux.img ==> Image generation successful
Теперь, когда у нас есть система, нам нужно установить сам загрузчик. Мой выбор пал на grub(2), потому как он как-то роднее и достаточно легко умеет загружать ядро с зашифрованного раздела(ну или я особо не искал другие).
[root@archiso /]# pacman -S grub dosfstools efibootmgr mtools
Перед генерацией конфига отредактируем дефолтные опции grub:
здесь нужно раскомментить одну важную строчку(без коммента, естественно):
# Uncomment to enable booting from LUKS encrypted devices GRUB_ENABLE_CRYPTODISK=y
и добавить(там пусто по умолчанию) в GRUB_CMDLINE_LINUX:
GRUB_CMDLINE_LINUX="cryptdevice=UUID=5ad7c9ad-fb17-4839-925e-479432516c07:container"
[root@archiso /]# blkid | grep vda2 /dev/vda2: UUID="5ad7c9ad-fb17-4839-925e-479432516c07" TYPE="crypto_LUKS" PARTLABEL="Linux filesystem" PARTUUID="667a1243-17ff-4f03-952c-5afd5e3415cc"
Генерируем конфиг для grub:
[root@archiso /]# grub-mkconfig -o /boot/grub/grub.cfg Generating grub configuration file . WARNING: Failed to connect to lvmetad. Falling back to device scanning. Found linux image: /boot/vmlinuz-linux Found initrd image: /boot/initramfs-linux.img Found fallback initrd image(s) in /boot: initramfs-linux-fallback.img WARNING: Failed to connect to lvmetad. Falling back to device scanning. done
Далее устанавливаем сам grub на диск:
[root@archiso /]# grub-install /dev/vda Installing for x86_64-efi platform. . Installation finished. No error reported.
*** можно добавить —recheck —debug, указать архитектуру… но… оно ведь само и так работает)
Теперь отредактируем /etc/crypttab, чтобы сама система знала, что при загрузке надо расшифровывать LUKS раздел. Добавим строчку:
echo "container /dev/vda2 none" >> /etc/crypttab
Которая означает, что надо запрашивать пароль(none) для раздела /dev/vda2 и представлять его уже как container через device mapper.
Теперь мы готовы выйти из chroot и перезагрузить систему:
[root@archiso /]# exit exit [root@archiso ~]# reboot Welcome back!
Теперь обратимся к консоли виртуальной машины чтобы увидеть результат:
На данном этапе у нас запустилось EFI-приложение /boot/efi/EFI/arch/grubx64.efi с /dev/vda1, которое запрашивает у нас пароль, чтобы расшифровать наш контейнер.
Здесь уже привычное окно grub с нашими опциями загрузки из /boot/grub/grub.cfg.
На данном этапе grub расшифровал наш контейнер и получил доступ к этом самому файлу (/boot/grub/grub.cfg), ядру и initramfs. После выбора опции по умолчанию загрузится ядро, initramfs:
Активно, ядро и дело дошло до хука encrypt, который заново спрашивает нас пароль для расшифровки контейнера( вообще влом 2 раза вводить пароль, но может быть так, что вы от излишка паранойи сделаете 2 контейнера для boot и root 🙂
И далее уже после полной загрузки системы:
PS: для повышения уровня шизофрении здесь не хватает только secure boot, чтобы подписать наш загрузчик grubx64.efi.
Просто положить ядро и initramfs на /dev/vda1 я счёл безыинтересным, так как 100 раз так уже делал. Другие загрузчики типа SHIM, bootctl и прочее не умеют вытворять подобного(ну и ли я не в курсе — расскажите в комментах )