dracut + systemd + LUKS + usbflash = автоматты түрде құлыпты ашу

Әңгіме баяғыда, Centos 7 (RHEL 7) шыққан кезде басталды. Егер сіз Centos 6 дискілерінде шифрлауды қолдансаңыз, USB флэш-дискісін қажетті пернелермен қосқан кезде дискілердің құлпын автоматты түрде ашуда проблемалар болған жоқ. Алайда, 7 шығарылған кезде, кенеттен бәрі сіз үйренгендей болмады. Содан кейін конфигурациядағы қарапайым жолды пайдаланып dracut файлын sysvinit-ке қайтару шешімін табуға болады: echo 'omit_dracutmodules+=" systemd "' > /etc/dracut.conf.d/luks-workaround.conf
Бұл бізді systemd барлық сұлулығынан бірден айырды - жүйелік қызметтерді жылдам және параллель іске қосу, бұл жүйені іске қосу уақытын айтарлықтай қысқартты.
Әлі де заттар бар: 905683
Шешімді күтпестен, мен оны өзім жасадым, енді мен оны қызығушылық танытқан жұртшылықпен бөлісіп жатырмын.
dracut + systemd + LUKS + usbflash = автоматты түрде құлыпты ашу

Кіріспе

Systemd, мен Centos 7-мен алғаш жұмыс істей бастағанда, ешқандай эмоциялар тудырмады, өйткені қызметті басқару синтаксисіндегі шамалы өзгерістерден басқа, мен басында көп айырмашылықты сезінбедім. Кейіннен маған systemd ұнады, бірақ бірінші әсер аздап бүлінді, өйткені dracut әзірлеушілері дискіні шифрлаумен бірге systemd көмегімен жүктеу процесін қолдауға көп уақыт жұмсамады. Жалпы, бұл жұмыс істеді, бірақ сервер іске қосылған сайын дискінің құпия сөзін енгізу ең қызықты нәрсе емес.
Көптеген ұсыныстарды қолданып, нұсқаулықты зерделей отырып, мен жүйелік режимде USB арқылы конфигурациялау мүмкін екенін түсіндім, бірақ әр дискіні USB дискідегі кілтпен қолмен байланыстыру арқылы ғана, ал USB дискінің өзін тек оның көмегімен байланыстыруға болады. UUID, LABEL жұмыс істемеді. Мұны өз үйімде ұстау өте ыңғайлы болмады, сондықтан мен күтуге кірістім және 7 жылға жуық күткеннен кейін мәселені ешкім шеше алмайтынын түсіндім.

проблемалар

Әрине, кез келген адам дерлік dracut үшін өз плагинін жаза алады, бірақ оны жұмыс істеу енді оңай емес. Жүйені іске қосудың параллельді сипатына байланысты кодты қосу және жүктеу барысын өзгерту оңай емес екені белгілі болды. Dracut құжаттамасы бәрін түсіндірмеді. Дегенмен, ұзақ тәжірибелерден кейін мен мәселені шеше алдым.

Бұл қалай жұмыс істейді

Ол үш бірлікке негізделген:

  1. luks-auto-key.service - LUKS кілттері бар дискілерді іздейді
  2. luks-auto.target - кірістірілген systemd-cryptsetup бірліктеріне тәуелділік ретінде әрекет етеді
  3. luks-auto-clean.service - luks-auto-key.service жасаған уақытша файлдарды тазартады

Ал luks-auto-generator.sh — systemd арқылы іске қосылатын және ядро ​​параметрлері негізінде бірліктерді жасайтын сценарий. Ұқсас генераторлар fstab қондырғыларымен және т.б.

luks-auto-generator.sh

drop-in.conf көмегімен стандартты systemd-cryptsetup әрекеті олардың тәуелділігіне luks-auto.target қосу арқылы өзгертіледі.

luks-auto-key.service және luks-auto-key.sh

Бұл құрылғы rd.luks.* пернелеріне негізделген luks-auto-key.sh сценарийін іске қосады, ол пернелері бар медианы табады және оларды әрі қарай пайдалану үшін уақытша каталогқа көшіреді. Процесс аяқталғаннан кейін кілттер luks-auto-clean.service арқылы уақытша каталогтан жойылады.

Дереккөздер:

/usr/lib/dracut/modules.d/99luks-auto/module-setup.sh

#!/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"
}

/usr/lib/dracut/modules.d/99luks-auto/luks-auto-generator.sh


#!/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

/usr/lib/dracut/modules.d/99luks-auto/luks-auto-key.service


[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

/usr/lib/dracut/modules.d/99luks-auto/luks-auto-key.sh


#!/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

/usr/lib/dracut/modules.d/99luks-auto/luks-auto.target


[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

/usr/lib/dracut/modules.d/99luks-auto/luks-auto.sh


#!/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."

/usr/lib/dracut/modules.d/99luks-auto/luks-auto-clean.service

[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

/etc/dracut.conf.d/luks-auto.conf

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

қорытынды

Ыңғайлы болу үшін мен ескі қондырғыларда пайдалануды жеңілдететін sysvinit режимі сияқты ядро ​​​​пәрмен жолы опцияларымен үйлесімділікті сақтадым.

Ақпарат көзі: www.habr.com

пікір қалдыру