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 иштеп чыгуучулары системаны диск шифрлөө менен бирге жүктөө процессин колдоого көп убакыт коротушкан эмес. Жалпысынан алганда, бул иштеди, бирок сервер ишке кирген сайын дисктин сырсөзүн киргизүү эң кызыктуу нерсе эмес.
Бир топ сунуштарды колдонуп, колдонмону окуп чыгып, мен 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

Бул блок 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 режими сыяктуу ядронун буйрук сабынын параметрлери менен шайкештикти сактап калдым, бул эски орнотууларда колдонууну жеңилдетет.

Source: www.habr.com

Комментарий кошуу