драцут + системд + ЛУКС + усбфласх = аутоматско откључавање

Прича је почела давно, када је Центос 7 (РХЕЛ 7) изашао. Ако сте користили шифровање на диск јединицама са Центос 6, онда није било проблема са аутоматским откључавањем диск јединица када сте повезали УСБ флеш диск са потребним кључевима. Међутим, када је 7 изашао, одједном све није функционисало како сте навикли. Тада је било могуће пронаћи решење у враћању драцута у сисвинит користећи једноставну линију у конфигурацији: ецхо 'омит_драцутмодулес+=" системд "' > /етц/драцут.цонф.д/лукс-воркароунд.цонф
Што нас је одмах лишило сву лепоту системд-а – брзо и паралелно покретање системских сервиса, што је значајно смањило време покретања система.
Ствари су још увек ту: 905683
Не чекајући решење, направио сам га за себе, а сада га делим са јавношћу, која је заинтересована, читајте даље.
драцут + системд + ЛУКС + усбфласх = аутоматско откључавање

Увод

Системд, када сам први пут почео да радим са Центосом 7, није изазвао никакве емоције, јер осим мање промене у синтакси управљања сервисом, у почетку нисам осетио велику разлику. Касније ми се допао системд, али први утисак је био мало покварен, пошто програмери драцута нису трошили много времена на подршку процеса покретања користећи системд у комбинацији са шифровањем диска. Генерално, функционисало је, али уношење лозинке за диск сваки пут када се сервер покрене није најзанимљивија ствар.
Након што сам испробао гомилу препорука и проучио приручник, схватио сам да је у системском режиму конфигурација са УСБ-ом могућа, али само уз ручно повезивање сваког диска са кључем на УСБ диску, а сам УСБ диск може бити повезан само његовим УУИД, ЛАБЕЛ није функционисао. Није било баш згодно одржавати ово код куће, па сам на крају уронио у чекање и након скоро 7 година чекања схватио сам да нико неће решити проблем.

Проблеми

Наравно, скоро свако може да напише сопствени додатак за драцут, али више није тако лако учинити га да функционише. Испоставило се да због паралелне природе покретања системд-а није тако лако укључити свој код и променити напредак учитавања. Документација за драцут није све објаснила. Међутим, након дугих експеримената, успео сам да решим проблем.

Како то функционише

Заснован је на три јединице:

  1. лукс-ауто-кеи.сервице - тражи дискове са кључевима за ЛУКС
  2. лукс-ауто.таргет - делује као зависност за уграђене јединице системд-цриптсетуп
  3. лукс-ауто-цлеан.сервице - чисти привремене датотеке које је креирао лукс-ауто-кеи.сервице

И лукс-ауто-генератор.сх је скрипта коју покреће системд и генерише јединице на основу параметара кернела. Сличне генераторе стварају фстаб јединице итд.

лукс-ауто-генератор.сх

Коришћењем дроп-ин.цонф, понашање стандардног системд-цриптсетуп-а се мења додавањем лукс-ауто.таргет њиховој зависности.

лукс-ауто-кеи.сервице и лукс-ауто-кеи.сх

Ова јединица покреће лукс-ауто-кеи.сх скрипту, која, на основу кључева рд.лукс.*, проналази медијум са кључевима и копира их у привремени директоријум за даљу употребу. Након што се процес заврши, лукс-ауто-цлеан.сервице брише кључеве из привременог директоријума.

Извори:

/уср/либ/драцут/модулес.д/99лукс-ауто/модуле-сетуп.сх

#!/bin/bash

check () {
        if ! dracut_module_included "systemd"; then
                "luks-auto needs systemd in the initramfs"
                return 1
        fi
        return 255
}

depends () {
        echo "systemd"
        return 0
}

install () {
        inst "$systemdutildir/systemd-cryptsetup"
		inst_script "$moddir/luks-auto-generator.sh" "$systemdutildir/system-generators/luks-auto-generator.sh"
		inst_script "$moddir/luks-auto-key.sh" "/etc/systemd/system/luks-auto-key.sh"
		inst_script "$moddir/luks-auto.sh" "/etc/systemd/system/luks-auto.sh"
		inst "$moddir/luks-auto.target" "${systemdsystemunitdir}/luks-auto.target"
		inst "$moddir/luks-auto-key.service" "${systemdsystemunitdir}/luks-auto-key.service"
		inst "$moddir/luks-auto-clean.service" "${systemdsystemunitdir}/luks-auto-clean.service"
		ln_r "${systemdsystemunitdir}/luks-auto.target" "${systemdsystemunitdir}/initrd.target.wants/luks-auto.target"
		ln_r "${systemdsystemunitdir}/luks-auto-key.service" "${systemdsystemunitdir}/initrd.target.wants/luks-auto-key.service"
		ln_r "${systemdsystemunitdir}/luks-auto-clean.service" "${systemdsystemunitdir}/initrd.target.wants/luks-auto-clean.service"
}

