dracut + systemd + LUKS + usbflash = automatische Entsperrung

Die Geschichte begann schon lange, nĂ€mlich mit der Veröffentlichung von Centos 7 (RHEL 7). Wenn Sie die FestplattenverschlĂŒsselung mit Centos 6 verwendet haben, gab es keine Probleme mit der automatischen Entsperrung der Festplatten beim Anschließen eines USB-Sticks mit den benötigten SchlĂŒsseln. Mit der Veröffentlichung von 7 hingegen funktionierte plötzlich alles nicht mehr so, wie Sie es gewohnt waren. Damals konnte man die Lösung finden, indem man dracut mit sysvinit zurĂŒcksetzte, mit einer einfachen Zeile im Konfigurationsfile: echo 'omit_dracutmodules+=" systemd "' > /etc/dracut.conf.d/luks-workaround.conf
Das hat uns sofort den ganzen Reiz von systemd genommen — den schnellen und parallelen Start von Systemdiensten, was die Bootzeit des Systems erheblich verkĂŒrzt hat.
Die Situation ist nach wie vor dieselbe: 905683
Ohne auf eine Lösung zu warten, habe ich sie selbst entwickelt und teile sie nun mit der Öffentlichkeit; wer interessiert ist, kann weiterlesen.
dracut + systemd + LUKS + usbflash = automatische Entsperrung

EinfĂŒhrung

Systemd hat bei mir, als ich anfing, mit Centos 7 zu arbeiten, keine besonderen Emotionen ausgelöst, da ich anfangs außer einer geringfĂŒgigen Änderung in der Syntax der Dienstverwaltung keine wesentlichen Unterschiede wahrgenommen habe. SpĂ€ter gefiel mir systemd, aber der erste Eindruck war ein wenig getrĂŒbt, da die Entwickler von dracut nicht viel Zeit mit der UnterstĂŒtzung des Bootprozesses mit systemd in Verbindung mit FestplattenverschlĂŒsselung verbrachten. Insgesamt funktionierte es, aber bei jedem Start das Passwort fĂŒr die Festplatte einzugeben, Server ist nicht die spannendste Aufgabe.
Nachdem ich viele Empfehlungen ausprobiert und das Handbuch studiert hatte, erkannte ich, dass eine Konfiguration im systemd-Modus mit USB möglich ist, aber nur durch manuelle Zuordnung jeder Festplatte mit dem SchlĂŒssel auf dem USB-Stick; der USB-Stick selbst konnte nur ĂŒber seine UUID zugeordnet werden, LABEL funktionierte nicht. Solch eine Lösung zu unterstĂŒtzen war nicht sehr praktisch, also habe ich letztendlich abgewartet und nach fast 7 Jahren festgestellt, dass niemand beabsichtigt, das Problem zu lösen.

Probleme

NatĂŒrlich kann fast jeder ein eigenes Plugin fĂŒr dracut schreiben, aber es zu einem funktionierenden zu machen, ist nicht so einfach. Es stellte sich heraus, dass die parallele Natur des Systemd-Starts das Einschalten meines Codes und die Änderung des Bootvorgangs nicht so einfach machte. Die Dokumentation zu dracut erklĂ€rte bei weitem nicht alles. Doch nach langen Versuchen konnte ich das Problem lösen.

Wie es funktioniert

Es basieren auf drei Einheiten:

  1. luks-auto-key.service — sucht nach Laufwerken mit SchlĂŒsseln fĂŒr LUKS
  2. luks-auto.target — fungiert als AbhĂ€ngigkeit fĂŒr die integrierten Einheiten systemd-cryptsetup
  3. luks-auto-clean.service — löscht temporĂ€re Dateien, die von luks-auto-key.service erstellt wurden

luks-auto-generator.sh ist ein Skript, das von systemd gestartet wird und Einheiten basierend auf den Kernelparametern generiert. Ähnliche Generatoren erstellen fstab-Einheiten usw.

luks-auto-generator.sh

Mit drop-in.conf wird das Verhalten der Standard-dystemd-cryptsetup geĂ€ndert, indem luks-auto.target als AbhĂ€ngigkeit hinzugefĂŒgt wird.

luks-auto-key.service und luks-auto-key.sh

Diese Einheit startet das Skript luks-auto-key.sh, das basierend auf den SchlĂŒsseln rd.luks.* die Speicher mit SchlĂŒsseln findet und sie in ein temporĂ€res Verzeichnis kopiert, um sie weiter zu verwenden. Nach Abschluss des Prozesses werden die SchlĂŒssel vom temporĂ€ren Verzeichnis von luks-auto-clean.service gelöscht.

Quellcodes:

/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 SchlĂŒssel-Suchdienst
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 Ziel
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 SchlĂŒsselreiniger
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 "

Installation


mkdir -p \/usr\/lib\/dracut\/modules.d\/99luks-auto\/\n# fast alle Dateien hier ablegen\nchmod +x \/usr\/lib\/dracut\/modules.d\/99luks-auto\/*.sh\n# Datei \/etc\/dracut.conf.d\/luks-auto.conf erstellen\n# Und neues initramfs generieren\ndracut -f

Fazit

Zu Ihrem Komfort habe ich die KompatibilitĂ€t mit den Kernel-Befehlszeilenparametern fĂŒr den sysvinit-Modus beibehalten, was die Verwendung bei Ă€lteren Installationen erleichtert.

Quelle: habr.com

ZuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz kaufen, VPS VDS Server đŸ”„ ZuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz kaufen, VPS VDS Server - ProHoster