• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья LUKS good! Ставим Linux на шифрованный раздел и делаем удобной работу с ним

tabac

CPU register
Пользователь
Регистрация
30.09.2018
Сообщения
1 610
Решения
1
Реакции
3 332
Сегодня полнодисковое шифрование — это норма. В Windows для этого есть BitLocker, в macOS — FileVault и APFS. В Linux для тех же целей служит dm-crypt и LUKS. В этой статье я покажу, как установить ОС на шифрованный корневой раздел, настроить авторазблокировку при загрузке с помощью модуля TPM и новой фичи systemd-cryptsetup, а также резервировать ключ восстановления в Active Directory. Все трюки будем делать в Arch Linux, хотя ты с легкостью сможешь повторить их в своем любимом дистрибутиве.

Шифрование дисков в Linux реализуется с помощью подсистемы dm-crypt Crypto API (встроено в ядро начиная с версии 2.6). Подсистема dm-crypt работает благодаря модулю ядра, который отображает шифрованный диск в виртуальное устройство. На вид оно ничем не отличается от обычного блочного устройства хранения данных. Для управления ключами шифрования используется раздел LUKS (Linux Unified Key Setup). Формат LUKS позволяет использовать до восьми ключей шифрования для одного раздела.

КАК УСТРОЕН РАЗДЕЛ LUKS​

Раздел LUKS имеет следующий формат.
partition.png

Он начинается с заголовка phdr, далее за ним следуют слоты с ключевыми данными (KM1, KM2, ..., KM8). За ключевыми данными располагаются данные, шифрованные мастер‑ключом.

Заголовок phdr хранит информацию о протоколе и режиме шифрования, длину ключей, идентификатор UUID и контрольную сумму мастер‑ключа.

В LUKS для одного зашифрованного раздела зарезервировано восемь слотов, в каждом из которых может храниться отдельный ключ. Любой из восьми ключей может быть использован для расшифровки раздела.

Заголовок и слоты ключей можно хранить на другом физическом носителе, отдельно от зашифрованных данных, тем самым реализуя многофакторную защиту. Но при утрате заголовка или слотов получить доступ к зашифрованным данным становится невозможно.

Для управления шифрованием дисков используется утилита cryptsetup.

С помощью этой утилиты возможно:
  • создавать шифрованные разделы LUKS;
  • открывать и закрывать разделы LUKS;
  • управлять слотами ключей;
  • дампить заголовок LUKS и мастер‑ключ.
Для работы cryptsetup требуются права суперпользователя и пароль шифрования.

ШИФРУЕМ​

Переходим к практике! Шифровать мы будем только рутовый раздел. Есть, конечно, экзотические кейсы, когда, помимо раздела root, шифруется еще и раздел boot, но такая конфигурация поддерживается не всеми загрузчиками и не считается стандартной и рекомендованной. Мы же вообще не будем использовать загрузчик, так что оставляем boot в покое и шифруем все остальное.

Начнем собирать нашу систему, загрузившись с установочного диска.

Для начала разметим диск следующим образом: sda1 для /boot, sda2 для /. Схему разделов выбираем GPT.
Код:
$ parted /dev/sda mklabel gpt mkpart primary fat32 1MiB 501MiB
$ parted /dev/sda set 1 esp on
$ parted /dev/sda mkpart primary btrfs 501MiB 100%
Далее создадим наш LUKS на sda2.
Код:
$ cryptsetup luksFormat /dev/sda2
WARNING!
========
This will overwrite data on /dev/sda2 irrevocably.
Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/sda2:
Verify passphrase:
cryptsetup luksFormat /dev/sda2  18.16s user 1.88s system 80% cpu 24.742 total
Взглянем теперь на LUKS.
Код:
$ cryptsetup luksDump /dev/sda2
LUKS header information
Version:        2
Epoch:          3
Metadata area:  16384 [bytes]
Keyslots area:  16744448 [bytes]
UUID:           e04b5b87-6bfc-4f73-83b0-36f91d52f141
Label:          (no label)
Subsystem:      (no subsystem)
Flags:          (no flags)
Data segments:
0: crypt
offset: 16777216 [bytes]
length: (whole device)
cipher: aes-xts-plain64
sector: 512 [bytes]
Keyslots:
0: luks2
Key:        512 bits
Priority:   normal
Cipher:     aes-xts-plain64
Cipher key: 512 bits
PBKDF:      argon2i
Time cost:  7
Memory:     483194
Threads:    2
Salt:       a8 d7 82 ce 89 c8 0f d6 29 18 83 e5 5d 9d a7 f1
a2 6d 66 81 70 db c4 82 cc fb ae 81 4c 7f ed 0c
AF stripes: 4000
AF hash:    sha256
Area offset:32768 [bytes]
Area length:258048 [bytes]
Digest ID:  0
Tokens:
Digests:
0: pbkdf2
Hash:       sha256
Iterations: 149967
Salt:       87 ac 6f 61 75 fb 91 14 63 5d ca 5d 1c 25 ef 42
7b af 51 63 34 eb 26 d5 d7 be 7a 78 7b 2a 25 f1
Digest:     da e7 fd 26 59 85 5d 5e 34 79 2a fa 20 95 f1 83
13 10 0d 0e a3 58 a6 0e 33 b0 f0 73 e8 0a a1 1e
Видно, что мы задействовали один из восьми доступных слотов с ключами — доступ к нему ограничен паролем.

Алгоритм шифрования по умолчанию (aes-xts-plain64) нас устроит. Перечень всех поддерживаемых алгоритмов зависит от ядра (загляни в /proc/crypto). Можно протестировать работу с ними.
Код:
$ cryptsetup benchmark
# Tests are approximate using memory only (no storage IO)
PBKDF2-sha1      1817289 iterations per second for 256-bit key
PBKDF2-sha256    2302032 iterations per second for 256-bit key
PBKDF2-sha512    1646116 iterations per second for 256-bit key
PBKDF2-ripemd160  903944 iterations per second for 256-bit key
PBKDF2-whirlpool  681778 iterations per second for 256-bit key
argon2i    N/A
argon2id   N/A
# Algorithm |       Key |      Encryption |      Decryption
aes-cbc        128b      1126.9 MiB/s      2966.7 MiB/s
serpent-cbc        128b        98.6 MiB/s       736.0 MiB/s
twofish-cbc        128b       226.0 MiB/s       404.9 MiB/s
aes-cbc        256b       868.5 MiB/s      2594.2 MiB/s
serpent-cbc        256b       107.9 MiB/s       779.9 MiB/s
twofish-cbc        256b       241.6 MiB/s       433.4 MiB/s
aes-xts        256b      3152.7 MiB/s      3146.5 MiB/s
serpent-xts        256b       676.5 MiB/s       665.9 MiB/s
twofish-xts        256b       400.6 MiB/s       410.4 MiB/s
aes-xts        512b      2614.9 MiB/s      2600.2 MiB/s
serpent-xts        512b       687.1 MiB/s       711.3 MiB/s
twofish-xts        512b       413.0 MiB/s       417.2 MiB/s
cryptsetup benchmark  9.54s user 23.98s system 107% cpu 31.226 total
Откроем раздел.
Код:
$ cryptsetup open /dev/sda2 cryptroot
Enter passphrase for /dev/sda2:
После этих манипуляций у нас в системе стал доступен новый раздел cryptroot.
Код:
$ lsblk /dev/sda
NAME          MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINTS
sda             8:0    0    8G  0 disk
├─sda1 8:1    0  500M  0 part
└─sda2 8:2    0  7.5G  0 part
└─cryptroot 253:0    0  7.5G  0 crypt
Создадим на разделах файловые системы.
Код:
$ mkfs.fat -F32 /dev/sda1
$ mkfs.btrfs -f -L "archroot" /dev/mapper/cryptroot
Для продолжения установки примонтируем наши разделы.
Код:
$ mount /dev/mapper/cryptroot /mnt
$ btrfs subvolume create /mnt/@root
$ btrfs subvolume create /mnt/@home
$ umount /mnt
$ mount /dev/mapper/cryptroot /mnt -o subvol=@root,ssd,noatime,space_cache,compress=zstd
$ mkdir /mnt/home
$ mount /dev/mapper/cryptroot /mnt/home -o subvol=@home,ssd,noatime,space_cache,compress=zstd
$ mkdir /mnt/boot
$ mount /dev/sda1 /mnt/boot
Заглядывая одним глазом в вики, устанавливаем систему обычным образом.