/уср/либ/драцут/модулес.д/99лукс-ауто/лукс-ауто-генератор.сх


#!/bin/sh
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh

. /lib/dracut-lib.sh

SYSTEMD_RUN='/run/systemd/system'
CRYPTSETUP='/usr/lib/systemd/systemd-cryptsetup'
TOUT=$(getargs rd.luks.key.tout)
if [ ! -z "$TOUT" ]; then
	mkdir -p "${SYSTEMD_RUN}/luks-auto-key.service.d"
	cat > "${SYSTEMD_RUN}/luks-auto-key.service.d/drop-in.conf"  <<EOF
[Service]
Type=oneshot
ExecStartPre=/usr/bin/sleep $TOUT

EOF
fi
mkdir -p "$SYSTEMD_RUN/luks-auto.target.wants"
for argv in $(getargs rd.luks.uuid -d rd_LUKS_UUID); do
	_UUID=${argv#luks-}
	_UUID_ESC=$(systemd-escape -p $_UUID)
	mkdir -p "${SYSTEMD_RUN}/systemd-cryptsetup@luksx2d${_UUID_ESC}.service.d"
	cat > "${SYSTEMD_RUN}/systemd-cryptsetup@luksx2d${_UUID_ESC}.service.d/drop-in.conf"  <<EOF
[Unit]
After=luks-auto.target
ConditionPathExists=!/dev/mapper/luks-${_UUID}

EOF
	cat > "${SYSTEMD_RUN}/luks-auto@${_UUID_ESC}.service"  <<EOF
[Unit]
Description=luks-auto Cryptography Setup for %I
DefaultDependencies=no
Conflicts=umount.target
IgnoreOnIsolate=true
Before=luks-auto.target
BindsTo=dev-disk-byx2duuid-${_UUID_ESC}.device
After=dev-disk-byx2duuid-${_UUID_ESC}.device luks-auto-key.service
Before=umount.target

[Service]
Type=oneshot
RemainAfterExit=yes
TimeoutSec=0
ExecStart=/etc/systemd/system/luks-auto.sh ${_UUID}
ExecStop=$CRYPTSETUP detach 'luks-${_UUID}'
Environment=DRACUT_SYSTEMD=1
StandardInput=null
StandardOutput=syslog
StandardError=syslog+console

EOF
ln -fs ${SYSTEMD_RUN}/luks-auto@${_UUID_ESC}.service $SYSTEMD_RUN/luks-auto.target.wants/luks-auto@${_UUID_ESC}.service
done

/уср/либ/драцут/модулес.д/99лукс-ауто/лукс-ауто-кеи.сервице


[Unit]
Description=LUKS AUTO key searcher
After=cryptsetup-pre.target
Before=luks-auto.target
DefaultDependencies=no

[Service]
Environment=DRACUT_SYSTEMD=1
Type=oneshot
ExecStartPre=/usr/bin/sleep 1
ExecStart=/etc/systemd/system/luks-auto-key.sh
RemainAfterExit=true
StandardInput=null
StandardOutput=syslog
StandardError=syslog+console

/уср/либ/драцут/модулес.д/99лукс-ауто/лукс-ауто-кеи.сх


#!/bin/sh
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh
export DRACUT_SYSTEMD=1

. /lib/dracut-lib.sh
MNT_B="/tmp/luks-auto"
ARG=$(getargs rd.luks.key)
IFS=$':' _t=(${ARG})
KEY=${_t[0]}
F_FIELD=''
F_VALUE=''
if [ ! -z $KEY ] && [ ! -z ${_t[1]} ];then
	IFS=$'=' _t=(${_t[1]})
	F_FIELD=${_t[0]}
	F_VALUE=${_t[1]}
	F_VALUE="${F_VALUE%"}"
	F_VALUE="${F_VALUE#"}"
fi
mkdir -p $MNT_B

