Хабрахабр

Установка Archlinux c полным шифрованием системы и LVM на LUKS

В данном посте вы прочитаете немного о моих странных изыскания во время вынужденного отпуска по болезни. Речь пойдёт сразу о нескольких вещах, которые не являются «best practice», но так же тоже можно! Итак, здесь будет туториал о том, как установить Archlinux(мой любимый дистр) так, чтобы:

  • без отдельного /boot (просто в /root)
  • / на lvm
  • lvm внутри luks-контейнера
  • с UEFI
  • в виртуальной машине.
  • с secure boot(«сложна», в виртуалке вряд ли получится)

Примечательно, что зашифровано будет всё, кроме EFI system partition с единственным файлом grubx64.efi — EFI-приложением для запуска grub.

Если заинтересовались, — добро пожаловать под кат!
Сначала я настроил это всё на моём ноутбуке Lenovo X240, потом для написания статьи пользовался уже виртуальной машиной с OVMF в Proxmox.

Настройка тестового стенда:

Создаётся всё достаточно стандартно. Образом используется мой любимый арч, который можно всегда загрузить с яндекса.

Чтобы протестировать работу стенда с UEFI(иначе не будет так интересно), нужно в свойствах виртуальной машины выставить OVMF вместо SeaBIOS: Далее несколько моментов по виртуалке в Proxmox относительно UEFI.

Далее соответственно добавить 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 партиции:

  • fat32 диск для UEFI приложений(EFI_system_partition)
  • LUKS контейнер со всем остальным

Используем gdisk для создания GPT:


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{KMGTP}:
Last sector (2048-31457246, default = 31457246) or {+-}size{KMGTP}: +512M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): <b>EF00</b>
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{KMGTP}:
Last sector (1050624-31457246, default = 31457246) or {+-}size{KMGTP}:
<b>Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'</b>

Запишем изменения и закончим с разметкой партиций:


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/{home,boot/efi}

*** /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:


[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 FOND=cyr-sun16 >> /etc/vconsole.conf

Теперь настроим файл /etc/mkinitcpio.conf, который у нас отвечает за опции, хуки и прочее при генерации initramfs:

vi /etc/mkinitcpio.conf

Самое главное здесь хуки и их порядок:

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: [keymap] -> Running build hook: [encrypt] -> Running build hook: [lvm2] -> Running build hook: [resume] -> Running build hook: [filesystems] -> Running build hook: [keyboard] -> Running build hook: [fsck]
==> Generating module dependencies
==> Creating gzip-compressed initcpio image: /boot/initramfs-linux.img
==> Image generation successful

Теперь, когда у нас есть система, нам нужно установить сам загрузчик. Мой выбор пал на grub(2), потому как он как-то роднее и достаточно легко умеет загружать ядро с зашифрованного раздела(ну или я особо не искал другие).

Установим пакет grub:


[root@archiso /]# pacman -S grub dosfstools efibootmgr mtools

Перед генерацией конфига отредактируем дефолтные опции grub:


vim /etc/default/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"

UUID я взял из blkid:

[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, которое запрашивает у нас пароль, чтобы расшифровать наш контейнер.

Далее, после ввода пароля:

После выбора опции по умолчанию загрузится ядро, initramfs: Здесь уже привычное окно grub с нашими опциями загрузки из /boot/grub/grub.cfg.
На данном этапе grub расшифровал наш контейнер и получил доступ к этом самому файлу (/boot/grub/grub.cfg), ядру и initramfs.

Активно, ядро и дело дошло до хука encrypt, который заново спрашивает нас пароль для расшифровки контейнера( вообще влом 2 раза вводить пароль, но может быть так, что вы от излишка паранойи сделаете 2 контейнера для boot и root 🙂

И далее уже после полной загрузки системы:

PS: для повышения уровня шизофрении здесь не хватает только secure boot, чтобы подписать наш загрузчик grubx64.efi.

Другие загрузчики типа SHIM, bootctl и прочее не умеют вытворять подобного(ну и ли я не в курсе — расскажите в комментах ) Просто положить ядро и initramfs на /dev/vda1 я счёл безыинтересным, так как 100 раз так уже делал.

Полезные материалы по теме и использованные материалы

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть