Расшифровка LUKS контейнера в момент загрузки системы +18


Всем доброго дня, ночи! Этот пост будет полезен тем, кто использует шифрование данных LUKS и хочет производить decryptдешифровку дисков под Linux (Debian, Ubuntu) на стадии расшифровки root раздела. И такой информации в интернете я найти не смог.

Совсем недавно с увеличением количества дисков в полках, столкнулся с проблемой расшифровки дисков с использованием более чем известного метода через /etc/crypttab. Лично я выделяю несколько проблем использования этого метода, а именно то, что файл читается только после загрузки (mount) root-раздела, что негативно сказывается на импорте ZFS, в частности если они были собраны из разделов на *_crypt устройстве, или же mdadm рейды, собранные так же из разделов. Мы же все знаем, что можно использовать parted на LUKS контейнерах? И также проблема раннего старта других служб, когда массивов еще нет, а использовать уже что-то надо (я работаю с кластеризованным Proxmox VE 5.x и ZFS over iSCSI).

Немного о ZFSoverISCSI
iSCSI работает у меня через LIO, и собственно когда стартует iscsi-таргет и не видит ZVOL устройств, он их просто-напросто удаляет из конфигурации, что не дает возможности загружаться гостевым системам. Отсюда либо восстановление бэкапа json файла, либо ручное добавление устройств с идентификаторами каждой VM, что просто ужас, когда таких машин десятки и в конфигурации каждой более 1 диска.

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

Чаще всего на просторах интернета используют ключевой файл (само-собой добавленный перед этим в слот командой — cryptsetup luksAddKey), либо в редких исключениях (в русско-язычном интернете очень скудная информация) — скрипт decrypt_derived, лежащий в /lib/cryptsetup/script/ (конечно, есть еще способы, но я использовал именно эти два, что и легло в основу статьи). Так же я стремился к полному автономному включению после перезагрузок, без каких либо дополнительных команд в консоли, чтобы у меня всё «взлетало» сразу. Поэтому, зачем ждать? —

Приступаем!

Предполагаем систему, например Debian, установленную на crypto-раздел sda3_crypt и десяток дисков, готовых к шифрованию и созданию чего душе угодно. Мы имеем ключевую фразу (passphrase) для разблокировки sda3_crypt и именно с этого раздела мы будем на запущенной (расшифрованной) системе снимать «хэш» от пароля и добавлять на остальные диски. Всё элементарно, в консоли выполняем:

/lib/cryptsetup/scripts/decrypt_derived sda3_crypt | cryptsetup luksFormat /dev/sdX

где X — это наши диски, разделы и т.д.

После шифрования дисков «хешем» от нашей ключевой-фразы, необходимо узнать UUID, либо ID — смотря кто и к чему привык. Берём данные из /dev/disk/by-uuid и by-id соответственно.

Следующий этап подготовка файлов и мини-скриптов для работы необходимых нам функций, приступаем:

cp -p /usr/share/initramfs-tools/hooks/cryptroot /etc/initramfs-tools/hooks/
cp -p /usr/share/initramfs-tools/scripts/local-top/cryptroot /etc/initramfs-tools/scripts/local-top/

далее

touch /etc/initramfs-tools/hooks/decrypt && chmod +x /etc/initramfs-tools/hooks/decrypt

Содержимое ../decrypt
#!/bin/sh

cp -p /lib/cryptsetup/scripts/decrypt_derived "$DESTDIR/bin/decrypt_derived"


далее

touch /etc/initramfs-tools/hooks/partcopy && chmod +x /etc/initramfs-tools/hooks/partcopy

Содержимое ../partcopy
#!/bin/sh

cp -p /sbin/partprobe "$DESTDIR/bin/partprobe"
cp -p /lib/x86_64-linux-gnu/libparted.so.2 "$DESTDIR/lib/x86_64-linux-gnu/libparted.so.2"
cp -p /lib/x86_64-linux-gnu/libreadline.so.7 "$DESTDIR/lib/x86_64-linux-gnu/libreadline.so.7"


еще немного

touch /etc/initramfs-tools/scripts/local-bottom/partprobe && chmod +x /etc/initramfs-tools/scripts/local-bottom/partprobe

Содержимое ../partprobe
#!/bin/sh

$DESTDIR/bin/partprobe


и последнее, перед update-initramfs, нужно отредактировать файл /etc/initramfs-tools/scripts/local-top/cryptroot, начиная со строки ~360, кусок кода ниже

Оригинал

                # decrease $count by 1, apparently last try was successful.
                count=$(( $count - 1 ))
                
                message "cryptsetup ($crypttarget): set up successfully"
                break


и приводим к такому виду

Отредактированный

                # decrease $count by 1, apparently last try was successful.
                count=$(( $count - 1 ))
                

                /bin/decrypt_derived $crypttarget | cryptsetup luksOpen /dev/disk/by-uuid/ *CRYPT_MAP*
                /bin/decrypt_derived $crypttarget | cryptsetup luksOpen /dev/disk/by-id/ *CRYPT_MAP*

                message "cryptsetup ($crypttarget): set up successfully"
                break


Обратите внимание, что здесь можно использовать либо UUID, либо ID. Главное чтобы нужные драйвера на устройства HDD/SSD были добавлены в /etc/initramfs-tools/modules. Узнать используемый драйвер можно командой udevadm info -a -n /dev/sdX | egrep 'looking|DRIVER'.

Теперь, когда мы закончили и все файлы на месте, запускаем update-initramfs -u -k all -v, в логировании не должно быть ошибок выполнения наших скриптов. Перезагружаемся, вводим ключевую-фразу и немного ждём, в зависимости от количества дисков. Далее система запустится и на конечной стадии запуска, а именно после «маунтинга» root-раздела, будет выполнена команда partprobe — она найдет и подцепит все созданные разделы на LUKS устройствах и любые массивы, будь то ZFS или mdadm соберутся без проблем! И всё это до загрузки основных служб и сервисов, которым нужны эти диски/массивы.

update1: Как заметил AEP, данный способ работает только для LUKS1.




К сожалению, не доступен сервер mySQL