Как загрузить парольную фразу LUKS с USB, возвращаясь к клавиатуре?

Я хочу настроить безголовый компьютер Linux (Debian Wheezy) с полным шифрованием диска, с возможностью разблокировки диска с помощью USB-накопителя или путем ввода ключевой фразы с клавиатуры. Моя отправная точка - новая установка, использующая базовую опцию шифрования всего диска в установщике Debian, которая управляет всем, кроме /boot, как группа логических томов с шифрованием LUKS и дает мне опцию клавиатуры. Я опишу свое текущее решение в ответе в надежде, что оно будет полезным и что другие могут улучшить его.

Вот некоторые из проблем, которые у меня были:

  • Настройка парольной фразы и ее установка на USB-накопитель.

  • Загрузка модулей USB вовремя.

  • Ожидание распознавания USB-накопителя Linux, прежде чем пытаться читать с него.

  • Определение правильного USB-накопителя (а не другого накопителя, который был вставлен).

  • Написание "скрипта ключа" для извлечения ключевой фразы с USB-накопителя.

  • Обеспечение возврата к клавиатуре во всех случаях сбоя USB.

Я приму ответ с существенными улучшениями и откликнусь с ответами, которые предлагают вклад.

5 ответов

Многое из моего решения взято из поста " Использование USB-ключа для парольной фразы LUKS".

  1. Создайте случайную фразу-пароль:

    dd if=/dev/urandom bs=1 count=256 > passphrase
    
  2. Вставьте USB-накопитель. dmesg вывод покажет имя устройства; предполагать /dev/sdd, Выяснить его размер:

    blockdev --getsize64 /dev/sdd
    
  3. Я решил установить парольную фразу в конце исходного устройства, полагая, что оно может выжить при любом случайном использовании USB-накопителя.

    dd if=passphrase of=/dev/sdd bs=1 seek=<size-256>
    
  4. Добавьте ключевую фразу в том LUKS:

    cryptsetup luksAddKey /dev/sda5 passphrase
    

    Это не влияет на существующую парольную фразу, введенную вручную от установщика. Файл парольной фразы может быть удален:

    rm passphrase
    
  5. Найдите уникальное имя для USB-накопителя, чтобы мы могли определить его при наличии:

    ls -l /dev/disk/by-id | grep -w sdd
    

    Вы должны увидеть одну символическую ссылку. Я назову это /dev/disk/by-id/<ID>,

  6. редактировать /etc/crypttab, Вы должны увидеть строку вроде:

    sdc5_crypt UUID=b9570e0f-3bd3-40b0-801f-ee20ac460207 none luks
    

    Изменить его на:

    sdc5_crypt UUID=b9570e0f-3bd3-40b0-801f-ee20ac460207 /dev/disk/by-id/<ID> luks,keyscript=/bin/passphrase-from-usb
    
  7. keyscript упомянутый выше должен будет прочитать парольную фразу с устройства USB. Тем не менее, он должен сделать больше, чем это. Чтобы понять, как это используется, проверьте /usr/share/initramfs-tools/scripts/local-top/cryptroot, скрипт, который запускается во время загрузки, чтобы разблокировать корневое устройство. Обратите внимание, когда keyscript установлен, он просто запускается, а вывод luksOpen без других проверок. Нет способа сообщить об ошибке (USB-накопитель отсутствует) или вернуться к вводу с клавиатуры. Если парольная фраза не срабатывает, сценарий запускается снова в цикле, до некоторого количества раз; однако нам не говорят, на какой итерации мы находимся. Кроме того, мы не контролируем, когда запускается сценарий с ключом, поэтому мы не можем быть уверены, что Linux распознал USB-накопитель.

    Я обратился к этому с некоторыми взломами:

    1. Проведите опрос на USB-накопителе и подождите 3 секунды, пока он не появится. Это работает для меня, но я хотел бы узнать лучший способ.

    2. Создать фиктивный файл /passphrase-from-usb-tried при первом запуске, чтобы показать, что мы запускались хотя бы один раз.

    3. Если мы запустились хотя бы один раз или USB-накопитель не найден, запустите askpass программа используется cryptroot для ввода с клавиатуры.

    Финальный сценарий:

    #!/bin/sh
    
    set -e
    
    if ! [ -e /passphrase-from-usb-tried ]; then
        touch /passphrase-from-usb-tried
        if ! [ -e "$CRYPTTAB_KEY" ]; then
            echo "Waiting for USB stick to be recognized..." >&2
            sleep 3
        fi
        if [ -e "$CRYPTTAB_KEY" ]; then
            echo "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME) from USB key" >&2
            dd if="$CRYPTTAB_KEY" bs=1 skip=129498880 count=256 2>/dev/null
            exit
        else
            echo "Can't find $CRYPTTAB_KEY; USB stick not present?" >&2
        fi
    fi
    
    /lib/cryptsetup/askpass "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME)\nEnter passphrase: "
    

    Наконец, нам нужно убедиться, что этот скрипт доступен в initramfs. Создайте /etc/initramfs-tools/hooks/passphrase-from-usb содержащий:

    #!/bin/sh
    
    PREREQ=""
    
    prereqs() {
            echo "$PREREQ"
    }
    
    case "$1" in
            prereqs)
                    prereqs
                    exit 0
            ;;
    esac
    
    . "${CONFDIR}/initramfs.conf"
    . /usr/share/initramfs-tools/hook-functions
    
    copy_exec /bin/passphrase-from-usb /bin
    
  8. Драйверы USB не присутствовали в моих initramfs. (Похоже, они по умолчанию в более поздних версиях Debian.) Я должен был добавить их, добавив в /etc/initramfs-tools/modules:

    uhci_hcd
    ehci_hcd
    usb_storage
    
  9. Когда все будет сделано, обновите initramfs:

    update-initramfs -u
    

