Historien började lĂ€nge sedan, nĂ€r Centos 7 (RHEL 7) slĂ€pptes. Om du anvĂ€nde kryptering pĂ„ diskar med Centos 6, sĂ„ fanns det inga problem med automatisk upplĂ„sning av diskarna vid anslutning av en USB-flash-enhet med de rĂ€tta nycklarna. Men vid lanseringen av 7:an fungerade plötsligt allt inte som du var van vid. DĂ„ kunde lösningen hittas genom att Ă„tergĂ„ till dracut med sysvinit med hjĂ€lp av en enkel rad i konfigurationsfilen: echo âomit_dracutmodules+=" systemd "â > /etc/dracut.conf.d/luks-workaround.conf
Detta berövade oss genast av alla fördelar med systemd â snabb och parallell start av systemtjĂ€nster, vilket avsevĂ€rt minskade systemets uppstartstid.
Det stÄr fortfarande stilla:
Utan att vÀnta pÄ en lösning, gjorde jag en sjÀlv för mig sjÀlv och nu delar jag den med allmÀnheten, den som Àr intresserad, fortsÀtt lÀsa.

Introduktion
Systemd, nĂ€r jag först började arbeta med Centos 7, vĂ€ckte ingen sĂ€rskild reaktion, dĂ„ jag utöver en liten förĂ€ndring i syntaxen för tjĂ€nsthantering inte kĂ€nde nĂ„gon större skillnad i början. Senare kom jag att gilla systemd, men första intrycket var nĂ„got förstört, eftersom utvecklarna av dracut inte la ner mycket tid pĂ„ att stödja bootprocessen med systemd i samband med disk-kryptering. Ăvergripande fungerade det, men att ange lösenordet för disken vid varje start servern â Ă€r inte den mest intressanta sysselsĂ€ttningen.
Efter att ha provat en massa rekommendationer och studerat manualen insĂ„g jag att det i systemd-lĂ€get var möjligt att konfigurera med USB, men endast genom en manuell koppling av varje disk med nyckeln pĂ„ USB-enheten, dessutom kunde sjĂ€lva USB-enheten endast kopplas via dess UUID, LABEL fungerade inte. Att hĂ„lla detta pĂ„ plats var inte sĂ„ praktiskt för mig, sĂ„ till slut hamnade jag i vĂ€ntan och efter nĂ€stan 7 Ă„r insĂ„g jag â ingen har för avsikt att lösa problemet.
Problem
SjÀlvklart kan nÀstan vem som helst skriva sin egen plugin till dracut, men att fÄ den att fungera Àr inte sÄ enkelt. Det visade sig att pÄ grund av systemds parallella natur Àr det inte sÄ lÀtt att aktivera sin egen kod och Àndra bootflödet. Dokumentationen för dracut förklarade lÄngt ifrÄn allt. Men genom lÄngvariga experiment lyckades jag lösa uppgiften.
Hur det fungerar
I grunden ligger tre enheter:
- luks-auto-key.service â söker efter lagringsenheter med nycklar för LUKS
- luks-auto.target â fungerar som ett beroende för inbyggda enheter av systemd-cryptsetup
- luks-auto-clean.service â raderar temporĂ€ra filer som skapats av luks-auto-key.service
luks-auto-generator.sh Àr ett skript som körs av systemd och genererar enheter baserat pÄ kÀrnparametrar. Liknande generatorer skapar enheter för fstab och sÄdana.
luks-auto-generator.sh
Genom drop-in.conf Àndras beteendet hos standard systemd-cryptsetup, vilket gör att det lÀgger till beroendet luks-auto.target.
luks-auto-key.service och luks-auto-key.sh
Den hÀr enheten kör skriptet luks-auto-key.sh, vilket, baserat pÄ nycklarna rd.luks.*, hittar enheter med nycklar och kopierar dem till en temporÀr katalog för vidare anvÀndning. Efter att processen Àr klar tar luks-auto-clean.service bort nycklarna frÄn den temporÀra katalogen.
KĂ€llkoder:
/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 nyckelsökare
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Äl
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 nyckelrensare
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 "Installation
mkdir -p /usr/lib/dracut/modules.d/99luks-auto/
# placera nÀstan alla filer hÀr
chmod +x /usr/lib/dracut/modules.d/99luks-auto/*.sh
# skapa filen /etc/dracut.conf.d/luks-auto.conf
# och generera ny initramfs
dracut -f
Slutsats
För bekvÀmlighetens skull har jag behÄllit kompatibiliteten med kÀrnans kommandoradsparameterer Àven för sysvinit-lÀget, vilket underlÀttar anvÀndningen i gamla installationer.
KĂ€lla: habr.com
