dracut + systemd + LUKS + usbflash = automatisk upplÄsning

Historien började lĂ€nge sedan, nĂ€r Centos 7 (RHEL 7) slĂ€pptes. Om du anvĂ€nde kryptering pĂ„ diskar med Centos 6, sĂ„ fanns det inga problem med automatisk upplĂ„sning av diskarna vid anslutning av en USB-flash-enhet med de rĂ€tta nycklarna. Men vid lanseringen av 7:an fungerade plötsligt allt inte som du var van vid. DĂ„ kunde lösningen hittas genom att Ă„tergĂ„ till dracut med sysvinit med hjĂ€lp av en enkel rad i konfigurationsfilen: echo ‘omit_dracutmodules+=" systemd "’ > /etc/dracut.conf.d/luks-workaround.conf
Detta berövade oss genast av alla fördelar med systemd — snabb och parallell start av systemtjĂ€nster, vilket avsevĂ€rt minskade systemets uppstartstid.
Det stÄr fortfarande stilla: 905683
Utan att vÀnta pÄ en lösning, gjorde jag en sjÀlv för mig sjÀlv och nu delar jag den med allmÀnheten, den som Àr intresserad, fortsÀtt lÀsa.
dracut + systemd + LUKS + usbflash = automatisk upplÄsning

Introduktion

Systemd, nĂ€r jag först började arbeta med Centos 7, vĂ€ckte ingen sĂ€rskild reaktion, dĂ„ jag utöver en liten förĂ€ndring i syntaxen för tjĂ€nsthantering inte kĂ€nde nĂ„gon större skillnad i början. Senare kom jag att gilla systemd, men första intrycket var nĂ„got förstört, eftersom utvecklarna av dracut inte la ner mycket tid pĂ„ att stödja bootprocessen med systemd i samband med disk-kryptering. Övergripande fungerade det, men att ange lösenordet för disken vid varje start servern — Ă€r inte den mest intressanta sysselsĂ€ttningen.
Efter att ha provat en massa rekommendationer och studerat manualen insĂ„g jag att det i systemd-lĂ€get var möjligt att konfigurera med USB, men endast genom en manuell koppling av varje disk med nyckeln pĂ„ USB-enheten, dessutom kunde sjĂ€lva USB-enheten endast kopplas via dess UUID, LABEL fungerade inte. Att hĂ„lla detta pĂ„ plats var inte sĂ„ praktiskt för mig, sĂ„ till slut hamnade jag i vĂ€ntan och efter nĂ€stan 7 Ă„r insĂ„g jag — ingen har för avsikt att lösa problemet.

Problem

SjÀlvklart kan nÀstan vem som helst skriva sin egen plugin till dracut, men att fÄ den att fungera Àr inte sÄ enkelt. Det visade sig att pÄ grund av systemds parallella natur Àr det inte sÄ lÀtt att aktivera sin egen kod och Àndra bootflödet. Dokumentationen för dracut förklarade lÄngt ifrÄn allt. Men genom lÄngvariga experiment lyckades jag lösa uppgiften.

Hur det fungerar

I grunden ligger tre enheter:

  1. luks-auto-key.service — söker efter lagringsenheter med nycklar för LUKS
  2. luks-auto.target — fungerar som ett beroende för inbyggda enheter av systemd-cryptsetup
  3. luks-auto-clean.service — raderar temporĂ€ra filer som skapats av luks-auto-key.service

luks-auto-generator.sh Àr ett skript som körs av systemd och genererar enheter baserat pÄ kÀrnparametrar. Liknande generatorer skapar enheter för fstab och sÄdana.

luks-auto-generator.sh

Genom drop-in.conf Àndras beteendet hos standard systemd-cryptsetup, vilket gör att det lÀgger till beroendet luks-auto.target.

luks-auto-key.service och luks-auto-key.sh

Den hÀr enheten kör skriptet luks-auto-key.sh, vilket, baserat pÄ nycklarna rd.luks.*, hittar enheter med nycklar och kopierar dem till en temporÀr katalog för vidare anvÀndning. Efter att processen Àr klar tar luks-auto-clean.service bort nycklarna frÄn den temporÀra katalogen.

KĂ€llkoder:

/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 nyckelsökare
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 mÄl
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 nyckelrensare
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/
# placera nÀstan alla filer hÀr
chmod +x /usr/lib/dracut/modules.d/99luks-auto/*.sh
# skapa filen /etc/dracut.conf.d/luks-auto.conf
# och generera ny initramfs
dracut -f

Slutsats

För bekvÀmlighetens skull har jag behÄllit kompatibiliteten med kÀrnans kommandoradsparameterer Àven för sysvinit-lÀget, vilket underlÀttar anvÀndningen i gamla installationer.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster