dracut + systemd + LUKS + usbflash = déverrouillage automatique

L'histoire a commencĂ© il y a longtemps, lors de la sortie de Centos 7 (RHEL 7). Si vous avez utilisĂ© le chiffrement des disques avec Centos 6, il n'y avait aucun problĂšme de dĂ©verrouillage automatique des disques lors de la connexion d'une clĂ© USB avec les clĂ©s nĂ©cessaires. Cependant, avec la sortie de la version 7, tout a soudainement cessĂ© de fonctionner comme vous en aviez l'habitude. À ce moment-lĂ , on pouvait trouver une solution en revenant de dracut Ă  sysvinit grĂące Ă  une simple ligne dans le fichier de configuration : echo ‘omit_dracutmodules+=" systemd "’ > /etc/dracut.conf.d/luks-workaround.conf
Ce qui nous privait immĂ©diatement de toute la beautĂ© de systemd — le dĂ©marrage rapide et parallĂšle des services systĂšme, ce qui rĂ©duisait considĂ©rablement le temps de dĂ©marrage du systĂšme.
Et toujours rien : 905683
Ne sachant pas attendre une solution, je l'ai créée moi-mĂȘme et maintenant je la partage avec le public, pour ceux que cela intĂ©resse, lisez la suite.
dracut + systemd + LUKS + usbflash = déverrouillage automatique

Introduction

Systemd, quand j'ai commencĂ© Ă  travailler avec Centos 7, n'a suscitĂ© aucune Ă©motion, car mis Ă  part un changement mineur dans la syntaxe de gestion des services, je n'ai pas ressenti de diffĂ©rence particuliĂšre au dĂ©but. Par la suite, j'ai aimĂ© systemd, mais la premiĂšre impression a Ă©tĂ© un peu entachĂ©e, car les dĂ©veloppeurs de dracut ne consacraient pas beaucoup de temps au soutien du processus de dĂ©marrage avec systemd en conjonction avec le chiffrement des disques. En gĂ©nĂ©ral, cela fonctionnait, mais taper le mot de passe du disque Ă  chaque dĂ©marrage — ce n'est pas le faire le plus intĂ©ressant. de serveurs — ce n'est pas une occupation des plus passionnantes.
AprĂšs avoir essayĂ© une multitude de recommandations et avoir Ă©tudiĂ© le manuel, j'ai compris qu'en mode systemd, il Ă©tait possible de configurer avec USB, mais seulement en associant manuellement chaque disque Ă  la clĂ© sur la clĂ© USB, et que la clĂ© USB elle-mĂȘme ne pouvait ĂȘtre liĂ©e que par son UUID, l'Ă©tiquette (LABEL) ne fonctionnant pas. Maintenir cela chez moi n'Ă©tait pas trĂšs pratique, donc finalement je me suis plongĂ© dans l'attente et, aprĂšs avoir attendu prĂšs de 7 ans, j'ai compris — personne ne s'apprĂȘte Ă  rĂ©soudre le problĂšme.

ProblĂšmes

Bien sûr, presque tout le monde peut écrire son propre plugin pour dracut, mais en faire un qui fonctionne, c'est déjà moins simple. Il s'est avéré qu'en raison de la nature parallÚle du démarrage de systemd, inclure mon propre code et modifier le processus de démarrage n'est pas aussi facile. La documentation de dracut n'expliquait pas tout. Cependant, suite à de longues expériences, j'ai pu résoudre le problÚme.

Comment cela fonctionne

À la base, il y a trois unitĂ©s :

  1. luks-auto-key.service — recherche des supports avec des clĂ©s pour LUKS
  2. luks-auto.target — joue le rĂŽle de dĂ©pendance pour les unitĂ©s intĂ©grĂ©es de systemd-cryptsetup
  3. luks-auto-clean.service — nettoie les fichiers temporaires créés par luks-auto-key.service

luks-auto-generator.sh est un script qui s’exĂ©cute avec systemd et gĂ©nĂšre des unitĂ©s en fonction des paramĂštres du noyau. Des gĂ©nĂ©rateurs similaires crĂ©ent des unitĂ©s fstab, etc.

luks-auto-generator.sh

Avec drop-in.conf, le comportement par défaut de systemd-cryptsetup est modifié en ajoutant la dépendance à luks-auto.target.

luks-auto-key.service et luks-auto-key.sh

Cette unité exécute le script luks-auto-key.sh qui, basé sur les clés rd.luks.*, détecte les dispositifs contenant les clés et les copie dans un répertoire temporaire pour une utilisation future. AprÚs la fin du processus, les clés du répertoire temporaire sont supprimées par luks-auto-clean.service.

Sources :

/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=Rechercheur de clés AUTO LUKS
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=Cible AUTO LUKS
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=Nettoyeur de clés AUTO LUKS
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/
# On place ici presque tous les fichiers
chmod +x /usr/lib/dracut/modules.d/99luks-auto/*.sh
# On crée le fichier /etc/dracut.conf.d/luks-auto.conf
# Et on génÚre un nouvel initramfs
dracut -f

Conclusion

Pour plus de commodité, j'ai conservé la compatibilité avec les paramÚtres de ligne de commande du noyau comme pour le mode sysvinit, ce qui facilite l'utilisation dans les anciennes installations.

Source : habr.com

Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS đŸ”„ Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster