dracut + systemd + LUKS + usbflash = auto unlock

Ang kwento ay nagsimula nang matagal na ang nakalipas, noong ipinalabas ang Centos 7 (RHEL 7). Kung gumamit ka ng pag-encrypt sa mga drive na may Centos 6, walang mga problema sa awtomatikong pag-unlock ng mga drive kapag nagkonekta ka ng USB flash drive gamit ang mga kinakailangang key. Gayunpaman, noong inilabas ang 7, biglang hindi gumana ang lahat tulad ng nakasanayan mo. Pagkatapos ay posible na makahanap ng solusyon sa 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

Ang Systemd, noong una akong nagsimulang magtrabaho sa Centos 7, ay hindi nagdulot ng anumang mga emosyon, dahil bukod sa isang maliit na pagbabago sa syntax ng pamamahala ng serbisyo, wala akong masyadong naramdaman na pagkakaiba noong una. Kasunod nito, nagustuhan ko ang systemd, ngunit ang unang impression ay medyo nasisira, dahil ang mga developer ng dracut ay hindi gumugol ng maraming oras sa pagsuporta sa proseso ng boot gamit ang systemd kasabay ng pag-encrypt ng disk. Sa pangkalahatan, nagtrabaho ito, ngunit ang pagpasok ng password sa disk sa tuwing magsisimula ang server ay hindi ang pinaka-kagiliw-giliw na bagay.
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

Magdagdag ng komento