FreeBSD virtual environment management and repository

2020-10 upd: we reached the first fundraising goal and rented a server in Hetzner for development! Thank you for donating !

Шифрованные образы с cbsd geli

Имеются ситуации, когда информацию, размещенную на жестком диске сервера желательно хранить в зашифрованном виде. Например, вы устанавливаете сервер с важной информацией в любом чужом датацентре. Бывают реальные случаи (автор с таким случаем знаком не по наслышке), когда недобросовестные сотрудники датацентра могут на несколько минут выключить ваш сервер под любым предлогом (перерывы на технические работы — не редкость), сделать образ жесткого диска и включить обратно, что для вас будет выглядеть как перезагрузка сервера, в то время как вся информация стала находится у сторонних лиц. Либо, вы арендуете VDS/VPS, где чужой для вас не только датацентр, но и сам сервер и носитель информации.

В подобных случаях прибегают к шифрованию тех данных, утечка которых нежелательна. В данный момент, CBSD имеет скрипт-враппер geli для работы с зашифрованными образами через GELI фреймворк. Также, как перед использованием CBSD крайне желательно ознакомится с оригинальным man на jail, так и в данном контексте настоятельно рекомендуется ознакомиться со следующей информацией:

перед использованием cbsd geli.

Работа с GELI предполагается по следующему сценарию:

  • Криптованию подлежат только выборочные данные. Поскольку операция шифрования зависима в первую очередь от вашего процессора, потребление ресурсов всегда будет выше, а I/O — ниже при работе с данными на зашифрованном разделе. Вместо того, чтобы шифровать всю клетку, вы можете предпочесть зашифровать только важные данны внутри клетки, например: /root, /home/user, /var/db/mysql. /usr/local/etc и тд, при этом логи, база или весь сторонний софт, который вы установили через pkg/ports — можно оставить незашифрованными. Также, кроме шифрования данных клеток, вы можете захотеть шифровать каталог $workdir/.rssh, в котором CBSD хранит ID_RSA ключи удаленных машин и $workdir/.ssh в котором расположен собственный ключ от пользователя cbsd.
  • Каждому зашифрованному устройству назначается свой собственный пароль/фраза для дешифрации. Однако, все они будут хранится на системном образе CBSD, который в свою очередь будет зашифрован master-ключем. Другими словами, поскольку вы доверяете вашему собственному серверу, то при необходимости включить тот или иной зашифрованный раздел, CBSD будет сама применять нужный ключ при подключении того или иного криптованного образа. При этом ключи для их дешифровки хранится в файле, который в свою очередь зашифрованным вашим паролем и активируется вручную.

Для общего понимания, обозначим следующие условности:

  • ${dbdir}— каталог $workdir/var/db, где workdir — куда проинициализирована CBSD. Например: /usr/jails/var/db
  • MASTER_GELI— зашифрованный вашим паролем образ, в котором CBSD будет искать ключи для всех остальных geli attach операций. Расположен на файловой системе в виде файла ${dbdir}/master_geli.img

ВНИМАНИЕ! Удаление или порча этогоо файла сделает невозможным подключение всех остальные криптованных образов автоматически и подмонтировать эти образы будет возможно только если вы помните, какому образу какой пароль вы назначали на cbsd geli mode=init file= стадии. В связи с этим, регулярно делайте резервные копии этого файла.

  • каталог ключей— смонтированный образ MASTER_GELI файла в каталог ${dbdir}/geli. Во избежание возможной порчи из-за некорректного размонтирования (сбой сервера, пропажа питания, некорректное выключение), данный ресурс подключен в режиме Read-only и переходит в режим записи только при модификациях.

Инициализация cbsd geli

Для начала работы с шифрованными разделами на ноде, необходимо создать MASTER_GELI файл и придумать для него пароль. Используйте сложный пароль, поскольку он открывает доступ для всех остальных ключей. Для инициалиации служит команда cbsd geli mode=initmaster.

			% cbsd geli mode=initmaster
			Initialization. Please set master password for geli base image
			Enter new passphrase:
		

