dracut + systemd + LUKS + usbflash = avtomatik qulfni ochish

Hikoya uzoq vaqt oldin, Centos 7 (RHEL 7) chiqarilganda boshlangan. Agar siz Centos 6 drayvlarida shifrlashni ishlatgan bo'lsangiz, USB flesh-diskini kerakli kalitlar bilan ulaganingizda drayverlarni avtomatik ravishda qulfdan chiqarish bilan bog'liq muammolar bo'lmagan. Biroq, 7 chiqarilganda, to'satdan hamma narsa siz ko'rganingizdek ishlamadi. Keyin konfiguratsiyadagi oddiy chiziq yordamida dracutni sysvinit-ga qaytarish yechimini topish mumkin edi: echo 'omit_dracutmodules+=" systemd "' > /etc/dracut.conf.d/luks-workaround.conf
Bu bizni systemd ning barcha go'zalligidan darhol mahrum qildi - tizim xizmatlarini tez va parallel ishga tushirish, bu tizimni ishga tushirish vaqtini sezilarli darajada qisqartirdi.
Ishlar hali ham mavjud: 905683
Yechimni kutmasdan, men buni o'zim uchun qildim va endi men buni jamoatchilik bilan baham ko'raman, qiziquvchilar, o'qing.
dracut + systemd + LUKS + usbflash = avtomatik qulfni ochish

kirish

Systemd, men Centos 7 bilan birinchi marta ishlay boshlaganimda, hech qanday his-tuyg'ularga sabab bo'lmadi, chunki xizmatlarni boshqarish sintaksisidagi kichik o'zgarishlardan tashqari, men birinchi navbatda unchalik katta farqni his qilmadim. Keyinchalik menga systemd yoqdi, lekin birinchi taassurot biroz buzilgan edi, chunki dracut ishlab chiquvchilari diskni shifrlash bilan birgalikda systemd yordamida yuklash jarayonini qo'llab-quvvatlashga ko'p vaqt sarflamadilar. Umuman olganda, u ishladi, lekin har safar server ishga tushganda disk parolini kiritish eng qiziq narsa emas.
Bir qator tavsiyalarni sinab ko'rib, qo'llanmani o'rganib chiqib, men tushundimki, tizim rejimida USB bilan konfiguratsiya qilish mumkin, lekin faqat har bir diskni USB diskdagi kalit bilan qo'lda bog'lash va USB diskning o'zini faqat uning yordamida bog'lash mumkin. UUID, LABEL ishlamadi. Buni uyda saqlash juda qulay emas edi, shuning uchun oxir-oqibat men kutishga kirishdim va deyarli 7 yil kutganimdan so'ng, hech kim muammoni hal qilmasligini angladim.

Muammolar

Albatta, deyarli har bir kishi dracut uchun o'z plaginini yozishi mumkin, ammo uni ishga tushirish endi unchalik oson emas. Ma'lum bo'lishicha, tizimni ishga tushirishning parallel tabiati tufayli kodingizni kiritish va yuklanish jarayonini o'zgartirish oson emas. Dracut uchun hujjatlar hamma narsani tushuntirib bermadi. Biroq, uzoq tajribalardan so'ng, men muammoni hal qila oldim.

Bu qanday ishlaydi

U uchta birlikka asoslangan:

  1. luks-auto-key.service - LUKS kalitlari bilan drayverlarni qidiradi
  2. luks-auto.target - o'rnatilgan systemd-cryptsetup birliklariga bog'liqlik vazifasini bajaradi
  3. luks-auto-clean.service - luks-auto-key.service tomonidan yaratilgan vaqtinchalik fayllarni tozalaydi

Va luks-auto-generator.sh - bu systemd tomonidan ishga tushiriladigan va yadro parametrlari asosida birliklarni ishlab chiqaradigan skript. Shunga o'xshash generatorlar fstab birliklari va boshqalar tomonidan yaratilgan.

luks-auto-generator.sh

Drop-in.conf dan foydalanib, standart systemd-cryptsetup ning xatti-harakati ularning bog'liqligiga luks-auto.target qo'shish orqali o'zgartiriladi.

luks-auto-key.service va luks-auto-key.sh

Bu birlik rd.luks.* tugmalariga asoslanib, tugmalar bilan mediani topib, keyinchalik foydalanish uchun ularni vaqtinchalik katalogga ko'chiradigan luks-auto-key.sh skriptini boshqaradi. Jarayon tugagandan so'ng, kalitlar luks-auto-clean.service tomonidan vaqtinchalik katalogdan o'chiriladi.

Manbalar:

/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 "

sozlama


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

xulosa

Qulaylik uchun sysvinit rejimiga o'xshab, yadro buyruq qatori opsiyalari bilan moslikni saqlab qoldim, bu eski o'rnatishlarda foydalanishni osonlashtiradi.

Manba: www.habr.com

a Izoh qo'shish