Для меня было бы идеально, если бы я мог просто иметь небольшую флешку с парольной фразой, которая разблокирует диск. Это будет не только удобно для серверов (где вы можете оставить USB-накопитель на сервере - цель состоит в том, чтобы иметь возможность возвращать сломанные жесткие диски, не беспокоясь о конфиденциальных данных), это также будет полезно для моего ноутбука: вставьте Флешка при загрузке и вынимайте ее после разблокировки криптодиска.

Теперь я написал патч, который будет искать файл "cryptkey.txt" в корневом каталоге всех устройств и пытаться расшифровать каждую строку в качестве ключа. Если это не помогло: вернитесь к вводу парольной фразы.

Это означает, что ключ не может содержать \ n, но это также относится к любому введенному ключу. Хорошая часть заключается в том, что вы можете использовать один и тот же USB-диск для хранения ключа для нескольких машин: вам не нужен отдельный USB-диск для каждой. Таким образом, если у вас есть USB-накопитель в вашем физическом брелоке, вы можете использовать один и тот же накопитель для всех машин, которые вы загружаете, когда физически находитесь рядом.

Вы добавляете ключ с помощью:

cryptsetup luksAddKey /dev/sda5

Затем вставьте тот же ключ, что и строку, в файл на USB /MMC-диске с именем "cryptkey.txt". Патч здесь:

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=864647

Если драйверы USB, драйверы MMC или файловые системы отсутствуют в ваших initramfs, вам необходимо добавить их, добавив в / etc / initramfs-tools / modules:

uhci_hcd
ehci_hcd
usb_storage
nls_utf8
nls_cp437
vfat
fat
sd_mod
mmc_block
tifm_sd
tifm_core
mmc_core
tifm_7xx1
sdhci
sdhci_pci

Когда все будет сделано, обновите initramfs:

update-initramfs -u

Его можно найти в виде патча и файла по адресу: https://gitlab.com/ole.tange/tangetools/tree/master/decrypt-root-with-usb

Несмотря на отличный ответ от @Andrew, который работает в предыдущих версиях. Решение на самом деле устарело и требует большой настройки для ubuntu 18.04 и 19.10. Итак, я хочу поделиться своим исследованием по этому поводу.

По поводу crypttab есть несколько уловок. С 14 апреля по 18 апреля и по 19 октября число секций сильно изменилось. Он начинает поддерживать больше параметров для cryptsetup. Например, смещение ключевого файла, размер ключевого файла и т.д. Некоторые параметры, например nobootwait, пропали. Некоторые параметры уже поддерживаются в другом дистрибутиве, но еще не поддерживаются в ubuntu (например, очень хороший параметр keyfile-timeout. Это может устранить весь сценарий клавиш, поскольку он автоматически откатится к вводу с клавиатуры после тайм-аута ключевого файла).

Основная проблема crypttab в ubuntu заключается в том, что он фактически обрабатывается двумя разными процессами. Один из них - это традиционно initramfs, а другой - современный systemd. Systemd должен быть более продвинутым и гибким во многих аспектах. Однако systemd плохо поддерживает crypptab, есть много опций, таких как keycript, которые просто игнорируются. поэтому я понятия не имею, что происходит, пока не заметил этот пост. Почти все сообщения в Интернете о настройках crypttab предназначены для initramfs, а не для systemd. Итак, нам нужно добавитьinitramfs ко всем записям в crypttab, чтобы избежать проблем.

Я также обнаружил хороший способ отладки нашего скрипта ключей и crypttab без виртуальной машины или многократной перезагрузки. этоcryptdisks_start. Прежде чем мы фактически распространим наши изменения в initramfs, мы всегда должны тестировать его с помощью этой красивой команды. В противном случае вы должны быть заблокированы в своей системе и сможете восстановить ее только через среду chroot.

@andrew опубликовал хороший способ использовать скрытие данных в необработанной области файловой системы. Однако я обнаружил, что это очень раздражает, когда мы хотим автоматически создавать разделы и распределять необработанные данные на множество usbkeys, мы должны рассчитывать смещение для всех различных файловых систем и разных размеров разделов. Более того, если пользователь случайно напишет на ФС, есть риск, что ключ будет перезаписан. Необработанный раздел без ФС в этом случае имеет больше смысла. Однако необработанный раздел не имеет UUID, который не очень полезен для автоматической разблокировки. Таким образом, я хотел бы представить способ использования обычных файлов парольных фраз в файловой системе usbkey. Основная проблема passdev в том, что он не ищет / не останавливается во время чтения файла. Таким образом, мы не можем использовать параметры keyfile-offset и keyfile-size, когда хотим вернуться к вводу с клавиатуры. Поскольку cryptsetup на самом деле пытается пропустить входной контент, и если контент короче, чем размер ключевого файла, это вызывает ошибку. Это также означает, что при большом смещении passdev может быть очень медленным, поскольку всегда читается с начала. Однако нет смысла реализовывать смещение и размер ключевого файла для реального файла в файловой системе. Я считаю, что они созданы для необработанного устройства.

Crypttab

luks-part UUID="<uuid>" /dev/disk/by-uuid/<keyfile FS uuid>:/<keyfile path relative to usbkey root>:<timeout in sec> luks,keyfile-offset=<seek to the key>,keyfile-size=<>,keyscript=/bin/passphrase-from-usbfs.sh,tries=<number of times to try>,initramfs

ключевой скрипт passphrase-from-usbfs.sh использовал /lib/cryptsetup/scripts/passdevкоторый будет ждать USB-устройство и смонтировать файловую систему, а затем передать содержимое файла. Он поддерживаетCRYPTTAB_KEY в формате /device-path/<keyfile FS uuid>:/<keyfile path relative to usbkey root>:<timeout in sec>.

#!/bin/sh
#all message need to echo to stderr, the stdout is used for passphrase
# TODO: we may need to do something about the plymouth
echo "CRYPTTAB_KEY=$CRYPTTAB_KEY" >&2
echo "CRYPTTAB_OPTION_keyfile_offset=$CRYPTTAB_OPTION_keyfile_offset" >&2
#set your offset and file size here if your system does not support those paramters
#CRYPTTAB_OPTION_keyfile_offset=
#CRYPTTAB_OPTION_keyfile_size=
echo "timeout=$CRYPTTAB_OPTION_keyfile_timeout" >&2
CRYPTTAB_OPTION_keyfile_timeout=10 # keyfile-timeout is not supported yet 
pass=$(/lib/cryptsetup/scripts/passdev $CRYPTTAB_KEY)
rc=$?
if ! [ $rc -eq 0 ]; then
    echo "Can't find $CRYPTTAB_KEY; USB stick not present?" >&2
    /lib/cryptsetup/askpass "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME) Enter passphrase: "
else
    echo "successfully load passphrase." >&2
    echo -n $pass
fi

Хук сообщает update-initramfs, что нужно скопировать наши скрипты.

#!/bin/sh

PREREQ=""

prereqs() {
        echo "$PREREQ"
}

case "$1" in
        prereqs)
                prereqs
                exit 0
        ;;
esac

. "${CONFDIR}/initramfs.conf"
. /usr/share/initramfs-tools/hook-functions
copy_exec /bin/passphrase-from-usbfs.sh
copy_exec /bin/passphrase-from-usb.sh
#when using passdev we need to hook additionaly FS and binary
copy_exec /lib/cryptsetup/scripts/passdev
manual_add_modules ext4 ext3 ext2 vfat btrfs reiserfs xfs jfs ntfs iso9660 udf

