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-г ашигласнаар luks-auto.target-ийг тэдгээрийн хамаарал дээр нэмснээр стандарт systemd-cryptsetup-ийн үйлдлийг өөрчилдөг.

luks-auto-key.service болон luks-auto-key.sh

Энэ нэгж нь luks-auto-key.sh скриптийг ажиллуулдаг бөгөөд энэ нь rd.luks.* товчлуурууд дээр тулгуурлан товчлууртай зөөвөрлөгчийг олж, цаашид ашиглахын тулд түр зуурын лавлах руу хуулдаг. Процесс дууссаны дараа түлхүүрүүдийг 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

сэтгэгдэл нэмэх