dracut + systemd + LUKS + usbflash = auto unlock

Nagsimula ang kwento matagal na ang nakalipas, noong ito ay ipinalabas. Centos 7 (RHEL 7). Kung gumamit ka ng encryption sa mga disk na may Centos 6, walang problema sa awtomatikong pag-unlock ng mga disk kapag ikinokonekta ang isang USB flash drive gamit ang mga tamang key. Gayunpaman, sa paglabas ng 7, biglang tumigil ang lahat sa paggana gaya ng inaasahan. Natagpuan ang isang solusyon sa pamamagitan ng pagbabalik ng dracut sa sysvinit gamit ang isang simpleng linya sa config: echo 'omit_dracutmodules+=" systemd "' > /etc/dracut.conf.d/luks-workaround.conf
Na agad na nag-alis sa amin ng lahat ng kagandahan ng systemd - mabilis at parallel na paglulunsad ng mga serbisyo ng system, na makabuluhang nabawasan ang oras ng pagsisimula ng system.
Ang mga bagay ay naroroon pa rin: 905683
Nang hindi naghihintay ng solusyon, ginawa ko ito para sa aking sarili, at ngayon ay ibinabahagi ko ito sa publiko, na interesado, basahin.
dracut + systemd + LUKS + usbflash = auto unlock

Pagpapakilala

Systemd noong una akong nagsimulang magtrabaho kasama Centos Hindi naman nakapagdulot ng anumang kapanapanabik ang 7, dahil bukod sa kaunting pagbabago sa syntax ng pamamahala ng serbisyo, hindi ko napansin ang malaking pagkakaiba noong una. Kalaunan ay nagustuhan ko ang systemd, ngunit ang una kong impresyon ay bahagyang nabahiran ng katotohanan na ang mga developer ng Dracut ay hindi gumugugol ng maraming oras sa pagsuporta sa proseso ng pag-boot ng systemd kasabay ng disk encryption. Gumagana ito sa pangkalahatan, ngunit kinailangan kong ilagay ang aking disk password sa bawat oras na sisimulan ko ito. server — hindi ang pinakakawili-wiling aktibidad.
Ang pagkakaroon ng pagsubok ng isang grupo ng mga rekomendasyon at pag-aralan ang manu-manong, napagtanto ko na sa systemd mode configuration na may USB ay posible, ngunit sa manu-manong pag-uugnay ng bawat disk na may isang susi sa isang USB disk, at ang USB disk mismo ay maaari lamang maiugnay sa pamamagitan nito. UUID, LABEL ay hindi gumana. Ito ay hindi masyadong maginhawa upang mapanatili ito sa bahay, kaya sa huli ay naghintay ako at, pagkatapos maghintay ng halos 7 taon, napagtanto ko na walang sinuman ang lutasin ang problema.

Mga Problema

Siyempre, halos kahit sino ay maaaring magsulat ng kanilang sariling plugin para sa dracut, ngunit ang paggawa nito ay hindi na napakadali. Ito ay lumabas na dahil sa magkatulad na katangian ng systemd startup, hindi ganoon kadali na isama ang iyong code at baguhin ang pag-unlad ng paglo-load. Ang dokumentasyon para sa dracut ay hindi ipinaliwanag ang lahat. Gayunpaman, pagkatapos ng mahabang eksperimento, nalutas ko ang problema.

Paano ito gumagana

Ito ay batay sa tatlong yunit:

  1. luks-auto-key.service - naghahanap ng mga drive na may mga key para sa LUKS
  2. luks-auto.target - nagsisilbing dependency para sa mga built-in na systemd-cryptsetup unit
  3. luks-auto-clean.service - nililinis ang mga pansamantalang file na ginawa ng luks-auto-key.service

At ang luks-auto-generator.sh ay isang script na inilunsad ng systemd at bumubuo ng mga unit batay sa mga parameter ng kernel. Ang mga katulad na generator ay nilikha ng mga unit ng fstab, atbp.

luks-auto-generator.sh

Gamit ang drop-in.conf, ang gawi ng karaniwang systemd-cryptsetup ay binago sa pamamagitan ng pagdaragdag ng luks-auto.target sa kanilang dependency.

luks-auto-key.service at luks-auto-key.sh

Ang unit na ito ay nagpapatakbo ng luks-auto-key.sh script, na, batay sa mga rd.luks.* key, ay naghahanap ng media na may mga key at kinokopya ang mga ito sa isang pansamantalang direktoryo para sa karagdagang paggamit. Matapos makumpleto ang proseso, ang mga susi ay tatanggalin mula sa pansamantalang direktoryo ng luks-auto-clean.service.

Mga Pinagmulan:

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

Instalasyon


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

Konklusyon

Para sa kaginhawahan, pinananatili ko ang pagiging tugma sa mga pagpipilian sa linya ng command ng kernel tulad ng para sa sysvinit mode, na ginagawang mas madaling gamitin sa mas lumang mga pag-install.

Pinagmulan: www.habr.com

Bumili ng maaasahang pagho-host para sa mga site na may proteksyon ng DDoS, mga server ng VPS VDS 🔥 Bumili ng maaasahang website hosting na may proteksyon ng DDoS, VPS VDS servers | ProHoster