Наконец, я опубликовал обновленную версию passphrase-from-usb.sh, которая может использовать новые параметры в crypttab:

Чтобы сопровождать превосходные ответы выше, пожалуйста, смотрите подпрограммы C, которые вы можете использовать для записи / генерации и чтения необработанного блочного ключа устройства "Readkey.c" извлекает ключ заданного размера из блочного устройства, а "writekey.c" может генерировать или записывать существующий ключ в необработанное устройство. После компиляции "readkey.c" можно использовать в пользовательском скрипте для извлечения ключа известного размера из необработанного блочного устройства, например, так:

readkey </path/to/device> <keysize>

Чтобы увидеть использование "writekey", после компиляции запустите его без флагов.
Для компиляции просто используйте:

gcc readkey.c -o readkey

gcc writekey.c -o writekey

Я протестировал оба устройства на USB-флешке Verbatim 16 ГБ USB 2.0 с пользовательским параметром "keyscript=" в crypttab, также опубликованном ниже. Идея "crypto-usb.sh" взята из руководства по cryptsetup debian etch.

crypto-usb.sh:

#!/bin/sh
echo ">>> Trying to get the key from agreed space <<<" >&2
modprobe usb-storage >/dev/null 2>&1
sleep 4
OPENED=0
disk="/sys/block/sdb"
boot_dir="/boot"
readkey="/boot/key/readkey"
echo ">>> Trying device: $disk <<<" >&2
F=$disk/dev
if [ 0`cat $disk/removable` -eq 1 -a -f $F ]; then
    mkdir -p $boot_dir
    mount /dev/sda1 $boot_dir -t ext2 >&2
    echo ">>> Attempting key extraction <<<" >&2
    if [ -f $readkey ]; then
        # prints key array to the caller
        $readkey /dev/sdb 4096
        OPENED=1
    fi
    umount $boot_dir >&2
fi


if [ $OPENED -eq 0 ]; then
    echo "!!! FAILED to find suitable key !!!" >&2
    echo -n ">>> Try to enter your password: " >&2
    read -s -r A
    echo -n "$A"
else
    echo ">>> Success loading key <<<" >&2
fi

Когда необходимо указать размер ключа, сгенерированный ключ сохраняется в файле ".tmpckey" с правами доступа 0600 для последующего использования. При записи существующего ключа размер определяется путем измерения существующего размера ключа. Это похоже на сложный подход, однако после компиляции с простым "gcc" он может обеспечить простой способ манипулирования содержимым необработанного ключа.

readkey.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main(int argc, char *argv[])
{
    int blockSize = 512;
    int keySize = 2048; 

    FILE *device;       

    if (  argc == 3 
           && (sizeof(argv[1]) / sizeof(char)) > 1
           && (sizeof(argv[2]) / sizeof(char)) > 1
       && (atoi(argv[2]) % 512) == 0
       ) {
        device = fopen(argv[1], "r");
        if(device == NULL) { 
            printf("\nI got trouble opening the device %s\n", argv[1]);
            exit(EXIT_FAILURE);
        }
        keySize = atoi(argv[2]);        
    }
    else if (  argc == 2 
            && (sizeof(argv[1]) / sizeof(char)) > 1
        ) {
        device = fopen(argv[1], "r");
        if(device == NULL) { 
            printf("\nI got trouble opening the device %s\n", argv[1]);
            exit(EXIT_FAILURE);
        }

    }
    else {

        printf("\nUsage: \n");
        printf("\nKey Size Provided: \n");
        printf("\n\t\treadkey </path/to/device> <keysize> \n");
        printf("\nDefault key size: %d\n", keySize);
        printf("\n\t\treadkey </path/to/device>\n");
        exit(1);
    }

    int count;

    char *block;

    /* Verify if key is multiple of blocks */
    int numBlocks = 0;
    if (keySize % 512 != 0) {
       printf("\nSory but key size is not multiple of block size, try again. TA.\n");
       exit(1);
    }

    /* Seek till the end to get disk size and position to start */
    fseek(device, 0, SEEK_END);

    /* Determine where is the end */
    long endOfDisk = ftell(device);

    /* Make sure we start again */
    rewind(device); // Do I need it ???

    /* Get the required amount minus block size */
    long startFrom = endOfDisk - blockSize - keySize;

    /* Allocate space for bloc */
    block = calloc(keySize, sizeof(char));

    /* Start reading from specified block */
    fseek(device, startFrom, SEEK_SET);
    fread(block, 1, keySize, device);

    /* Do something with the data */
    for(count = 0; count < keySize/*sizeof(block)*/; count++){
        printf("%c", block[count]);
    }

    /* Close file */
    fclose(device);

    /* Make sure freed array is zeroed */
    memset(block, 0, keySize);
    free(block);
}