Не забудем включить хук encrypt при создании initramfs.
Код:
$ vim /etc/mkinitcpio.conf
HOOKS=(base udev autodetect keyboard keymap modconf block encrypt filesystems)
$ mkinitcpio -p linux
Финальный этап — настройка UEFI для загрузки нашего ядра. Напоминаю, что мы обойдемся без GRUB и будем загружать ядро напрямую, используя фичу EFISTUB.

Добавляем запись в UEFI.
Код:
$ efibootmgr \
--create \
--bootnum=0000 \
--label "Arch Linux" \
--disk /dev/sda \
--part 1 \
--loader /vmlinuz-linux \
--unicode 'cryptdevice=/dev/sda2:cryptroot root=/dev/mapper/cryptroot rootflags=subvol=@root rw initrd=\initramfs-linux.img' \
--verbose
Особое внимание обрати на параметры ядра! Без них система просто не сможет найти шифрованный раздел.

Перезагружаемся и убеждаемся, что все работает, как мы хотели: на этапе загрузки требуется ввод пароля для расшифрования раздела.
first_reboot

НАСТРАИВАЕМ АВТОРАЗБЛОКИРОВКУ​

Хотелось бы не вводить пароль при загрузке каждый раз. Для этого нужно настроить авторазблокировку LUKS с помощью чипа TPM.

Убедимся, что мы счастливые обладатели TPM. Необходимая версия TPM — 2.0.
Код:
$ test -e /dev/tpm0 && echo PASS || echo FAIL
PASS
$ cat /sys/class/tpm/tpm0/device/description
TPM 2.0 Device
or
$ cat /sys/class/tpm/tpm0/tpm_version_major
2
Авторазблокировку сделаем с помощью относительно новой фичи systemd-cryptsetup. Systemd-cryptsetup добавлена в systemd начиная с версии 248.

Для начала необходимо проверить нашу версию systemd.
Код:
$ systemctl --version
systemd 249 (249.2-1-arch)
+PAM +AUDIT -SELINUX -APPARMOR -IMA +SMACK +SECCOMP +GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY +P11KIT -QRENCODE +BZIP2 +LZ4 +XZ +ZLIB +ZSTD +XKBCOMMON +UTMP -SYSVINIT default-hierarchy=unified
Все отлично. Для работы с TPM нужно дополнительно установить пакет tpm2-tss.
Код:
$ pacman -Sy tpm2-tss
Далее добавим ключ TPM в слот LUKS с помощью тулзы systemd-cryptenroll.
Код:
$ systemd-cryptenroll /dev/sda2 --tpm2-device=auto --tpm2-pcrs=0,4
Не забываем проверить.
Код:
$ systemd-cryptenroll /dev/sda2
SLOT TYPE
---------
0 password
1 tpm2
В команде выше мы указали параметр --tpm2-pcrs=0,4. Что такое PCR? Вот определение из Википедии:
PCR — это внутренние регистры памяти TPM, в которых в зашифрованном виде содержится вся информация о целостности метрик системы, начиная с загрузки BIOS до завершения работы системы. Информация, содержащаяся в PCR, формирует корень доверия для измерений (RTM). Могут храниться как в энергонезависимой, так и в энергозависимой памяти. Эти регистры сбрасываются при старте и при перезагрузке системы. Спецификация предписывает минимальное количество регистров (16), каждый регистр содержит 160 бит информации. Регистры 0–7 зарезервированы для нужд TPM. Регистры 8–15 доступны для использования операционной системой и приложениями. Изменения значений PCR необратимы, и их значения нельзя записать напрямую, их можно только расширить новыми значениями, которые зависят от предыдущих. Все изменения значений PCR записываются в лог изменений, который хранится в энергозависимой памяти.
PCRUSE
PCR0Core System Firmware executable code (aka Firmware)
PCR1Core System Firmware data (aka UEFI settings)
PCR2Extended or pluggable executable code
PCR3Extended or pluggable firmware data
PCR4Boot Manager
PCR5GPT / Partition Table
PCR6Resume from S4 and S5 Power State Events
PCR7Secure Boot State
PCR8Hash of the booted kernel
PCR 9 to 10Reserved for Future Use
PCR11BitLocker Access Control
PCR12Data events and highly volatile events
PCR13Boot Module Details
PCR14Boot Authorities
PCR 15 to 23Reserved for Future Use
Для включения systemd-cryptsetup необходимо добавить в /etc/mkinicpio.conf хуки systemd и sd-encrypt.
Код:
HOOKS=(base systemd modconf block keyboard sd-encrypt filesystems fsck)
$ mkinicpio -P
Наконец, изменим строку загрузки, добавив параметры rd.luks.name и rd.luks.name.
Код:
$ blkid /dev/sda2
/dev/sda2: UUID="e04b5b87-6bfc-4f73-83b0-36f91d52f141" TYPE="crypto_LUKS" PARTLABEL="primary" PARTUUID="136ffe26-5569-4c76-a871-9025ea52dbd8"
$ efibootmgr \
--create \
--bootnum=0001 \
--label "Arch Linux" \
--disk /dev/sda \
--part 1 \
--loader /vmlinuz-linux \
--unicode 'rd.luks.name=e04b5b87-6bfc-4f73-83b0-36f91d52f141=cryptroot rd.luks.options=tpm2-device=auto root=/dev/mapper/cryptroot rootflags=subvol=@root rw initrd=\initramfs-linux.img' \
--verbose
Перезагружаемся и проверяем, что все работает как надо.

