dracut + systemd + LUKS + usbflash = automātiskā atbloķēšana

Vēsture sākās sen, kad tika izlaists Centos 7 (RHEL 7). Ja jūs izmantojāt diskus šifrēšanai ar Centos 6, nebija nekādu problēmu ar diskus automātiski atbloķējot, pievienojot USB zibatmiņu ar nepieciešamajiem atslēgām. Tomēr, kad parādījās 7. versija, pēkšņi viss nedarbojās kā jūs bija pieraduši. Toreiz risinājumu varēja atrast, atgriežot dracut pie sysvinit, izmantojot vienkāršu rindu konfigurācijā: echo ‘omit_dracutmodules+=" systemd "’ > /etc/dracut.conf.d/luks-workaround.conf
Tas uzreiz atņēma mums visu systemd burvību — ātru un paralēlu sistēmas servisu palaišanu, kas ievērojami samazināja sistēmas palaišanas laiku.
Joprojām bez izmaiņām: 905683
Negaidot risinājumu, es izveidoju to pats un tagad dalos ar to ar sabiedrību, kam interesē, lasiet tālāk.
dracut + systemd + LUKS + usbflash = automātiskā atbloķēšana

Ievads

Systemd, kad es sāku strādāt ar Centos 7, neradīja nekādas emocijas, jo, izņemot nelielas izmaiņas servisu pārvaldības sintaksē, es sākumā nejustu īpašu atšķirību. Vēlāk man patika systemd, bet pirmais iespaids bija nedaudz sabojāts, jo dracut izstrādātāji nepievērsa lielu uzmanību atbalstam sistematizēšanas procesam ar systemd kopā ar diskus šifrēšanu. Kopumā tas darbojās, bet ikreiz ievadīt paroli no diska pie katras palaišanas serveris — nav visinteresantākais pasākums.
Pārbaudot daudz ieteikumu un izlasot rokasgrāmatu, es sapratu, ka, strādājot ar systemd, ir iespējama konfigurācija ar USB, bet tikai ar katra diska manuālu sasaistīšanu ar atslēgām USB zibatmiņā, turklāt pašu USB zibatmiņu var sasaistīt tikai pēc tās UUID, LABEL nestrādāja. Uzturēt tādu pieeju bija neērtāk, tāpēc galu galā es ieslīdēju gaidīšanā un, gaidot gandrīz 7 gadus, es sapratu — neviens nerunā par problēmas risināšanu.

Problēmas

Protams, uzrakstīt savu spraudni dracut var gandrīz ikviens, bet padarīt to darba kārtībā jau nav tik vienkārši. Izrādījās, ka, pateicoties systemd paralēljai palaišanas daba, bija grūti iekļaut savu kodu un mainīt palaišanas gaitu. Dokumentācija par dracut neskaidri paskaidroja visu. Tomēr pēc ilgstošiem eksperimentiem man izdevās atrisināt uzdevumu.

Kā tas darbojas

Pamats sastāv no trim vienībām:

  1. luks-auto-key.service — meklē LUKS atslēgu glabāšanas ierīces
  2. luks-auto.target — darbojas kā atkarības vienības sistematizēšanas dla systemd-cryptsetup
  3. luks-auto-clean.service — iznīcina pagaidu failus, ko izveidojis luks-auto-key.service

luks-auto-generator.sh ir skripts, kas tiek palaists ar systemd un ģenerē vienības, pamatojoties uz kodola parametriem. Līdzīgi ģeneratori veido fstab un tamlīdzīgas vienības.

luks-auto-generator.sh

Izmantojot drop-in.conf, tiek mainīta standarta systemd-cryptsetup uzvedība, pievienojot tiem atkarību luks-auto.target.

luks-auto-key.service un luks-auto-key.sh

Šī vienība palaidīs skriptu luks-auto-key.sh, kas, pamatojoties uz atslēgām rd.luks.*, atrod atslēgu nesējus un kopē tos pagaidu katalogā turpmākai izmantošanai. Pēc procesa pabeigšanas atslēgas no pagaidu kataloga tiks dzēstas ar luks-auto-clean.service.

Avoti:

/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 atslēgu meklētājs
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ērķis
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 atslēgu tīrītājs
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 "

Uzstādīšana


mkdir -p \/usr\/lib\/dracut\/modules.d\/99luks-auto\/\n# ievietojam te gandrīz visus failus
chmod +x \/usr\/lib\/dracut\/modules.d\/99luks-auto\/*.sh\n# izveidojam failu \/etc\/dracut.conf.d\/luks-auto.conf\n# un ģenerējam jauno initramfs
dracut -f

Secinājums

Lai atvieglotu lietošanu, es saglabāju saderību ar kodola komandrindas parametriem gan sysvinit režīmā, kas atvieglo izmantošanu vecajās instalācijās.

Avots: habr.com

Iegādājieties uzticamu tīmekļa hostingu ar DDoS aizsardzību, VPS VDS serveriem 🔥 Iegādājieties uzticamu tīmekļa hostingu ar DDoS aizsardzību, VPS VDS serveriem | ProHoster