Вторичный запуск этой команды выдаст вопрос на ввод пароля, либо команда отработает без какого-либо вывода, если данный файл уже проиницализирован и подмонтирован в $dbdir/geli. Успешная инициализация файла подключает содержимое файла в каталог $dbdir/geli, давай остальным скриптам доступ к ключам остальных образов.

Примечание:

По-умолчанию, образ для хранения ключей создается равным 5Mb и используется алгоритм AES-XTS. Данная настройка находится в файле ${workdir}/etc/defaults/geli.conf и может быть изменена через соответствующие записи в $workdir/etc/geli.conf

Инициализация geli-образов для использования CBSD

GELI образ должен быть приинициализирован до того, как вы примонтируете его и начнете писать информацию. Для инициализации служит команда:

			% cbsd geli mode=init file=/path/to/file
		

При первом запуске geli init для файла /path/to/file будет выполнены следующие шаги:

  • 1) если в путь к файлу начинается с $workdir (например, CBSD установлена в /usr/jails, а cbsd init выполняется с параметрами mode=init file=/usr/jails/jails-system/jail1/root.img), то логикой скрипта путь $workdir удаляется из пути и эта локация используется для генерации имени файла ключа через md5. Подобная операция необходима для тех случаев, если вы будете мигрировать клетку с одной ноды на другую и различными $workdir — если не отрезать workdir, то md5 имена ключей станут разными. Если же путь задается для файла, не входящего в $workdir, путь остается без изменений.
  • 2) скрипт cbsd geli запрашивает от вас пароль для файла в переменной file= и сохраняет его в файле $dbdir/geli/md5_от_результата_шага_1
  • 3) выполняет geli attach с этим ключем и выводит имя получившегося устройства, например:
    				/dev/md1.eli
    			
    который вы уже можете отформатировать и заполнить теми данными, которые будут зашифрованы.

Как и в случае с initmaster, если запускается init на файл вторично — система без вопросов его презентует, если ключ уже имеется.

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

Использование fstab клеток для составления списка криптованных имиджей и точек монтирования

Например чтобы клетка jail1 при запуске подмонтировала криптованный образ в каталог /usr/home/web внутри окружения, в локальном fstab файле клетки пишется имя файла образа и указывается тип файловой системы geli, например:

			webhome.img /usr/home/web geli rw 0 0
		

В этом случае, файл webhome.img должен лежать в директории /usr/jails/jails-system/jail1/ (если workdir = /usr/jails).

Если вы храните криптованный образ не в /usr/jails/jails-system/$jname/ каталоге, то необходимо прописывать полный путь, начинающийся с /. Например:

			/data/images/webhome.img /usr/home/web geli rw 0 0
		

Однако, хранение .img файлов для клетки в /usr/jails/jails-system/$jname/ является рекомендуемой, поскольку каталог jails-system/$jname учавствует в операциях миграции, jimport, jexport. В противном случае, вам придется переносить файл образа самостоятельно.

Имейте ввиду, если после запуска сервера не произведена инициализация cbsd geli (cbsd geli mode=initmaster), которая после ввода пароля получает доступ к ключам для расшифровки образов, то при старте клетки, не найдя ключа для дешифровки, данный образ не будет подключен. Поэтому, как правило, криптованные клетки должны иметь флаг автостарта выключенным (astart=0).

Практический пример

Предположим, у нас есть jail с именем private1, в котором базовые файлы, конфигурация и сторонний софт устанавливаемый из портов нам шифровать не требуется, поскольу все это и так можно скачать на просторах интернет. Однако содержимое домашнего каталога пользователя web по пути /usr/home/web внутри клетки должно быть зашифровано.

Поскольку при загрузке сервера нам необходимо будет вводить вручную пароль, сделаем себе посылку письма на электронную почту для тех случаев, когда сервер может перезапуститься без нашего ведома. Для этого в /etc/crontab добавим запись:

	@reboot root /bin/echo "Incident date: `/bin/date`"| mail -s "`/bin/hostname` rebooted" your_mail@my.domain
	