Для тех, кому systemd-cryptsetup по каким‑то причинам не подходит (например, версия systemd старая или вообще нет systemd), могу порекомендовать фреймворк Clevis. С его помощью можно реализовать следующие сценарии авторазблокировки LUKS:
  • tpm2 — разблокировка с TPM;
  • tang — разблокировка с сетевого сервера.
Вот как использовать Сlevis с TPM:
Код:
$ clevis luks bind -d /dev/sda2 tpm2 '{"pcr_bank":"sha1","pcr_ids":"0,4"}'
Enter existing LUKS password: ***************
Проверяем.
Код:
$ sudo clevis luks list -d /dev/sda2
1: tpm2 '{"hash":"sha256","key":"ecc","pcr_bank":"sha1","pcr_ids":"0,4"}
Вариант с сервером tang настраивается не сложнее (разумеется, заранее разворачиваем tang и обеспечиваем сетевую доступность):
Код:
$ sudo clevis luks bind -d /dev/sda2 tang '{"url":"http://192.168.88.101:7500"}'
The advertisement contains the following signing keys:
QjvwIdUeor3gBqxLteIOKvWPRqM
Do you wish to trust these keys? [ynYN] y
Enter existing LUKS password:
Проверяем.
Код:
$ sudo clevis luks list -d /dev/sda2
1: tpm2 '{"hash":"sha256","key":"ecc","pcr_bank":"sha1","pcr_ids":"0,4"}'
2: tang '{"url":"http://192.168.88.101:7500"}'
В заключение темы авторазблокировки стоит упомянуть некоторые ограничения фреймворка Clevis:
  • Clevis работает только с TPM 2.0; TPM 1.2 не поддерживается.
  • В Tang не реализован механизм смены ключей.
  • Для Tang необходима доступность сети на этапе загрузки, поэтому, например, для Wi-Fi-подключения требуется дополнительная настройка адаптера в initrd.

СОЗДАНИЕ КЛЮЧЕЙ ВОССТАНОВЛЕНИЯ​

Бэкапы ключей в таком деле, как шифрование, должны быть, об этом знает каждый.

Есть два варианта создания ключей восстановления:
  • дамп заголовка и мастер‑ключа;
  • запись пароля восстановления в Active Directory.

Делаем копию мастер-ключа​

Сделать резервную копию заголовка и мастер‑ключа можно с помощью хорошо известной нам утилиты cryptsetup. С помощью созданной копии можно будет получить доступ к разделу, не зная пароль, поэтому нас заботливо предупреждают, что хранить ее нужно в секрете!
Код:
$ cryptsetup luksDump --dump-master-key /dev/sda2 --master-key-file mk.dump
WARNING!
========
The header dump with volume key is sensitive information
that allows access to encrypted partition without a passphrase.
This dump should be stored encrypted in a safe place.
Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/sda2:
LUKS header information for /dev/sda2
Cipher name:    aes
Cipher mode:    xts-plain64
Payload offset: 32768
UUID:           e04b5b87-6bfc-4f73-83b0-36f91d52f141
MK bits:        512
Key stored to file mk.dump
$ xxd mk.dump
00000000: 1501 eccc 84fd 82f7 f53b 56ae 4ab8 5775  .........;V.J.Wu
00000010: 4968 ea61 8d01 1f29 985e 33af 5537 ba40  Ih.a...).3.U7.@
00000020: af61 6aa2 b384 afe1 aff6 d4c9 ad95 1d67  .aj............g
00000030: 3a4f d64f 33ea 6f50 0a18 1139 9196 d694  :O.O3.oP...9....
При необходимости можно восстановить заголовок и установить новый пароль.
Код:
$ cryptsetup luksAddKey /dev/sda2 --master-key-file mk.dump
Enter new passphrase for key slot: ********
Verify passphrase: ********

Добавляем пароль восстановления в Active Directory​

Другой интересный способ — это хранение пароля в AD.

Для начала нужно включить нашу Arch Linux в домен. Делать это буду с помощью System Security Services Daemon (SSSD) и realmd.

Устанавливаем sssd обычным способом:
Код:
$ pacman -Sy sssd
А realmd ставим из AUR.

Убедимся, что домен доступен.
Код:
$ realm discover ad.localdomain
ad.localdomain
type: kerberos
realm-name: AD.LOCALDOMAIN
domain-name: ad.localdomain
configured: no
server-software: active-directory
client-software: sssd
Присоединяемся к домену, для этого понадобится учетная запись с правами ввода в домен (для простоты — administrator).
Код:
$ realm join ad.localdomain
 Password for Administrator: ********
Проверяем, что все прошло успешно и мы получили билеты Kerberos:
Код:
$ realm list
ad.localdomain
type: kerberos
realm-name: AD.LOCALDOMAIN
domain-name: ad.localdomain
configured: kerberos-member
server-software: active-directory
client-software: sssd
login-formats: %U@ad.localdomain
login-policy: allow-realm-logins
$ klist -k
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
2 ARCH$@AD.LOCALDOMAIN
2 ARCH$@AD.LOCALDOMAIN
2 ARCH$@AD.LOCALDOMAIN
2 host/ARCH@AD.LOCALDOMAIN
2 host/ARCH@AD.LOCALDOMAIN
2 host/ARCH@AD.LOCALDOMAIN
2 RestrictedKrbHost/ARCH@AD.LOCALDOMAIN
2 RestrictedKrbHost/ARCH@AD.LOCALDOMAIN
2 RestrictedKrbHost/ARCH@AD.LOCALDOMAIN
Пароль восстановления будем хранить в учетной записи компьютера: это дочерний объект класса msFVE-RecoveryInformation. Так делает виндовый BitLocker, аналогично поступим и мы.

Записывать пароль в AD буду с помощью скрипта на Python.
Код:
$ git clone https://github.com/ambalabanov/lukscrow
$ cd lukscrow/
$ pip install -r requirements.txt
Запускаем утилиту, указав необходимые параметры и текущий ключ (пароль):
Код:
$ ./lukscrow --luks-device /dev/sda2 --ldap-url "ldap://ad.localdomain" --computers-base-dn "CN=Computers,DC=ad,DC=localdomain" --unlock-key ********
Using Kerberos credential cache /tmp/tmpcsdyn49r
Connected to AD as 'u:AD\ARCH$'
Generating recovery key...
Adding recovery key to LUKS volume...
New key added.
Storing recovery key in Active Directory
Recovery key saved to AD.
Remove Kerberos credential cache /tmp/tmpcsdyn49r
Removed cache file.
Проверяем в AD, что пароль восстановления успешно записался.

rp

Ну и напоследок проверяем сам пароль.
Код:
$ sudo cryptsetup --test-passphrase luksOpen /dev/sda2 && echo TRUE || echo FALSE
Enter passphrase for /dev/sda2: 287781-171655-523297-666928-307170-072073-039516-177220
TRUE

ЗАКЛЮЧЕНИЕ​

Итак, мы установили Arch Linux на шифрованный корневой раздел, настроили авторазблокировку при старте и позаботились о резервировании ключей. Надеюсь, для тебя это тоже было увлекательным приключением!

автор balabanov Андрей Балабанов
источник хакер.ру
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх