You are not logged in.

#1 2019-09-01 19:22:24

MilanKnizek
Member
Registered: 2005-12-13
Posts: 88

[SOLVED] Custom runtime hooks for systemd init

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

#2 2019-09-01 20:32:06

loqs
Member
Registered: 2014-03-06
Posts: 17,304

Re: [SOLVED] Custom runtime hooks for systemd init

MilanKnizek wrote:

Is it because systemd hook results in any custom runtime hook being ignored? (The mkinitcpio wiki page does not seem to suggest that.)

Yes.

MilanKnizek wrote:

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

#3 2019-09-02 19:55:35

MilanKnizek
Member
Registered: 2005-12-13
Posts: 88

Re: [SOLVED] Custom runtime hooks for systemd init

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

#4 2019-09-02 20:01:59

loqs
Member
Registered: 2014-03-06
Posts: 17,304

Re: [SOLVED] Custom runtime hooks for systemd init

Why would you need to remove the service file from /usr/lib/systemd/system ?

Offline

#5 2019-09-03 08:46:23

MilanKnizek
Member
Registered: 2005-12-13
Posts: 88

Re: [SOLVED] Custom runtime hooks for systemd init

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

#6 2019-09-05 05:00:19

MilanKnizek
Member
Registered: 2005-12-13
Posts: 88

Re: [SOLVED] Custom runtime hooks for systemd init

loqs wrote:

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

#7 2019-09-05 11:27:07

loqs
Member
Registered: 2014-03-06
Posts: 17,304

Re: [SOLVED] Custom runtime hooks for systemd init

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

#8 2019-09-05 21:08:18

MilanKnizek
Member
Registered: 2005-12-13
Posts: 88

Re: [SOLVED] Custom runtime hooks for systemd init

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

#9 2019-09-08 12:56:13

MilanKnizek
Member
Registered: 2005-12-13
Posts: 88

Re: [SOLVED] Custom runtime hooks for systemd init

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

Board footer

Powered by FluxBB