, где your_mail@my.domain - ваша электронная почта.

Выполним инициализацию master-образа CBSD, где будут хранится все ключи к образам. Вам будет предложено ввести фразу для дешифровки этого образа повторно, чтобы проинициализировать его немедленно. Не забывайте его.

	% cbsd geli mode=initmaster
	Initialization. Please set master password for geli base image
	Enter new passphrase:
	Reenter new passphrase: 
	Attaching geli base image. Please use master password.
	Enter passphrase:
	Init complete: /usr/jails/var/db/master_geli.img
	

Крайне желательно делать резервные копии файлу /usr/jails/var/db/master_geli.img, поскольку без него (или при поврежденном файле) и не помня персональные пароли (шагом ниже) для дешифрации конкретного образа, вы не сможете получить к ним доступ.

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

Создадим образ достаточного объема, в котором будет находится шифрованная файловая система. Например, создадим образ объемом в 10 Гбайт (подразумевается, что клетка jail1 уже создана и каталог /usr/jails/jails-system/private1 присутствует на файловой системе):

	% cd /usr/jails/jails-system/private1
	% truncate -s 10g home_web.img
	

Проинициализируем на этом файле GELI. Фраза, которую вы введете для дешифровки, будет сохранена в виде файла внутри зашифрованного мастер-паролем образа /usr/jails/var/db/master_geli.img, который вы создали выше.

	% cbsd geli mode=init file=/usr/jails/jails-system/private1/home_web.img
	Metadata backup can be found in /var/backups/md1.eli and
	can be restored with the following command:
	
	# geli restore /var/backups/md1.eli /dev/md1
	
	/dev/md1.eli
	

Файл /dev/md1.eli в выводе является в данный момент проинициализированным GELI-образом, на котором теперь необходимо создать файловую систему.

Вы можете убедиться, что файл md1 соответствует именно образу /usr/jails/jails-system/private1/home_web.img, посмотрев на вывод команды:

	% mdconfig -vl
	md0     vnode    5120K  /usr/jails/var/db/master_geli.img
	md1     vnode      10G  /usr/jails/jails-system/private1/home_web.img
	

Создаем файловую систему:

	% newfs -U -n -m0 /dev/md1.eli 
	

Теперь осталось добавить в fstab клетки информацию об GELI образе. Открываем или создаем файл /usr/jails/jails-fstab/fstab.private1.local и добавляем строчку:

	home_web.img /usr/home/web geli rw 0 0
	

Создадим пустой каталог /usr/home/web внутри клетки, которая будет являться точкой монтирования, если его нет:

	% mkdir -p /usr/jails/jails-data/private1-data/usr/home/web
	

Дополнительно, убедимся что клетка private1 не будет пробовать запускаться автоматически, поскольку в этом случае, без первичной инициализации CBSD GELI клетка запустится с пустым /usr/home/web:

	% cbsd jset jname=private1 astart=0
	% cbsd jls display=jname,astart
	JNAME     ASTART
	private1  0
	

После чего остается запустить клетку и убедится, что каталог примонтирован:

	% cbsd jstart private1
	% mount | grep "/usr/home/web"
	/dev/md1.eli on /usr/jails/jails/private1/usr/home/web (ufs, local, soft-updates)
	

После каждой перезагрузки ОС, вам необходимо разово заходить на сервер и инициализировать master-GELI образ через команду:

	% cbsd geli mode=initmaster
	

После чего до перезагрузки, CBSD сможет пользоваться индивидуальными ключами для дешифрации образов при запуске и останове клеток самостоятельно.

Нативное криптование ZFS

Начиная с версии CBSD 13.0.5 и при использовании FreeBSD 13.0, поддерживается создание контейнеров с применением нативного криптования ZFS датасета с использованием фразы, например:

	% cbsd jcreate jname=xxx zfs_encryption=1 runasap=1
	% zfs get encryption