dracut + systemd + LUKS + usbflash = otomatik kilit açma

Hikaye çok uzun zaman önce, filmin gösterime girdiği zamanlarda başladı. Centos 7 (RHEL 7). Disklerde şifreleme kullandıysanız Centos 6. sürümde, doğru anahtarlarla bir USB flash sürücü bağlandığında disklerin otomatik olarak kilidinin açılmasında hiçbir sorun yoktu. Ancak, 7. sürümün yayınlanmasıyla birlikte her şey aniden beklendiği gibi çalışmayı durdurdu. Çözüm, yapılandırma dosyasında basit bir satır kullanarak dracut'u sysvinit'e geri döndürmek oldu: echo 'omit_dracutmodules+=" systemd "' > /etc/dracut.conf.d/luks-workaround.conf
Bu bizi hemen systemd'nin tüm güzelliğinden mahrum etti - sistem hizmetlerinin hızlı ve paralel başlatılması, bu da sistem başlatma süresini önemli ölçüde azalttı.
Şeyler hala orada: 905683
Çözüm beklemeden kendim yaptım, şimdi de kamuoyuyla paylaşıyorum, ilgilenenler okusun.
dracut + systemd + LUKS + usbflash = otomatik kilit açma

Giriş

Systemd ile ilk çalışmaya başladığımda... Centos 7. sürüm beni pek heyecanlandırmadı, çünkü hizmet yönetimi sözdiziminde küçük bir değişiklik dışında ilk başta pek bir fark görmedim. Sonunda systemd'yi sevmeye başladım, ancak ilk izlenimim, dracut geliştiricilerinin disk şifrelemesiyle birlikte systemd önyükleme sürecini desteklemek için fazla zaman harcamamış olmaları gerçeğiyle biraz gölgelendi. Genel olarak çalışıyordu, ancak her başlattığımda disk şifremi girmek zorunda kalıyordum. sunucu — en ilgi çekici aktivite değil.
Bir dizi öneriyi denedikten ve kılavuzu inceledikten sonra, sistemd modunda USB ile yapılandırmanın mümkün olduğunu, ancak yalnızca her diskin bir USB diskteki bir anahtarla manuel olarak ilişkilendirilmesiyle ve USB diskin kendisinin yalnızca onunla ilişkilendirilebileceğini fark ettim. UUID, LABEL çalışmadı. Bunu evde sürdürmek pek uygun değildi, ben de sonunda beklemeye başladım ve neredeyse 7 yıl bekledikten sonra kimsenin sorunu çözemeyeceğini anladım.

Sorunları

Elbette hemen hemen herkes dracut için kendi eklentisini yazabilir, ancak onu çalıştırmak artık o kadar kolay değil. Systemd başlatmanın paralel doğası nedeniyle kodunuzu eklemenin ve yükleme ilerlemesini değiştirmenin o kadar kolay olmadığı ortaya çıktı. Dracut'ın belgeleri her şeyi açıklamıyordu. Ancak uzun denemelerden sonra sorunu çözmeyi başardım.

O nasıl çalışır

Üç birime dayanmaktadır:

  1. luks-auto-key.service - LUKS anahtarlarına sahip sürücüleri arar
  2. luks-auto.target - yerleşik systemd-cryptsetup birimlerine bağımlılık görevi görür
  3. luks-auto-clean.service - luks-auto-key.service tarafından oluşturulan geçici dosyaları temizler

Ve luks-auto-generator.sh, systemd tarafından başlatılan ve çekirdek parametrelerine dayalı birimler üreten bir komut dosyasıdır. Benzer jeneratörler fstab birimleri vb. tarafından oluşturulur.

luks-auto-generator.sh

Drop-in.conf kullanılarak standart systemd-cryptsetup'ın davranışı, bağımlılıklarına luks-auto.target eklenerek değiştirilir.

luks-auto-key.service ve luks-auto-key.sh

Bu birim, rd.luks.* anahtarlarını temel alarak anahtarların bulunduğu ortamı bulan ve bunları daha sonra kullanılmak üzere geçici bir dizine kopyalayan luks-auto-key.sh komut dosyasını çalıştırır. İşlem tamamlandıktan sonra anahtarlar luks-auto-clean.service tarafından geçici dizinden silinir.

Kaynaklar:

/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 key searcher
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 target
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 key cleaner
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 "

Montaj


mkdir -p /usr/lib/dracut/modules.d/99luks-auto/
# размещаем тут почти все файлы
chmod +x /usr/lib/dracut/modules.d/99luks-auto/*.sh
# создаем файл /etc/dracut.conf.d/luks-auto.conf
# И генерируем новый initramfs
dracut -f

Sonuç

Kolaylık sağlamak için, eski kurulumlarda kullanımı kolaylaştıran sysvinit modu gibi çekirdek komut satırı seçenekleriyle uyumluluğu korudum.

Kaynak: habr.com

DDoS korumalı siteler, VPS VDS sunucuları için güvenilir hosting satın alın 🔥 DDoS korumalı, güvenilir VPS ve VDS sunucu barındırma hizmeti satın alın | ProHoster