dracut + systemd + LUKS + usbflash = فتح تلقائي

بدأت القصة منذ وقت طويل ، مع إصدار Centos 7 (RHEL 7). إذا كنت تستخدم التشفير على الأقراص باستخدام Centos 6 ، فلن تكون هناك مشاكل في إلغاء القفل التلقائي للأقراص عند توصيل محرك أقراص USB محمول بالمفاتيح الضرورية. ومع ذلك ، مع إصدار 7-ki فجأة لم يعمل كل شيء كما اعتدت. ثم كان من الممكن إيجاد حل في إعادة dracut إلى sysvinit باستخدام خط غير معقد في التكوين: echo 'omit_dracutmodules + = "systemd"'> /etc/dracut.conf.d/luks-workaround.conf

الذي حرمنا على الفور من كل سحر systemd - سريع و إطلاق مواز لخدمات النظام ، مما قلل بشكل كبير من وقت بدء تشغيل النظام. الأمور لا تزال قائمة

: 905683

دون انتظار الحل ، صنعته لنفسي ، والآن أشاركه مع الجمهور المهتم ، تابع القراءة.



المقدمة


Systemd ، عندما بدأت العمل مع Centos 7 لأول مرة ، لم يسبب أي عواطف ، لأنه بالإضافة إلى تغيير طفيف في بنية إدارة الخدمة ، لم أشعر بأي فرق كبير في البداية. في وقت لاحق ، أحببت systemd ، ولكن الانطباع الأول كان مدللًا قليلاً ، حيث لم يكرس مطورو dracut الوقت بشكل خاص لدعم عملية التمهيد باستخدام systemd مع تشفير القرص. بشكل عام ، نجحت ، ولكن إدخال كلمة المرور من القرص في كل بداية للخادم ليس النشاط الأكثر إثارة للاهتمام.

بعد اختبار مجموعة من التوصيات ومراعاة الدليل ، أدركت أنه في وضع systemd ، يمكن إجراء تكوين باستخدام USB ، ولكن فقط مع الارتباط اليدوي لكل محرك أقراص بمفتاح على محرك أقراص USB ، ولا يمكن توصيل محرك أقراص USB نفسه إلا من خلال UUID ، لم يعمل LABEL. لم يكن الحفاظ على هذا في المنزل مناسبًا جدًا ، لذلك في النهاية وقعت في توقع ، وبعد أن انتظرت لما يقرب من 7 سنوات ، أدركت أنه لن يتمكن أحد من حل المشكلة.

مشاكل


بالطبع ، يمكن للجميع تقريبًا كتابة مكون إضافي خاص بهم لـ dracut ، ولكن جعله يعمل ليس بهذه البساطة. اتضح أنه نظرًا للطبيعة المتوازية لتشغيل النظام ، ليس من السهل جدًا تضمين التعليمات البرمجية وتغيير تقدم التنزيل. وثائق dracut لم تفسر كل شيء. ومع ذلك ، وبسبب التجارب الطويلة ، تمكنت من حل المشكلة.

كيف يعمل


يقوم على ثلاث وحدات:

  1. luks-auto-key.service - يبحث عن محركات الأقراص الرئيسية لـ LUKS
  2. luks-auto.target - بمثابة تبعية للوحدات المضمنة في cryptsetup
  3. luks-auto-clean.service - ينظف الملفات المؤقتة التي تم إنشاؤها بواسطة luks-auto-key.service

و luks-auto-generator.sh هو برنامج نصي يتم تشغيله بواسطة systemd ويقوم بإنشاء وحدات بناءً على معلمات kernel. تقوم المولدات المماثلة بإنشاء وحدات fstab وما إلى ذلك.

luks-auto-generator.sh


باستخدام drop-in.conf ، يتم تغيير سلوك systemd-cryptsetetups القياسي عن طريق إضافة luks-auto.target إليها.

luks-auto-key.service و luks-auto-key.sh


تقوم هذه الوحدة بتشغيل البرنامج النصي luks-auto-key.sh ، والذي يقوم ، استنادًا إلى rd.luks. * Keys ، بالبحث عن الوسائط باستخدام المفاتيح ونسخها إلى دليل مؤقت للاستخدام المستقبلي. بعد اكتمال العملية ، تقوم luks-auto-clean.service بحذف المفاتيح من الدليل المؤقت.

مصادر:


/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@luks\x2d${_UUID_ESC}.service.d"
	cat > "${SYSTEMD_RUN}/systemd-cryptsetup@luks\x2d${_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-by\x2duuid-${_UUID_ESC}.device
After=dev-disk-by\x2duuid-${_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 "


التركيب

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


استنتاج


من أجل الراحة ، احتفظت بالتوافق مع معلمات سطر الأوامر kernel كما هو الحال في وضع sysvinit ، مما يسهل الاستخدام في عمليات التثبيت القديمة.

All Articles