writekey.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int blockSize = 512;
    int keySize = 2048;

    int count;

    unsigned char *block;

    /*
        Thing to always remember that argv starts from 0 - the name of the program, and argc starts from 1 i.e. 1 is the name of the program.
    */
    if ( argc == 3 
       && strcmp(argv[1], "genwrite") != 0
       && (sizeof(argv[2]) / sizeof(char)) > 2
       ) {
        char ch;
        FILE *keyF;
        keyF = fopen(argv[1], "r");
        if (keyF == NULL) exit(EXIT_FAILURE);

        /* Tell key Size */
        fseek(keyF, 0, SEEK_END);
        keySize = ftell(keyF);
        rewind(keyF);
        printf("\nKey Size: %d\n", keySize);

        block = calloc(keySize, sizeof(char));
        printf("\n-- Start Key --:\n");
                for(count = 0; count < keySize/*sizeof(block)*/; count++){
            char ch = fgetc(keyF);
                        block[count] = ch;
            /*
              Uncomment below to see your key on screen
            */
            // printf("%c",ch);

                }
        printf("\n-- End Key --:\n");
        fclose(keyF);
    }
    else if (  argc == 3 
        && strcmp(argv[1], "genwrite") == 0 
        && (sizeof(argv[2]) / sizeof(char)) > 2
        ) 
        {
        printf("\n-- Attempting to create random key(ish --) of size: %d\n", keySize);
        block = calloc(keySize, sizeof(char));
        int count;
        for(count = 0; count < keySize/*sizeof(block)*/; count++){
            block[count] = (char) rand();
        }
        FILE *tmpfile;
        tmpfile = fopen(".tmpckey", "w");
        if(tmpfile == NULL) exit(EXIT_FAILURE);
        fwrite(block, 1, keySize, tmpfile);
        fclose(tmpfile);
        chmod(".tmpckey", 0600);
    }
    else if (  argc == 4 
        && strcmp(argv[1], "genwrite") == 0
        && (sizeof(argv[2]) / sizeof(char)) > 2
        && ((atoi(argv[3]) % 512) == 0)
        ) 
        {
        keySize = atoi(argv[3]);
        printf("\n-- Attempting to create random key(ish --) of size: %d\n", keySize);
        block = calloc(keySize, sizeof(char));
        int count;
        for(count = 0; count < keySize/*sizeof(block)*/; count++){
            block[count] = (char) rand();
        }
        FILE *tmpfile;
        tmpfile = fopen(".tmpckey", "w");
        if(tmpfile == NULL) exit(EXIT_FAILURE);
        fwrite(block, 1, keySize, tmpfile);
        fclose(tmpfile);
        chmod(".tmpckey", 0600);
    }   
    else {
        printf("\n");
        printf("################################################################################\n");
        printf("#                                                                              #\n");
        printf("#                              Usage:                                          #\n");
        printf("#                                                                              #\n");
        printf("################################################################################\n");
        printf("#> To write existing key to device:                                            #\n");
        printf("#                                                                              #\n");
        printf("#     writekey </path/to/keyfile> </path/to/removable/sd*>                     #\n");
        printf("#                                                                              #\n");
        printf("#> To generate and write pseudo random key,                                    #\n");
        printf("#> key will be saved to temporary file .tmpckey                                #\n");
        printf("#                                                                              #\n");
        printf("#     writekey genwrite </path/to/removable/sd*> <keysize in multiples of 512> #\n");
        printf("#                                                                              #\n");
        printf("#> When keysize is not provided default size is set to %d.                     #\n", keySize);
        printf("#                                                                              #\n");
        printf("################################################################################\n");
        exit(1);
    }

    /*
        Some printf debugging below, uncomment when needed to see what is going on.
    */
    /*
    printf("\nNumber of Args: %d\n", argc);
    printf("\nCurrently block array contains: \n");
    for(count = 0; count < keySize; count++){
        printf("%c", block[count]);
    }
    printf("\n-- End block -- \n");
    */
    /* Open Device itp... */
    FILE *device = fopen(argv[2], "a");
    if(device == NULL) exit(EXIT_FAILURE);

    printf("\nDevice to write: %s\n", argv[2]);

    fseek(device, 0, SEEK_END);

    /* Determine where is the end */
    long endOfDisk = ftell(device);
    printf("\nDevice Size: %ld\n", endOfDisk);

    /* Verify if key is multiple of blocks */
    int numBlocks = 0;
    if (keySize % 512 != 0 || endOfDisk < (blockSize + keySize) ) {
            printf("\nSorry but key size is not multiple of block size or device you trying to write to is too small, try again. TA.\n");
        fclose(device);
            exit(1);
    }



    /* Make sure we start again */
    rewind(device);

    /* Get the required amount sunbstracting block size */
    long startFrom = endOfDisk - blockSize - keySize;

    /* Write some data to the disk */
    printf("\nWriting data starting from: %ld\n", startFrom);
    fseek(device, startFrom, SEEK_SET);
    fwrite(block, 1, keySize, device);
    printf("\nBlock Position after data write procedure : %ld\n", ftell(device));

    /*
        Below is just for convenience, to read what was written,
        can aid in debugging hence left commented for later.
    */
    /*
    printf("\nAmount of Data written : %ld\n", ftell(device) - startFrom);

    // Start reading from specified block 
    printf("\n>>>>>>>> DEBUGGING SECTION <<<<<<<<<\n");
    rewind(device); //
    fseek(device, startFrom, SEEK_SET);
    printf("\nBlock Position before read attempted: %d\n", ftell(device));
    printf("\nKey size: %d\n", keySize);
    fread(block, 1, keySize, device);

    // Do something with the data
    printf("\nBlock Position startFrom: %ld\n", startFrom);
    printf("\nBlock Position after read: %d\n", ftell(device));
    printf("\n-- Buffer Read: --\n");
    for(count = 0; count < keySize; count++){
        printf("%c", block[count]);
    }
    printf("\n-- End block -- \n");
    printf("\n--  -- \n");
    printf("\n--  -- \n");
    */

    /* Close file */
    fclose(device);

    /* Make sure freed array is zeroed */
    memset(block, 0, keySize);
    free(block);

