2 TPM2 assisted ZFS root unlock
Luchesar ILIEV via Kerberiel edited this page 2026-09-11 22:16:31 +03:00

Native-encrypted ZFS roots can use the standard ZFS key-loading methods, including interactive passphrase prompts and key files.

ArchZFS also provides an optional TPM2-assisted key provider for systems that need unattended restarts. The provider uses systemd-creds(1) to recover the key needed by the boot root dataset's encryption root before the normal ZFS key-loading path runs.

The provider is disabled by default. Installing ArchZFS does not automatically place a ZFS key in the TPM, add a credential to the initramfs, or change the normal passphrase behavior.

Important

This page assumes that the system already boots successfully from its native-encrypted ZFS root using the normal key-loading path. Configure and test ordinary root-on-ZFS boot before adding unattended unlock.

How It Works

The ArchZFS mkinitcpio hook can invoke optional key-provider scripts before falling back to its normal zfs load-key behavior.

The packaged TPM2 example:

  1. Runs only for the encryption root needed by the boot root dataset.

  2. Uses systemd-creds to decrypt a credential through the TPM.

  3. Pipes the recovered key to:

    zfs load-key -L prompt "${ENCRYPTIONROOT}"
    
  4. Returns to the normal key-loading path if decryption or key loading fails.

Provider execution is isolated from the BusyBox /init process. A provider failure is non-fatal, but a machine without an accessible console or another recovery path may still become unreachable when manual input is required.

Datasets with independent encryption roots are not unlocked by the packaged provider. Datasets inheriting the same encryption root as the boot root may become available when that shared root key is loaded.

Requirements

Before enabling the provider, confirm that:

  • zfs-utils 2.4.4-3 or later is installed. The provider first appeared in 2.4.4-3; earlier packages do not contain or load it.
  • The system uses native ZFS encryption for its root dataset.
  • The existing root-on-ZFS configuration boots correctly with a passphrase or other standard key-loading method.
  • HOOKS in /etc/mkinitcpio.conf uses the normal BusyBox zfs hook and does not contain mkinitcpio's systemd hook. In a systemd-based initramfs, the ArchZFS ZFS runtime hook and its providers do not run.
  • A suitable TPM2 device is available.
  • The original ZFS passphrase is preserved through a secure recovery method.
  • Local console access or another tested recovery path is available for the first boot.

A useful diagnostic on the running system is:

systemd-analyze has-tpm2

systemd-analyze(1) reports firmware, kernel-driver, system, and userspace-library support. Its output depends on the complete system configuration; the actual credential encryption and decryption operations remain the decisive test.

The relevant ZFS properties can be inspected with a command such as:

zfs get encryption,encryptionroot,keyformat,keylocation tank/root

Replace tank/root with the actual root dataset.

The credential recipe below is intended for keyformat=passphrase. Encryption roots using hex or raw require the credential to contain the exact key material in the configured format and are outside this example.

Install the TPM Support

Perform a full system upgrade and install the optional TPM userspace dependency:

pacman -Syu tpm2-tss

Review the instructions shipped by the installed zfs-utils package:

mkinitcpio -H zfs

The package-matched help is authoritative if it differs from this Wiki page.

Enable the Provider

Install the packaged example under /etc/zfs:

install -Dm644 \
    /usr/share/doc/zfs-utils/initramfs-tools-load-key.d/tpm2-systemd-creds \
    /etc/zfs/initramfs-tools-load-key.d/tpm2-systemd-creds

Merely installing zfs-utils or tpm2-tss does not enable the provider. It becomes active only when this file is present while the initramfs is built.

Keep the destination filename exactly tpm2-systemd-creds. Provider files with other names are still sourced, but the ZFS install hook adds systemd-creds, TPM modules, and TSS libraries only when this exact filename is present. A renamed or number-prefixed copy will therefore fall back to normal key loading without the required TPM payload.

Create the Credential

Run the following in a root shell. It obtains the existing ZFS passphrase without placing it directly in shell history and pipes it into systemd-creds, so the plaintext is never written to a file:

umask 077
systemd-ask-password -n "ZFS passphrase:" |
    systemd-creds encrypt --with-key=tpm2 --tpm2-device=auto \
        --name=zfs-key - /etc/zfs/zfs-key.creds &&
    chmod 600 /etc/zfs/zfs-key.creds

The -n option suppresses the trailing newline that systemd-ask-password would otherwise append. --name=zfs-key embeds the name expected by the provider; without it, systemd-creds derives the different name zfs-key.creds from the output filename. Resolve any error before continuing.

The default credential path is:

/etc/zfs/zfs-key.creds

The default systemd-creds credential name is:

zfs-key

Treat the encrypted credential as sensitive configuration even though it cannot normally be decrypted without the associated TPM state.

Verify the Credential

Before rebuilding the initramfs, confirm that the credential decrypts and contains the correct ZFS key. The zfs load-key -n dry run does not change pool state and works even when the key is already loaded:

root_dataset=tank/root
encryption_root=$(zfs get -H -o value encryptionroot "${root_dataset}") &&
    test "${encryption_root}" != "-" &&
    systemd-creds decrypt --name=zfs-key /etc/zfs/zfs-key.creds - |
        zfs load-key -n -L prompt "${encryption_root}"

Replace tank/root with the actual boot root dataset. A failure means that the credential, its embedded name, the captured key, or the current TPM state is wrong. Fix it before rebuilding the initramfs. This check does not replace a real reboot test because it does not exercise the early-boot environment.

Add the Credential to the Initramfs

Add the credential to the FILES array in /etc/mkinitcpio.conf. Either add it to the existing assignment or append it below the existing FILES=() line:

FILES+=(/etc/zfs/zfs-key.creds)

Do not put this append before a later FILES=() assignment, which would discard it. The credential is never added automatically by the ZFS hook.

Keep zfs in the HOOKS array. Do not add a separate TPM hook or mkinitcpio's systemd hook for this provider.

Rebuild the initramfs:

mkinitcpio -P

Review the complete output and resolve any missing-file, missing-library, or module errors before rebooting.

If a path listed in FILES is missing, mkinitcpio reports an error and exits non-zero but may still write or replace an incomplete image. Do not delete the credential while it remains in FILES, and do not ignore failures from manual or automatic initramfs rebuilds: the resulting image may lose unattended unlock.

Inspect the Result

List the relevant contents of the image, for example:

lsinitcpio -l /boot/initramfs-linux.img |
    grep -E 'tpm2-systemd-creds|zfs-key\.creds|systemd-creds|libtss2'

Use the actual image path for the installed kernel.

A provider-enabled image should contain entries for:

etc/zfs/initramfs-tools-load-key.d/tpm2-systemd-creds
etc/zfs/zfs-key.creds
usr/bin/systemd-creds

lsinitcpio -l displays paths without a leading slash. The image should also contain the required libtss2 libraries and their dependencies. Applicable TPM drivers may be included as modules or built directly into the kernel.

The credential reaches the image only through the FILES array. Without an enabled provider, the ArchZFS hook does not add the provider, systemd-creds, or provider-specific TSS payload merely because the package is installed. Other configured mkinitcpio hooks may have their own payload requirements.

Test Before Relying on It

Perform the first boot with working console access.

Verify that:

  • The ZFS root unlocks without a passphrase prompt when the enrolled TPM is available.
  • The expected root dataset is mounted.
  • The pool is online.
  • The encryption-root key status is available.
  • A provider or TPM failure returns to the normal passphrase path.
  • The retained passphrase can still unlock the root.

Test the recovery procedure before depending on unattended remote restarts. Do not clear or reset a production TPM merely to test fallback.

Security Model

With the default systemd configuration, the example command seals the credential to the TPM but does not bind it to a measured-boot PCR policy. The TPM may therefore release it to software with sufficient privileges on the original machine.

The credential contains the reusable ZFS passphrase, not a one-time boot token. An attacker who can run privileged code on the machine and access both the credential and TPM can recover the plaintext passphrase. Booting separate media may provide that access unless firmware settings, Secure Boot, or other controls prevent it. With the recovered passphrase and access to the pool devices or a copy, the attacker can attempt to unlock the pool on another machine.

TPM binding still protects against an attacker who has only the disks, or only the initramfs and credential, without the original TPM. It does not attest the boot chain.

Unattended unlock also means that a complete machine may boot into its normal operating environment without an operator supplying a secret. Evaluate physical access, service exposure, login security, Secure Boot, measured boot, and any PCR policy as separate parts of the system's threat model.

systemd-creds supports more restrictive TPM policies, but PCR selection, firmware and bootloader updates, initramfs changes, recovery, and re-enrollment must be designed together. ArchZFS does not prescribe a universal PCR policy.

systemd-creds may automatically adopt a signed PCR policy if tpm2-pcr-public-key.pem exists under /etc/systemd, /run/systemd, or /usr/lib/systemd. The packaged provider does not automatically include the matching tpm2-pcr-signature.json in the initramfs. Such a custom policy must provide all required policy files through FILES; otherwise decryption falls back to normal key loading. Signed PCR policies are outside this example.

Recovery and Key Changes

Keep the original ZFS passphrase available outside the TPM. The TPM credential must not be the only recovery mechanism.

Recreate the credential after:

  • zfs change-key
  • A TPM clear or reset
  • TPM storage-root-key rotation
  • Motherboard or TPM replacement
  • Any policy change that invalidates the existing credential

After recreating the credential, rebuild the initramfs and test both unattended unlock and manual recovery again.

A TPM failure does not change the ZFS encryption key. If the original passphrase remains available, it can still be entered through the normal fallback path.

If the passphrase may have been recovered, or the credential and original TPM may have been exposed together, treat the ZFS user key as compromised. Deleting the credential does not revoke a passphrase already recovered by an attacker. At minimum, change the user key and recreate the credential, but note that OpenZFS warns that zfs change-key does not necessarily protect previously or subsequently written data after key compromise because older wrapped master-key material may remain recoverable. Consult the upstream zfs-load-key(8) security guidance when choosing a remediation; high-assurance recovery may require migrating data to a newly encrypted dataset or pool.

Alternative Credential Path or Name

The provider accepts these kernel parameters:

zfs_tpm2_credential=/path/to/credential
zfs_tpm2_credential_name=credential-name

An alternative credential path must also be included in the initramfs through the FILES array. The configured credential name must match the name used when running systemd-creds encrypt.

Most installations should keep the defaults unless a specific naming or layout requirement exists.

Disable the Provider

To return to the standard key-loading behavior:

  1. Remove /etc/zfs/initramfs-tools-load-key.d/tpm2-systemd-creds.
  2. Remove the credential entry from the FILES array.
  3. Remove any zfs_tpm2_credential= or zfs_tpm2_credential_name= parameters from the bootloader configuration.
  4. Rebuild the initramfs with mkinitcpio -P.
  5. Confirm that the resulting image no longer contains the provider or credential.
  6. Remove /etc/zfs/zfs-key.creds if it is no longer needed.

Do not remove the only working recovery passphrase.

Troubleshooting

If the machine still requests a passphrase, check:

  • Whether the provider and credential are present in the initramfs.
  • Whether tpm2-tss was installed when the image was built.
  • Whether the TPM device and required drivers are available during early boot.
  • Whether the credential can still be decrypted by the current TPM.
  • Whether the boot root uses the expected encryption root.
  • Whether the credential name and path match the provider configuration.
  • Whether the TPM, storage root key, or PCR policy changed after enrollment.
  • Whether the initramfs was rebuilt after configuration changes.

A pool-import failure occurring before key loading is not necessarily a TPM provider problem. This feature does not change general root-on-ZFS pool discovery, import, device, cache, or hostid handling. Confirm that the same system boots through its standard key-loading path and consult the ArchWiki installation guidance when diagnosing the underlying root-on-ZFS configuration.

When reporting an ArchZFS problem, include the exact kernel, zfs-utils, and kernel-module package versions, the relevant mkinitcpio configuration, and complete sanitized boot output. Never include the ZFS passphrase, decrypted credential contents, TPM private state, or unrelated host information.