Предисловие

Понадобилось моему товарищу криптовать его централизованное хранилище. Причины тут описываться не будут, я думаю причин найти можно много для этого. ТЗ простое - воткнул ключ, работает, выткнул не работает.
В связи с тем, что мне это никогда не было актуальным, посредством гугля, я выяснил, что единственный, мне известный в этой области продукт - truecrypt, имеет проблемы в своей лицензии, ну и во многих дистрибутивах его присутствие остаётся под сомнением . Я задал вопрос в конференции на [email protected], где собственно меня и направили на путь истинный :)

Зри в опенсорс

Мне помог модератор Котэ Бегемот (ник на момент написания заметки), сказав что есть такой dm-crypt и что он(Котэ), им даже пользуется. Чтож, уже хорошо, как минимум программа работает, пол проблемы решено :)

Дальше я обратил свой взор на Википедию:
dm-crypt is a transparent disk encryption subsystem in Linux kernel versions 2.6 and later. It is part of the device mapper infrastructure, and uses cryptographic routines from the kernel's Crypto API. Unlike its predecessor cryptoloop, dm-crypt was designed to support advanced modes of operation, such as XTS, LRW and ESSIV (see disk encryption theory), in order to avoid watermarking attacks. In addition to that, dm-crypt also addresses some reliability problems of cryptoloop.

И даже есть к нему фронтенды:
The dm-crypt device mapper target resides entirely in kernel space, and is only concerned with encryption of the block device — it does not interpret any data itself. It relies on user space front-ends to create and activate encrypted volumes, and manage authentication. At least two frontends are currently available: cryptsetup and cryptmount.

Я решил, проверить первый по списку:
[simplexe@myhost Debug]$ cryptsetup
Использование: cryptsetup [-?vyrq] [-?|--help] [--usage] [-v|--verbose] [--debug]
        [-c|--cipher=STRING] [-h|--hash=STRING] [-y|--verify-passphrase]
        [-d|--key-file=STRING] [--master-key-file=STRING]
        [-s|--key-size=BITS] [-S|--key-slot=INT] [-b|--size=SECTORS]
        [-o|--offset=SECTORS] [-p|--skip=SECTORS] [-r|--readonly]
        [-i|--iter-time=msecs] [-q|--batch-mode] [--version]
        [-t|--timeout=secs] [-T|--tries=INT] [--align-payload=SECTORS]
        [--non-exclusive] [--header-backup-file=STRING]
        [OPTION...]  ]
cryptsetup: Argument  missing.
Ну вот в принципе и вся предыстория.

Ход Конем

Идём дальше, нам же нужно организовать usbtoken. Это тоже не проблема, решается она с помощью чтения документации и man'ов cryptsetup.

1. Создаем ключ.
Берём обычный Flash накопитель на базе интерфейса USB, любого размера - у меня были 2 шт. по 2 Гб - меньше в магазинах тяжеловато найти :) Форматируем ее в vfat и монтируем:
sudo su - 
mkfs.vfat /dev/sdd1
mkdir /mnt/usbkey
mount /dev/sdd1 /mnt/usbkey
Теперь, на неё нужно залить наш будущий ключ:
dd if=/dev/random of=/mnt/usbkey/public.key bs=1 count=256
Тут думаю все понятно. Теперь, ключ готов и он на флэшке.

2. Криптование тома.
У меня хранилище на зеркальном софтовом RAID'е. У вас может быть по-другому, но смысл тот же:
cryptsetup --verbose -c aes-cbc-essiv:sha256 luksFormat /dev/md0 /mnt/usbkey/public.key
Том зашифрован, подключаем его:
cryptsetup --key-file /mnt/usbkey/public.key luksOpen /dev/md0 public
Ну и форматируем:
mkfs.ext3 -j -m 1 -O dir_index,sparse_super /dev/mapper/public
Всё, он готов.

Назад в будущее

Вот с автомонтированием оказалось посложнее. Точнее, документацию и примеры я быстро нашёл. Но там чёрт ногу сломит ) Сначала, с irc-канала #archlinux-ru меня направили в арчвики по ключевому слову “udev”. Оттуда по ссылкам я дошёл до документации. Долго читал и экспериментировал, из этого вышел такой вот конфиг, точнее его минимальный вариант:

[root@localhost ~]# cat /etc/udev/rules.d/10-usb-storage.rules 
# если не sd уходим
KERNEL!="sd[a-z][0-9]", GOTO="end"
# если переменная существует, то отмонтируем /public
ACTION=="remove", ENV{dir_name}=="?*", RUN+="/bin/umount -l /public"
# если переменная существует, то закрываем ключ
ACTION=="remove", ENV{dir_name}=="?*", RUN+="/sbin/cryptsetup luksClose public"
# если переменная существует, то отмонтируем саму флэш
ACTION=="remove", ENV{dir_name}=="?*", RUN+="/bin/umount -l /mnt/%E{dir_name}"
# если переменная существует, то удаляем каталог
ACTION=="remove", ENV{dir_name}=="?*", RUN+="/bin/rmdir /mnt/%E{dir_name}", GOTO="end"
# проверяем на предмет монтирования (тут можно извращаться как хотите, но главное чтоб понимали, что делаете)
ACTION=="add", PROGRAM=="/usr/bin/find /mnt/usbkey", RESULT=="/mnt/usbkey", GOTO="end"
# ищем именно наши флэшки (просто у меня их две - с запасом, а посмотреть uuid можно /lib/udev/vol_id -u /dev/sdd1)
# и переходим к монтированию, иначе уходим в конец
ACTION=="add", PROGRAM=="/lib/udev/vol_id -u %N", RESULT=="4B7E-E254", GOTO="mount"
ACTION=="add", PROGRAM=="/lib/udev/vol_id -u %N", RESULT=="2C3E-F663", GOTO="mount"
GOTO="end"
LABEL="mount"
# опции монтирования и переменная каталога
ACTION=="add", ENV{mount_options}="ro,utf8,noexec,nodev,noauto", ENV{dir_name}="usbkey"
# создаем каталог
ACTION=="add", RUN+="/bin/mkdir /mnt/%E{dir_name}"
# монтируем ключ
ACTION=="add", RUN+="/bin/mount -t vfat -o $env{mount_options} /dev/%k /mnt/%E{dir_name}"
# открываем наш криптованный том
ACTION=="add", RUN+="/sbin/cryptsetup --key-file /mnt/usbkey/public.key luksOpen /dev/md0 public"
# монтируем его
ACTION=="add", RUN+="/bin/mount /dev/mapper/public /public -t ext3 -o defaults"
LABEL="end
Думаю, тут тоже всё понятно, конфиг минимальный. У меня, в итоге, он оказался совсем другой. Но мысль я донёс. Отладку конфига можно сделать так:
udevcontrol log_priority=9999
И смотреть журнал:
tail -f /var/log/messages
Итоги

Вот таким вот нехитрым методом можно получить динамически монтируемые тома на основе usbtoken'ов.