dracut + systemd + LUKS + usbflash = automaattinen lukituksen avaus

Tarina alkoi kauan sitten, kun Centos 7 (RHEL 7) julkaistiin. Jos käytit salausta asemissa Centos 6:lla, asemien automaattisessa lukituksen avaamisessa ei ollut ongelmia, kun liitit USB-muistitikun tarvittavilla avaimilla. Kuitenkin, kun 7 julkaistiin, kaikki ei yhtäkkiä toiminut niin kuin olit tottunut. Sitten oli mahdollista löytää ratkaisu dracutin palauttamiseen sysvinitiin käyttämällä yksinkertaista riviä konfiguraatiossa: echo 'omit_dracutmodules+=" systemd "' > /etc/dracut.conf.d/luks-workaround.conf
Mikä riisti meiltä välittömästi kaiken systemd:n ​​kauneuden - järjestelmäpalvelujen nopean ja rinnakkaisen käynnistämisen, mikä lyhensi merkittävästi järjestelmän käynnistysaikaa.
Asiat ovat edelleen siellä: 905683
Ratkaisua odottamatta tein sen itselleni, ja nyt jaan sen yleisölle, jotka ovat kiinnostuneita, lukekaa.
dracut + systemd + LUKS + usbflash = automaattinen lukituksen avaus

Esittely

Systemd, kun aloitin työskentelyn Centos 7:n kanssa, ei aiheuttanut mitään tunteita, sillä palvelunhallinnan syntaksin pientä muutosta lukuun ottamatta en aluksi tuntenut suurta eroa. Myöhemmin pidin systemdistä, mutta ensivaikutelma oli hieman pilaantunut, koska dracut-kehittäjät eivät käyttäneet paljon aikaa käynnistysprosessin tukemiseen käyttämällä systemdiä yhdessä levysalauksen kanssa. Yleensä se toimi, mutta levysalasanan syöttäminen aina palvelimen käynnistyksen yhteydessä ei ole mielenkiintoisin asia.
Kokeiltuani joukkoa suosituksia ja tutkittuani käsikirjaa, tajusin, että systemd-tilassa konfigurointi USB:n avulla on mahdollista, mutta vain yhdistämällä jokainen levy manuaalisesti USB-levyllä olevaan avaimeen, ja itse USB-levy voidaan yhdistää vain sen avulla. UUID, LABEL ei toiminut. Ei ollut kovin kätevää ylläpitää tätä kotona, joten lopulta syöksyin odottamiseen ja melkein 7 vuoden odotuksen jälkeen tajusin, että kukaan ei aio ratkaista ongelmaa.

Ongelmat

Tietenkin melkein kuka tahansa voi kirjoittaa oman lisäosan dracutille, mutta sen saaminen toimimaan ei ole enää niin helppoa. Kävi ilmi, että systemd-käynnistyksen rinnakkaisluonteen vuoksi koodin sisällyttäminen ja latauksen etenemisen muuttaminen ei ole niin helppoa. Dracutin dokumentaatio ei selittänyt kaikkea. Pitkien kokeilujen jälkeen pystyin kuitenkin ratkaisemaan ongelman.

Kuinka se toimii

Se perustuu kolmeen yksikköön:

  1. luks-auto-key.service - etsii LUKSin avaimilla varustettuja asemia
  2. luks-auto.target - toimii riippuvuutena sisäänrakennetuille systemd-cryptsetup-yksiköille
  3. luks-auto-clean.service - puhdistaa luks-auto-key.service-palvelun luomat väliaikaiset tiedostot

Ja luks-auto-generator.sh on skripti, jonka systemd käynnistää ja joka luo yksiköitä ytimen parametrien perusteella. Samanlaisia ​​generaattoreita luovat fstab-yksiköt jne.

luks-auto-generator.sh

Käyttämällä drop-in.conf-tiedostoa, standardin systemd-cryptsetupin käyttäytymistä muutetaan lisäämällä luks-auto.target niiden riippuvuuteen.

luks-auto-key.service ja luks-auto-key.sh

Tämä yksikkö suorittaa luks-auto-key.sh-komentosarjan, joka rd.luks.*-avaimien perusteella löytää median avaimilla ja kopioi ne väliaikaiseen hakemistoon myöhempää käyttöä varten. Kun prosessi on valmis, luks-auto-clean.service poistaa avaimet väliaikaisesta hakemistosta.

Lähteet:

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

Asennus


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

Johtopäätös

Mukavuussyistä olen säilyttänyt yhteensopivuuden ytimen komentorivivalintojen kanssa kuten sysvinit-tilassa, mikä helpottaa käyttöä vanhemmissa asennuksissa.

Lähde: will.com

Lisää kommentti