dracut + systemd + LUKS + usbflash = automatische Entsperrung

Die Geschichte begann vor langer Zeit, als CentOS 7 (RHEL 7) veröffentlicht wurde. Wenn Sie unter CentOS 6 Festplattenschutz verwendet haben, gab es keine Probleme mit der automatischen Entsperrung der Festplatten, wenn Sie einen USB-Stick mit den richtigen SchlĂŒsseln angeschlossen haben. Mit dem Erscheinen von Version 7 funktionierte jedoch plötzlich alles nicht mehr wie gewohnt. Die Lösung war, dracut durch sysvinit zurĂŒckzusetzen, indem man eine einfache Zeile in die Konfiguration einfĂŒgte: echo ‘omit_dracutmodules+=" systemd "’ > /etc/dracut.conf.d/luks-workaround.conf
Das nahm uns sofort den ganzen Vorteil von systemd – den schnellen und parallelen Start von Systemdiensten, was die Bootzeit erheblich verkĂŒrzte.
Und es ist nach wie vor so: 905683
Da ich auf eine Lösung wartete, habe ich selbst eine erstellt und teile sie nun mit der Öffentlichkeit. Wer interessiert ist, kann weiterlesen.
dracut + systemd + LUKS + usbflash = automatische Entsperrung

EinfĂŒhrung

Als ich anfing, mit CentOS 7 zu arbeiten, weckte Systemd zunĂ€chst keine besonderen Emotionen in mir. Abgesehen von geringfĂŒgigen Änderungen in der Handhabung der Dienste bemerkte ich anfangs keinen großen Unterschied. Im Laufe der Zeit fand ich systemd jedoch gut, obwohl der erste Eindruck leicht getrĂŒbt war, da die Entwickler von dracut nicht viel Zeit in die UnterstĂŒtzung des Bootprozesses mit systemd in Verbindung mit der VerschlĂŒsselung von Festplatten investiert hatten. Im Großen und Ganzen funktioniert es, aber jedes Mal beim Start das Passwort fĂŒr die Festplatte einzugeben, ist nicht gerade spannend. Server — ist nicht die interessanteste Aufgabe.
Nachdem ich viele Empfehlungen ausprobiert und das Handbuch studiert habe, erkannte ich, dass eine Konfiguration im systemd-Modus mit USB möglich ist, jedoch nur durch manuelle Zuordnung jeder Festplatte mit dem SchlĂŒssel auf dem USB-Stick. Zudem kann der USB-Stick nur ĂŒber seine UUID verbunden werden, LABEL funktionierte nicht. So etwas bei mir zu unterstĂŒtzen, war nicht besonders praktisch, also tauchte ich schließlich in Geduld ein und wartete fast 7 Jahre, bis ich verstand — niemand plant, das Problem zu lösen.

Die Probleme

NatĂŒrlich kann fast jeder ein eigenes Plugin fĂŒr dracut schreiben, aber es ist nicht so einfach, es funktionsfĂ€hig zu machen. Es stellte sich heraus, dass aufgrund der parallelen Natur des Systemstarts mit systemd die Integration des eigenen Codes und die Änderung des Bootvorgangs alles andere als leicht ist. Die Dokumentation zu dracut erklĂ€rte bei weitem nicht alles. Nach langwierigen Experimenten konnte ich jedoch die Herausforderung meistern.

Wie es funktioniert

Im Kern stehen drei Einheiten:

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

Und luks-auto-generator.sh — ein Skript, das von systemd ausgefĂŒhrt wird und Einheiten basierend auf den Kernel-Parametern generiert. Ähnliche Generatoren erstellen fstab-Einheiten usw.

luks-auto-generator.sh

Mit Hilfe von drop-in.conf wird das Verhalten der Standard-systemd-cryptsetup-Einheiten 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 Speichermedien mit SchlĂŒsseln findet und sie in ein temporĂ€res Verzeichnis kopiert, um sie spĂ€ter zu verwenden. Nach Abschluss des Prozesses entfernt luks-auto-clean.service die SchlĂŒssel aus dem temporĂ€ren Verzeichnis.

Quelltexte:

/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-Sucher
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ĂŒssel-Reiniger
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 von


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

Fazit

Zur Vereinfachung habe ich die KompatibilitĂ€t mit den Befehlszeilenparametern des Kernels sowohl fĂŒr den sysvinit-Modus als auch fĂŒr die Nutzung in Ă€lteren Installationen beibehalten.

Quelle: habr.com

ZuverlĂ€ssiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen đŸ”„ ZuverlĂ€ssiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen | ProHoster