Câu chuyện bắt đầu từ rất lâu rồi, ngay từ khi nó được phát hành. Centos 7 (RHEL 7). Nếu bạn đã sử dụng mã hóa trên các ổ đĩa với Centos Ở phiên bản 6, không có vấn đề gì với việc tự động mở khóa ổ đĩa khi kết nối ổ USB flash có khóa chính xác. Tuy nhiên, với phiên bản 7 được phát hành, mọi thứ đột nhiên ngừng hoạt động như mong đợi. Một giải pháp đã được tìm thấy bằng cách chuyển dracut trở lại sysvinit bằng một dòng đơn giản trong tệp cấu hình: echo 'omit_dracutmodules+=" systemd "' > /etc/dracut.conf.d/luks-workaround.conf
Điều này ngay lập tức tước đi vẻ đẹp của systemd - khởi chạy nhanh và song song các dịch vụ hệ thống, giúp giảm đáng kể thời gian khởi động hệ thống.
Mọi thứ vẫn còn đó:
Không chờ giải pháp, tôi đã tự làm ra nó và bây giờ tôi chia sẻ nó với công chúng, những ai quan tâm, hãy đọc tiếp.

Giới thiệu
Systemd khi tôi mới bắt đầu làm việc với Centos Phiên bản 7 không gây ấn tượng gì đặc biệt, ngoài một thay đổi nhỏ về cú pháp quản lý dịch vụ, ban đầu tôi không nhận thấy nhiều khác biệt. Cuối cùng tôi cũng thích systemd, nhưng ấn tượng ban đầu của tôi hơi bị ảnh hưởng bởi việc các nhà phát triển dracut không dành nhiều thời gian hỗ trợ quá trình khởi động systemd kết hợp với mã hóa ổ đĩa. Nó hoạt động nhìn chung, nhưng tôi phải nhập mật khẩu ổ đĩa mỗi khi khởi động. người phục vụ — Không phải là hoạt động thú vị nhất.
Sau khi thử một loạt đề xuất và nghiên cứu hướng dẫn, tôi nhận ra rằng có thể cấu hình ở chế độ systemd với USB, nhưng chỉ khi liên kết thủ công từng đĩa với một phím trên đĩa USB và bản thân đĩa USB chỉ có thể được liên kết bằng chính nó. UUID, LABEL không hoạt động. Việc duy trì việc này ở nhà không thuận tiện lắm nên cuối cùng tôi lao vào chờ đợi và sau gần 7 năm chờ đợi, tôi nhận ra rằng sẽ không có ai giải quyết được vấn đề.
Vấn đề
Tất nhiên, hầu hết mọi người đều có thể viết plugin cho dracut của riêng mình, nhưng để nó hoạt động không còn dễ dàng nữa. Hóa ra do tính chất song song của quá trình khởi động systemd, việc đưa mã của bạn vào và thay đổi tiến trình tải không dễ dàng như vậy. Tài liệu về dracut không giải thích được mọi thứ. Tuy nhiên, sau nhiều thử nghiệm kéo dài, tôi đã có thể giải quyết được vấn đề.
Làm thế nào nó hoạt động
Nó dựa trên ba đơn vị:
- luks-auto-key.service - tìm kiếm ổ đĩa có khóa cho LUKS
- luks-auto.target - hoạt động như một phần phụ thuộc cho các đơn vị systemd-cryptsetup tích hợp
- luks-auto-clean.service - xóa các tệp tạm thời được tạo bởi luks-auto-key.service
Và luks-auto-generator.sh là một tập lệnh được systemd khởi chạy và tạo các đơn vị dựa trên các tham số kernel. Các trình tạo tương tự được tạo bởi các đơn vị fstab, v.v.
luks-auto-generator.sh
Sử dụng drop-in.conf, hành vi của systemd-cryptsetup tiêu chuẩn được thay đổi bằng cách thêm luks-auto.target vào phần phụ thuộc của chúng.
luks-auto-key.service và luks-auto-key.sh
Đơn vị này chạy tập lệnh luks-auto-key.sh, dựa trên các khóa rd.luks.*, tìm phương tiện bằng các khóa và sao chép chúng vào một thư mục tạm thời để sử dụng tiếp. Sau khi quá trình hoàn tất, các khóa sẽ bị luks-auto-clean.service xóa khỏi thư mục tạm thời.
Nguồn:
/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 "
Cài đặt
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
Kết luận
Để thuận tiện, tôi đã duy trì khả năng tương thích với các tùy chọn dòng lệnh kernel như đối với chế độ sysvinit, giúp sử dụng dễ dàng hơn trong các bản cài đặt cũ hơn.
Nguồn: www.habr.com