/* Return success, might change it to be useful return not place holder */
return 0;
}

Чтобы убедиться, что ключ, записанный в raw-устройство, совпадает с ключом в файле (ниже ничего не выводится, если ключи идентичны):

diff -B <(./readkey </path/to/device> 4096) <(cat .tmpckey)

Или для существующего ключа, сгенерированного с использованием собственных средств:

diff -B <(./readkey </path/to/device> <generated elsewhere key size>) <(cat </path/to/keyfile>)

Благодарю вас

Вот решение, похожее на решение Эндрю, но

  • использование CRYPTTAB_TRIED, описанное на справочной странице Debian crypttab, для различения попыток, и

  • вызов существующего стандартного ключа /lib/cryptsetup/scripts/passdevс первой попытки.

  1. Создайте свой ключевой файл или ключевой раздел, как обычно для скрипта.

  2. Создайте следующий файл /usr/local/bin/key-from-usbи сделать его исполняемым.

            #!/bin/sh
    set -e
    if [ $CRYPTTAB_TRIED -ge 1 ]; then
      /lib/cryptsetup/askpass "Second try to unlock $CRYPTTAB_SOURCE ($CRYPTTAB_NAME). Please enter passphrase: "
    else
      /lib/cryptsetup/scripts/passdev $CRYPTTAB_KEY
    fi
    
  3. В /etc/crypttabиспользуйте параметр keyscript=/usr/local/bin/key-from-usb.

  4. Создавать /etc/initramfs-tools/hooks/key-from-usbс этим содержанием:

            #!/bin/sh
    
    PREREQ=""
    
    prereqs() {
            echo "$PREREQ"
    }
    
    case "$1" in
             prereqs)
                     prereqs
                     exit 0
             ;;
    esac
    
    . "${CONFDIR}/initramfs.conf"
    . /usr/share/initramfs-tools/hook-functions
    
    manual_add_modules vfat
    
    copy_exec /usr/lib/cryptsetup/scripts/passdev /usr/lib/cryptsetup/scripts/passdev
    
    copy_exec /usr/local/bin/key-from-usb /usr/local/bin/key-from-usb
    

    Первый copy_execлиния здесь необходима, потому что passdevне копируется, если он не упоминается в crypttab. Сходным образом, manual_add_modules vfatобеспечит возможность использования vfat usb-диска.

Подсказка: используйте lsinitramfs /boot/initrd.img-...и сравните/сравните результаты, чтобы убедиться, что скрипт и все его зависимости включены.

Другие вопросы по тегам