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

в 13:49, , рубрики: fun, linux, luks, lvm2, security, Настройка Linux

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

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

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

Если заинтересовались, — добро пожаловать под кат!

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

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

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

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

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

Далее соответственно добавить UEFI-диск, чтобы получилось примерно так:

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

Теперь можем стартовать виртуальную машину и начинать процесс установки. В консоли виртуальной машины сразу стартуем сервис sshd, задаём пароль root и узнаём dhcp-адрес виртуальной машины:

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

Далее мы можем продолжить работу по 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!

Теперь обратимся к консоли виртуальной машины чтобы увидеть результат:

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

На данном этапе у нас запустилось EFI-приложение /boot/efi/EFI/arch/grubx64.efi с /dev/vda1, которое запрашивает у нас пароль, чтобы расшифровать наш контейнер.

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

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

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

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

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

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

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

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

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

Автор: Станислав

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js