dracut + systemd + LUKS + usbflash = auto-sblocco

La storia è iniziata tanto tempo fa, ancora con il rilascio di Centos 7 (RHEL 7). Se hai utilizzato la crittografia sui dischi con Centos 6, non c'erano problemi con lo sblocco automatico dei dischi collegando una chiavetta USB con le chiavi necessarie. Tuttavia, con il rilascio della versione 7, all'improvviso tutto non funzionava come eri abituato. Allora era possibile trovare una soluzione tornando a dracut utilizzando sysvinit con una semplice riga di codice nel file di configurazione: echo ‘omit_dracutmodules+=" systemd "’ > /etc/dracut.conf.d/luks-workaround.conf
Ciò ci privava immediatamente di tutto il fascino di systemd: l'avvio rapido e parallelo dei servizi di sistema, che riduceva notevolmente il tempo di avvio del sistema.
E così siamo rimasti: 905683
Non aspettando una soluzione, l'ho creata da solo e ora la condivido con il pubblico, chi è interessato legga oltre.
dracut + systemd + LUKS + usbflash = auto-sblocco

Introduzione

Systemd, quando ho iniziato a lavorare con Centos 7, non suscitò alcuna emozione, poiché a parte una lieve modifica della sintassi per la gestione dei servizi, non sentii inizialmente differenze significative. In seguito mi piacque systemd, ma la prima impressione fu un po' offuscata, poiché gli sviluppatori di dracut non dedicavano molto tempo al supporto del processo di avvio con systemd insieme alla crittografia dei dischi. In generale funzionava, ma dover inserire la password del disco ad ogni avvio server non è esattamente un'attività interessante.
Dopo aver provato una miriade di raccomandazioni e studiato il manuale, ho capito che in modalità systemd era possibile configurare l'USB, ma solo associando manualmente ogni disco alla chiave nella chiavetta USB, e la chiavetta USB poteva essere collegata solo tramite il suo UUID, l'LABEL non funzionava. Mantenere una configurazione del genere non era molto comodo, quindi alla fine ho vissuto in attesa e, dopo quasi 7 anni, ho capito che nessuno intendeva risolvere il problema.

Problemi

Certo, scrivere il proprio plugin per dracut può farlo quasi chiunque, ma renderlo funzionante non è affatto semplice. Si è rivelato che a causa della natura parallela dell'avvio di systemd, integrare il proprio codice e modificare il processo di avvio non è affatto facile. La documentazione di dracut non chiariva tutto. Tuttavia, a seguito di lunghi esperimenti, sono riuscito a risolvere il problema.

Come funziona

Al centro ci sono tre unità:

  1. luks-auto-key.service — ricerca dispositivi con chiavi per LUKS
  2. luks-auto.target — funge da dipendenza per le unità integrate systemd-cryptsetup
  3. luks-auto-clean.service — pulisce i file temporanei creati da luks-auto-key.service

Il luks-auto-generator.sh è uno script che viene eseguito da systemd e genera unità basate sui parametri del kernel. Generatori analoghi creano unità fstab e simili.

luks-auto-generator.sh

Con drop-in.conf si modifica il comportamento degli standard systemd-cryptsetup, aggiungendo come dipendenza luks-auto.target.

luks-auto-key.service e luks-auto-key.sh

Questa unità esegue lo script luks-auto-key.sh, che, basandosi sulle chiavi rd.luks.*, trova i supporti con le chiavi e li copia in una directory temporanea per un utilizzo successivo. Al termine del processo, le chiavi vengono rimosse dalla directory temporanea da luks-auto-clean.service.

Sorgenti:

/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=Ricercatore di chiavi LUKS AUTO
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=Obiettivo LUKS AUTO
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=Pulisci chiavi LUKS AUTO
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 "

Installazione


mkdir -p \/usr\/lib\/dracut\/modules.d\/99luks-auto\/\n# posizioniamo qui quasi tutti i file
chmod +x \/usr\/lib\/dracut\/modules.d\/99luks-auto\/*.sh\n# creiamo il file \/etc\/dracut.conf.d\/luks-auto.conf\n# E generiamo un nuovo initramfs
dracut -f

Conclusione

Per comodità ho mantenuto la compatibilità con i parametri della riga di comando del kernel per la modalità sysvinit, facilitando l'uso nelle installazioni più vecchie.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster