You are not logged in.
Hi,
I am not able to get a custom hook 'tpm' to be run during init.
/etc/mkinitcpio.conf
...
HOOKS=(base systemd keyboard autodetect sd-vconsole modconf block tpm sd-encrypt sd-lvm2 filesystems fsck)
...
I need sd-encrypt for multiple luks devices. As per Wiki, use of sd-encrypt seems to require systemd hook as well.
The tpm hook gets copied to /hooks with `mkinitcpio -P` command. It is also listed in initramfs/config within HOOKS. However, it does not run at all during boot.
Is it because systemd hook results in any custom runtime hook being ignored? (The mkinitcpio wiki page does not seem to suggest that.)
If it is the case, any idea how to get the luks_key.bin from TPM NVRAM and save it to a file for sd-encrypt hook? I have not really found much info about how to write systemd run time hooks for initramfs...
P.S. On Debian based systems, one can use 'keyscript' parameter for crypttab to run a script which outputs the key for LUKS. This parameter is not supported on Arch Linux, though.
Last edited by MilanKnizek (2019-09-05 21:08:53)
--
Milan Knizek
http://knizek.net
Offline
Is it because systemd hook results in any custom runtime hook being ignored? (The mkinitcpio wiki page does not seem to suggest that.)
Yes.
If it is the case, any idea how to get the luks_key.bin from TPM NVRAM and save it to a file for sd-encrypt hook? I have not really found much info about how to write systemd run time hooks for initramfs...
When systemd is providing init you would need to use a service that would run before cryptsetup.target
Offline
What is the proper method of adding a systemd.service file to initramfs via install hooks (the systemd.service file would simply exec the runtime hook)?
As per /usr/lib/initcpio/install/systemd hook it seems I should use add_systemd_unit function, which takes care about dependencies. However, it looks for service files only in /usr/lib/systemd/system.
add_systemd_unit() {
# Add a systemd unit file to the initcpio image. Hard dependencies on binaries
# and other unit files will be discovered and added.
# $1: path to rules file (or name of rules file)
local unit= rule= entry= key= value= binary= dep=
unit=$(PATH=/usr/lib/systemd/system:/lib/systemd/system type -P "$1")
if [[ -z $unit ]]; then
# complain about not found unit file
return 1
fi
I do not think it is a good idea that my /etc/initcpio/install/tpm hook should a) create a service file in /usr/... b) run add_systemd_unit function, c) delete that file again...
P.S. I may eventually create an AUR package and put install and runtime hooks and tpm.service to /usr/lib, nevertheless I hope there is still a standard method via /etc/initcpio/hooks.
--
Milan Knizek
http://knizek.net
Offline
Why would you need to remove the service file from /usr/lib/systemd/system ?
Offline
I would actually prefer not to have to create a unit file manually in /usr/... That's why there is /etc/...
--
Milan Knizek
http://knizek.net
Offline
When systemd is providing init you would need to use a service that would run before cryptsetup.target
Reading systemd docs back and forth, but I cannot get it work.
[Unit]
Description=Get secret from TPM NVRAM
Wants=systemd-modules-load.service
After=systemd-modules-load.service
Before=cryptsetup.target
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/hooks/tpm run_hook
And it runs in parallel - actually, cryptsetup.target starts first, it detects LUKS partition, does not find the key file and asks for a password on console. Only then the tpm.service gets started and extracts the key (too late, though).
I tried also Before=local-fs-pre.target, but to no avail.
P.S. Currently, I do not use add_systemd_unit() mkinitcpio install function and instead, put the tpm.service directly to /usr/lib/systemd/system and create a symlink in sysinit.target.wants sub-dir. Not sure if this has an impact on unit starting order.
--
Milan Knizek
http://knizek.net
Offline
What if you change the symlink to be in the cryptsetup-pre.target.wants sub directory?
If that fails try removing systemd-modules-load.service dependency (which usually starts after cryptsetup.target) and use ExecStartPre to load the module directly.
Offline
Thanks for the hint about cryptsetup-pre.target. However, the 'RemainAfterExit=yes' made the real difference:
Excerpt of /etc/initcpio/install/tpm:
build() {
... cut on purpose ...
# This will copy runtime /etc/initcpio/hooks/tpm to $BUILDROOT/hooks/tpm
add_runscript
# However, with systemd based initramfs, this is ignored and must be executed
# via systemd.service file
cat >"$BUILDROOT/usr/lib/systemd/system/tpm.service" <<EOF
[Unit]
Description=Get secret from TPM NVRAM
Before=cryptsetup-pre.target
DefaultDependencies=no
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=/usr/bin/modprobe tpm_tis
ExecStart=/hooks/tpm run_hook
EOF
add_systemd_unit cryptsetup-pre.target
cd "$BUILDROOT/usr/lib/systemd/system/sysinit.target.wants"
ln -sf ../cryptsetup-pre.target cryptsetup-pre.target
ln -sf ../tpm.service tpm.service
}
That is, all symlinks are placed in std '/usr/lib/systemd/system/sysinit.target.wants' directory.
As per journalctl -b, the cryptsetup-pre.target waits for completion of the tpm.service unit now:
Sep 05 22:50:14 archlinux systemd[1]: Started Get secret from TPM NVRAM.
Sep 05 22:50:14 archlinux systemd[1]: Reached target Local Encrypted Volumes (Pre).
Sep 05 22:50:14 archlinux systemd[1]: Starting Cryptography Setup for cryptlvm...
Without 'RemainAfterExit=yes', cryptsetup-pre.target continued immediately after tpm.service was run and did not wait for the ExecStart process completion.
--
Milan Knizek
http://knizek.net
Offline
For those interested, I compiled the procedure for full system encryption (apart from /boot) with LUKS key retrieval from TPM 1.2 to a GitHub repo: https://github.com/archont00/arch-linux-luks-tpm-boot
--
Milan Knizek
http://knizek.net
Offline