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:
Negaidot risinājumu, es izveidoju to pats un tagad dalos ar to ar sabiedrību, kam interesē, lasiet tālāk.

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:
- luks-auto-key.service — meklē LUKS atslēgu glabāšanas ierīces
- luks-auto.target — darbojas kā atkarības vienības sistematizēšanas dla systemd-cryptsetup
- 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