finding_luks_keys(){
	local _DEVNAME=''
	local _UUID=''
	local _TYPE=''
	local _LABEL=''
	local _MNT=''
	local _KEY="$1"
	local _F_FIELD="$2"
	local _F_VALUE="$3"
	local _RET=0	
	blkid -s TYPE -s UUID -s LABEL -u filesystem | grep -v -E -e "TYPE=".*_member"" -e "TYPE="crypto_.*"" -e "TYPE="swap"" | while IFS=$'' read -r _line; do
		IFS=$':' _t=($_line);
		_DEVNAME=${_t[0]}
		_UUID=''
		_TYPE=''
		_LABEL=''
		_MNT=''
		IFS=$' ' _t=(${_t[1]});
		for _a in "${_t[@]}"; do
			IFS=$'=' _v=(${_a});
			temp="${_v[1]%"}"
			temp="${temp#"}"
			case ${_v[0]} in
				'UUID')
					_UUID=$temp
				;;
				'TYPE')
					_TYPE=$temp
				;;
				'LABEL')
					_LABEL=$temp
				;;
			esac
		done
		if [ ! -z "$_F_FIELD" ];then
			case $_F_FIELD in
				'UUID')
					[ ! -z "$_F_VALUE" ] && [ "$_UUID" != "$_F_VALUE" ] && continue
				;;
				'LABEL')
					[ ! -z "$_F_VALUE" ] && [ "$_LABEL" != "$_F_VALUE" ] && continue
				;;
				*)
					[ "$_DEVNAME" != "$_F_FIELD" ] && continue
				;;
			esac
		fi
		_MNT=$(findmnt -n -o TARGET $_DEVNAME)
		if [ -z "$_MNT" ]; then
			_MNT=${MNT_B}/KEY-${_UUID}
			mkdir -p "$_MNT" && mount -o ro "$_DEVNAME" "$_MNT"
			_RET=$?
		else
			_RET=0
		fi
		if [ "${_RET}" -eq 0 ] && [ -f "${_MNT}/${_KEY}" ]; then
			cp "${_MNT}/${_KEY}" "$MNT_B/${_UUID}.key"
			info "Found ${_MNT}/${_KEY} on ${_UUID}"
		fi
		if [[ "${_MNT}" =~ "${MNT_B}" ]]; then
			umount "$_MNT" && rm -rfd --one-file-system "$_MNT"						
		fi
	done
	return 0
}
finding_luks_keys $KEY $F_FIELD $F_VALUE

/уср/либ/драцут/модулес.д/99лукс-ауто/лукс-ауто.таргет


[Unit]
Description=LUKS AUTO target
After=systemd-readahead-collect.service systemd-readahead-replay.service
After=cryptsetup-pre.target luks-auto-key.service
Before=cryptsetup.target

/уср/либ/драцут/модулес.д/99лукс-ауто/лукс-ауто.сх


#!/bin/sh
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh
export DRACUT_SYSTEMD=1
. /lib/dracut-lib.sh

MNT_B="/tmp/luks-auto"
CRYPTSETUP='/usr/lib/systemd/systemd-cryptsetup'

for i in $(ls -p $MNT_B | grep -v /);do
	info "Trying $i on $1..."
	$CRYPTSETUP attach "luks-$1" "/dev/disk/by-uuid/$1" $MNT_B/$i 'tries=1'
	if [ "$?" -eq "0" ]; then
		info "Found $i for $1"
		exit 0
	fi
done
warn "No key found for $1.  Fallback to passphrase mode."

/уср/либ/драцут/модулес.д/99лукс-ауто/лукс-ауто-цлеан.сервице

[Unit]
Description=LUKS AUTO key cleaner
After=cryptsetup.target
DefaultDependencies=no

[Service]
Type=oneshot
ExecStart=/usr/bin/rm -rfd --one-file-system /tmp/luks-auto

/етц/драцут.цонф.д/лукс-ауто.цонф

add_dracutmodules+=" luks-auto "

Инсталација


mkdir -p /usr/lib/dracut/modules.d/99luks-auto/
# размещаем тут почти все файлы
chmod +x /usr/lib/dracut/modules.d/99luks-auto/*.sh
# создаем файл /etc/dracut.conf.d/luks-auto.conf
# И генерируем новый initramfs
dracut -f

Закључак

Ради практичности, задржао сам компатибилност са опцијама командне линије кернела као за сисвинит режим, што га чини лакшим за коришћење у старијим инсталацијама.

Извор: ввв.хабр.цом

Додај коментар