dracut + systemd + LUKS + usbflash = آٹو انلاک

کہانی بہت پہلے شروع ہوئی تھی، جب Centos 7 (RHEL 7) ریلیز ہوئی تھی۔ اگر آپ سینٹوس 6 کے ساتھ ڈرائیوز پر انکرپشن استعمال کرتے ہیں، تو جب آپ نے ضروری کلیدوں کے ساتھ USB فلیش ڈرائیو کو منسلک کیا تو ڈرائیوز کو خودکار طور پر غیر مقفل کرنے میں کوئی مسئلہ نہیں تھا۔ تاہم، جب 7 کو ریلیز کیا گیا، اچانک سب کچھ اس طرح کام نہیں کیا جیسا کہ آپ کی عادت تھی۔ پھر ترتیب میں ایک سادہ لائن کا استعمال کرتے ہوئے dracut کو sysvinit میں واپس کرنے کا حل تلاش کرنا ممکن تھا: echo 'omit_dracutmodules+=" systemd"' > /etc/dracut.conf.d/luks-workaround.conf
جس نے ہمیں فوری طور پر سسٹمڈ کی تمام خوبصورتی سے محروم کر دیا - سسٹم سروسز کے تیز اور متوازی آغاز، جس سے سسٹم کے آغاز کے وقت میں نمایاں کمی واقع ہوئی۔
چیزیں اب بھی موجود ہیں: 905683
حل کا انتظار کیے بغیر، میں نے اسے اپنے لیے بنایا، اور اب میں اسے عوام کے ساتھ شیئر کر رہا ہوں، جو دلچسپی رکھتے ہیں، پڑھیں۔
dracut + systemd + LUKS + usbflash = آٹو انلاک

تعارف

Systemd، جب میں نے پہلی بار Centos 7 کے ساتھ کام کرنا شروع کیا، تو کوئی جذبات پیدا نہیں ہوا، کیونکہ سروس منیجمنٹ نحو میں معمولی تبدیلی کے علاوہ، میں نے شروع میں زیادہ فرق محسوس نہیں کیا۔ اس کے بعد، میں نے systemd کو پسند کیا، لیکن پہلا تاثر تھوڑا سا خراب ہو گیا، کیونکہ ڈراکٹ ڈویلپرز نے ڈسک انکرپشن کے ساتھ مل کر systemd کا استعمال کرتے ہوئے بوٹ کے عمل کو سپورٹ کرنے پر زیادہ وقت نہیں گزارا۔ عام طور پر، اس نے کام کیا، لیکن جب بھی سرور شروع ہوتا ہے ڈسک پاس ورڈ درج کرنا سب سے زیادہ دلچسپ چیز نہیں ہے۔
سفارشات کے ایک گروپ کو آزمانے اور دستی کا مطالعہ کرنے کے بعد، میں نے محسوس کیا کہ سسٹمڈ موڈ میں USB کے ساتھ کنفیگریشن ممکن ہے، لیکن صرف USB ڈسک پر ایک کلید کے ساتھ ہر ڈسک کی دستی ایسوسی ایشن کے ساتھ، اور USB ڈسک خود صرف اس کے ذریعے منسلک ہو سکتی ہے۔ UUID، LABEL نے کام نہیں کیا۔ گھر میں اسے برقرار رکھنا بہت آسان نہیں تھا، لہذا آخر میں میں انتظار میں ڈوب گیا اور، تقریبا 7 سال انتظار کرنے کے بعد، مجھے احساس ہوا کہ کوئی بھی مسئلہ حل کرنے والا نہیں ہے۔

مسائل

یقیناً، تقریباً کوئی بھی ڈراکٹ کے لیے اپنا پلگ ان لکھ سکتا ہے، لیکن اسے کام کرنا اب اتنا آسان نہیں رہا۔ پتہ چلا کہ سسٹمڈ اسٹارٹ اپ کی متوازی نوعیت کی وجہ سے، اپنے کوڈ کو شامل کرنا اور لوڈنگ کی پیشرفت کو تبدیل کرنا اتنا آسان نہیں ہے۔ ڈراکٹ کے لیے دستاویزات نے ہر چیز کی وضاحت نہیں کی۔ تاہم، طویل تجربات کے بعد، میں اس مسئلے کو حل کرنے میں کامیاب رہا۔

یہ کیسے کام کرتا ہے

یہ تین اکائیوں پر مبنی ہے:

  1. luks-auto-key.service - LUKS کے لیے چابیاں والی ڈرائیوز تلاش کرتا ہے۔
  2. luks-auto.target - بلٹ ان systemd-cryptsetup یونٹس کے لیے انحصار کے طور پر کام کرتا ہے
  3. luks-auto-clean.service - luks-auto-key.service کے ذریعے تخلیق کردہ عارضی فائلوں کو صاف کرتا ہے۔

اور luks-auto-generator.sh ایک اسکرپٹ ہے جو systemd کے ذریعے شروع کیا جاتا ہے اور کرنل پیرامیٹرز کی بنیاد پر یونٹس تیار کرتا ہے۔ اسی طرح کے جنریٹر fstab یونٹس وغیرہ کے ذریعہ بنائے گئے ہیں۔

luks-auto-generator.sh

drop-in.conf کا استعمال کرتے ہوئے، معیاری systemd-cryptsetup کے رویے کو ان کے انحصار میں luks-auto.target شامل کرکے تبدیل کیا جاتا ہے۔

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

یہ یونٹ luks-auto-key.sh اسکرپٹ چلاتا ہے، جو rd.luks.* کیز پر مبنی میڈیا کو چابیاں کے ساتھ ڈھونڈتا ہے اور مزید استعمال کے لیے انہیں ایک عارضی ڈائریکٹری میں کاپی کرتا ہے۔ عمل مکمل ہونے کے بعد، 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@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 "

تنصیب


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

حاصل يہ ہوا

سہولت کے لیے، میں نے کرنل کمانڈ لائن کے اختیارات کے ساتھ مطابقت برقرار رکھی ہے جیسا کہ sysvinit موڈ کے لیے ہے، جو پرانی تنصیبات میں استعمال کرنا آسان بناتا ہے۔

ماخذ: www.habr.com

نیا تبصرہ شامل کریں