- Вопрос или проблема
- Ответ или решение
- Авто-монтаж зашифрованных разделов USB-накопителя с использованием udev и systemd
- Шаг 1: Подготовка системы
- Шаг 2: Настройка fstab
- Шаг 3: Скрипт для обработки динамических изменений
- Шаг 4: Создание udev правил
- Шаг 5: Настройка systemd
- Шаг 6: Включение и запуск сервиса
- Заключение
Вопрос или проблема
У меня есть следующие требования:
- Если вставить определенную флешку, она должна автоматически обнаруживаться и монтироваться. Информация о том, где ее необходимо смонтировать, будет в
/etc/fstab
(конечно). - Если флешка будет выдернута, должна автоматически произойти полная очистка; в результате чего не должно остаться следов, таких как то, что она была смонтирована (или все еще смонтирована) и/или какие-либо незавершенные единицы systemd.
- Если раздел(ы), о которых идет речь, будут смонтированы вручную с помощью
umount
, тогда также все должно быть очищено, даже если флешка все еще присутствует; ее извлечение из разъема должно очистить только то, что не удалось очистить ранее (вероятно, единицы.device
).
Для достижения вышеописанного в чистом виде вставка флешки должна привести к запуску пользовательской единицы systemd, которую мы затем настроим для выполнения остальных действий.
Что требуется для написания этого?
Предположим, у нас есть флешка с тремя разделами:
/dev/sdc1
и /dev/sdc2
– которые зашифрованы LUKS,
и /dev/sdc3
– который не зашифрован.
Например,
>sudo blkid /dev/sdc{1,2,3}
/dev/sdc1: UUID="de9a000f-fa60-4050-8d11-864e97829b8a" TYPE="crypto_LUKS" PARTUUID="219578f5-5905-41cd-895d-7b937ac0756a"
/dev/sdc2: UUID="012059c1-6b88-4937-889a-a21448740492" TYPE="crypto_LUKS" PARTUUID="59c7f6f3-a5cb-41af-82fa-b515031d85d5"
/dev/sdc3: LABEL="README" UUID="9d262deb-2343-4096-bccf-bb26ed4415ad" BLOCK_SIZE="1024" TYPE="ext2" PARTUUID="165db3da-4ebb-4f59-ab09-ee5e5b26ed43"
Здесь UUID
используется в /dev/disk/by-uuid
:
>ls -l /dev/disk/by-uuid | grep sdc
lrwxrwxrwx 1 root root 10 Dec 22 18:27 012059c1-6b88-4937-889a-a21448740492 -> ../../sdc2
lrwxrwxrwx 1 root root 10 Dec 22 18:27 9d262deb-2343-4096-bccf-bb26ed4415ad -> ../../sdc3
lrwxrwxrwx 1 root root 10 Dec 22 18:27 de9a000f-fa60-4050-8d11-864e97829b8a -> ../../sdc1
Поскольку имя устройства /dev/sdc
является довольно случайным, мы должны использовать только UUID с этого момента.
Чтобы вручную смонтировать незашифрованный раздел, нам нужно выполнить (убедитесь, что на /mnt и/или /mnt/usb ничего уже не смонтировано!):
UUID=9d262deb-2343-4096-bccf-bb26ed4415ad
SERIAL=408D5CBECAC3E7C0E9170AEC
sudo /bin/mkdir -p /mnt/usb/$SERIAL/part3
sudo mount -t ext2 /dev/disk/by-uuid/$UUID /mnt/usb/$SERIAL/part3
Где я выбрал использовать значение ID_SERIAL_SHORT
usb-устройства, которое можно получить, например:
>udevadm info -n /dev/sdc3 | grep -E '(ID_SERIAL_SHORT|ID_FS_UUID)='
E: ID_SERIAL_SHORT=408D5CBECAC3E7C0E9170AEC
E: ID_FS_UUID=9d262deb-2343-4096-bccf-bb26ed4415ad
Давайте запомним точку монтирования в /etc/fstab
, добавив в этот файл:
UUID=9d262deb-2343-4096-bccf-bb26ed4415ad /mnt/usb/408D5CBECAC3E7C0E9170AEC/part3 ext2 rw,noauto 0 0
Обратите внимание, что после этого мы можем сделать:
sudo mount /dev/sdc3
и это будет корректно смонтировано, пока это блочное устройство имеет ожидаемый UUID.
Другие два раздела, /dev/sdc{1,2}
, зашифрованы и сначала нужно
UUID1=573bfda0-69f5-4fb9-9d7e-333a70a51710
UUID2=6d7bdc1d-3eb0-4774-a9fb-3d1ac1027010
echo $LUKS_PASS | sudo cryptsetup -q luksOpen /dev/disk/by-uuid/$UUID1 usb-$UUID1
echo $LUKS_PASS | sudo cryptsetup -q luksOpen /dev/disk/by-uuid/$UUID2 usb-$UUID2
выполнять, где я предполагаю, что переменная окружения LUKS_PASS
содержит пароль, необходимый для расшифровки раздела LUKS. UUID здесь – это те, которые возвращает blkid:
>sudo blkid /dev/sdc{1,2}
/dev/sdc1: UUID="573bfda0-69f5-4fb9-9d7e-333a70a51710" TYPE="crypto_LUKS" PARTUUID="caa57a9d-7389-4990-a243-34b19a179368"
/dev/sdc2: UUID="6d7bdc1d-3eb0-4774-a9fb-3d1ac1027010" TYPE="crypto_LUKS" PARTUUID="10813450-6dcc-4700-9e88-d0577c0c9aeb"
Это создает устройство /dev/mapper/usb-$UUID
(для каждого раздела), каждое с собственным UUID:
>sudo blkid /dev/mapper/usb*
/dev/mapper/usb-573bfda0-69f5-4fb9-9d7e-333a70a51710: LABEL="gold1-2024-12-21" UUID="67f056be-dbbc-4f7a-979d-6ff077d16e93" BLOCK_SIZE="4096" TYPE="ext2"
/dev/mapper/usb-6d7bdc1d-3eb0-4774-a9fb-3d1ac1027010: LABEL="gold2-2024-12-21" UUID="94bfcc55-6b52-431f-bc76-3aa198c107c7" BLOCK_SIZE="4096" TYPE="ext2"
Именно эти UUID мы хотим добавить в /etc/fstab
.
Чтобы облегчить жизнь, я написал следующий скрипт, который выводит необходимую конфигурацию /etc/fstab
при запуске после вставки USB (для моего конкретного случая):
# Получить путь к устройству.
DEVPATH=$(/bin/ls /dev/disk/by-id/usb-Kingston_DataTraveler* | grep -E -v -- '-part[0-9]+$')
# Получить серийный номер флешки.
ID_SERIAL_SHORT=$(udevadm info -n $DEVPATH | grep ID_SERIAL_SHORT | sed -e 's/.*ID_SERIAL_SHORT=//')
# Пройтись по всем существующим разделам.
for p in $(/bin/ls $DEVPATH-part*); do
# Извлечь строку "part?".
PART=$(echo $p | sed -r -e 's/.*-(part[0-9]+)$/\1/')
# Получить UUID блочного устройства этого раздела, если это зашифрованный раздел LUKS.
UUID=$(blkid --match-token TYPE=crypto_LUKS $p | sed -e 's/.* UUID="\([^ ]*\)".*/\1/' || true)
if [ -n "$UUID" ]; then
# Расшифровать раздел.
echo $LUKS_PASS | sudo cryptsetup -q luksOpen /dev/disk/by-uuid/$UUID usb-$UUID
# Получить UUID зашифрованного раздела.
UUID2=$(blkid /dev/mapper/usb-$UUID | sed -e 's/.* UUID="\([^ ]*\)".*/\1/')
echo -e "UUID=$UUID2\t/mnt/usb/$ID_SERIAL_SHORT/$PART\text2\trw,noauto\t0 0"
sudo cryptsetup luksClose usb-$UUID
else
# Получить UUID незашифрованного раздела.
UUID=$(blkid $p | sed -e 's/.* UUID="\([^ ]*\)".*/\1/')
echo -e "UUID=$UUID\t/mnt/usb/$ID_SERIAL_SHORT/$PART\text2\trw,noauto\t0 0"
fi
done
После экспорта LUKS_PASS
убедитесь, что вы запустили выше указанный скрипт с использованием sudo -E
, чтобы сохранить окружение. Пример вывода:
>sudo -E ./foo.sh
UUID=db97c4b0-8f92-4edc-bacb-dc90e62de2e2 /mnt/usb/408D5CBECAC3E7C0E9170AEC/part1 ext2 rw,noauto 0 0
UUID=c45c6a7a-1c0f-49c4-bcfb-15766114daa1 /mnt/usb/408D5CBECAC3E7C0E9170AEC/part2 ext2 rw,noauto 0 0
UUID=9d262deb-2343-4096-bccf-bb26ed4415ad /mnt/usb/408D5CBECAC3E7C0E9170AEC/part3 ext2 rw,noauto 0 0
С установленным /etc/fstab
и точно зная, какие команды нужны; осталось автоматизировать это с помощью udev
и systemd units
.
Вопрос в том: как?
Ответ или решение
Авто-монтаж зашифрованных разделов USB-накопителя с использованием udev и systemd
Автоматизация процессов монтирования и размонтирования USB-накопителей — востребованная задача в управлении системами. В данном руководстве мы рассмотрим, как автоматически монтировать зашифрованные и незашифрованные разделы USB-накопителя с использованием механизма udev и управления сервисами через systemd. Мы будем рассматривать USB-накопитель, содержащий три раздела: два зашифрованных с помощью LUKS и один незашифрованный.
Шаг 1: Подготовка системы
Перед началом убедитесь, что у вас установлены необходимые инструменты:
sudo apt install cryptsetup
Шаг 2: Настройка fstab
Вам нужно будет добавить информацию о ваших разделе в файл /etc/fstab
. Запишите UUID для каждого раздела с помощью команды blkid
:
sudo blkid /dev/sdc{1,2,3}
Добавьте три строки в /etc/fstab
для указания того, где монтировать разделы. Например:
UUID=db97c4b0-8f92-4edc-bacb-dc90e62de2e2 /mnt/usb/408D5CBECAC3E7C0E9170AEC/part1 ext2 rw,noauto 0 0
UUID=c45c6a7a-1c0f-49c4-bcfb-15766114daa1 /mnt/usb/408D5CBECAC3E7C0E9170AEC/part2 ext2 rw,noauto 0 0
UUID=9d262deb-2343-4096-bccf-bb26ed4415ad /mnt/usb/408D5CBECAC3E7C0E9170AEC/part3 ext2 rw,noauto 0 0
Шаг 3: Скрипт для обработки динамических изменений
Создайте bash-скрипт для обработки событий подключения и отключения:
#!/bin/bash
DEVPATH=$(ls /dev/disk/by-id/usb-Kingston_DataTraveler* | grep -v -- '-part[0-9]+$')
ID_SERIAL_SHORT=$(udevadm info -n $DEVPATH | grep ID_SERIAL_SHORT | sed -e 's/.*ID_SERIAL_SHORT=//')
for p in $(ls $DEVPATH-part*); do
PART=$(echo $p | sed -r -e 's/.*-(part[0-9]+)$/\1/')
UUID=$(blkid --match-token TYPE=crypto_LUKS $p | sed -e 's/.* UUID="\([^ ]*\)".*/\1/' || true)
if [ -n "$UUID" ]; then
echo $LUKS_PASS | sudo cryptsetup -q luksOpen /dev/disk/by-uuid/$UUID usb-$UUID
UUID2=$(blkid /dev/mapper/usb-$UUID | sed -e 's/.* UUID="\([^ ]*\)".*/\1/')
echo -e "UUID=$UUID2\t/mnt/usb/$ID_SERIAL_SHORT/$PART\text2\trw,noauto\t0 0"
sudo cryptsetup luksClose usb-$UUID
else
UUID=$(blkid $p | sed -e 's/.* UUID="\([^ ]*\)".*/\1/')
echo -e "UUID=$UUID\t/mnt/usb/$ID_SERIAL_SHORT/$PART\text2\trw,noauto\t0 0"
fi
done
Убедитесь, что скрипт исполняемый:
chmod +x /path/to/your/script.sh
Шаг 4: Создание udev правил
Создайте файл /etc/udev/rules.d/99-usb-mount.rules
и добавьте следующее правило:
ACTION=="add", KERNEL=="sd*[0-9]", ENV{ID_SERIAL_SHORT}=="408D5CBECAC3E7C0E9170AEC", RUN+="/path/to/your/script.sh"
Это правило запускает ваш скрипт при подключении USB-накопителя с указанным серийным номером.
Шаг 5: Настройка systemd
Создайте единичный файл systemd для управления процессом:
sudo nano /etc/systemd/system/usb-mount.service
Заполните его следующим содержимым:
[Unit]
Description=Auto Mount USB Stick
After=local-fs.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/path/to/your/script.sh
ExecStop=/bin/umount /mnt/usb/408D5CBECAC3E7C0E9170AEC/part*
[Install]
WantedBy=multi-user.target
Шаг 6: Включение и запуск сервиса
После создания службы, активируйте её:
sudo systemctl enable usb-mount.service
Теперь вы можете протестировать, подключив USB-накопитель. Убедитесь, что разделы монтируются автоматически. Если они были размонтированы, проверьте выполнение скрипта через systemd.
Заключение
Это пошаговое руководство поможет вам создать систему авто-монтажа зашифрованных и незашифрованных разделов USB-накопителя на базе udev и systemd. С помощью этого решения вы получите стабильное и чистое управление вашим хранилищем, что значительно упростит ежедневные задачи работы с USB-устройствами.