OpenZFS allows full disk encryption in the latest versions based on a key that can be either read in as a password or read from a file. A trusted platform module (TPM) can be used to store a key in NVRAM and then retrieve the key in order to mount the OpenZFS pool. The following notes explain setting up a TPM v1.2 and automatically mounting an OpenZFS pool on boot without having to enter the password manually. The advantage of storing a passphrase in the TPM NVRAM is that the best of both worlds can be attained: a passphrase is readily available to unlock the ZFS pool in case the motherboard is destroyed and the fact that the ZFS pool will not have to be manually mounted on boot by specifying the password on the command line every time.
The required packages to be installed on Debian are:
tpm-tools
and,trousers
The TPM has to be cleared in the BIOS if not done so previously which will take two restarts: one to clear the TPM and then another restart to enable the TPM. Once that is done, and provided that the TPM is available, taking ownership of the TPM is the first step:
tpm_takeownership -z
where:
-z
will set the SRK password to the default of all zeroes; this is important because setting the SRK to the default well-known password will prevent the TPM to prompt for a password once the NVRAM indices are read.The command will prompt for an owner password that should be typed and remembered for all eternity.
As a hack, but harmless to do, is to run the following command:
tpm_nvdefine -i 0xFFFFFFFF –s 0
this will seal the TPM by setting the nvLocked
bit in case the hardware designer did not enable the bit when creating the TPM.
The following step is to define an NVRAM index governed by a set of permissions and PCRs: the permissions will define what operations are permitted (and by whom) for the NVRAM index and the PCRs define a set of well-known system parameters that the data placed in the NVRAM index depend upon. In case any of the PCRs change at a later date, the NVRAM location will no longer contain the password and this is the mechanism that locks the TPM to the hardware device.
At this point, the ZFS encryption password should be written to a file that will be used in the next step. Assuming that the file is named zfs_password
, the following command will count the number of characters in the file:
cat zfs_password | wc -c
this will yield the number of single byte characters and hence bytes to be used with the following command that defines an NVRAM index:
tpm_nvdefine -i 1 -s 32 -r0 -r1 -r2 -r3 -r4 -r5 -r6 -r7 -p "OWNERWRITE|READ_STCLEAR" -o PASSWORD
where:
-i 1
is a chosen index number,-s 32
is the size in bytes of the data stored in NVRAM at the given index (in this case, index being 1
); this must be equal to the number of bytes in the OpenZFS password inside the zfs_password
file,-r0 -r1 -r2 -r3 -r4 -r5 -r6 -r7
locks the NVRAM location to PCRs 0, 1, 2, 3, 4, 5, 6, and 7,-p "OWNERWRITE|READ_STCLEAR"
will grant permission to the owner to write and will specify that the location can be read and then cleared; in other words, the passphrase will be written to the TPM NVRAM only once and then read once on boot and then cleared,PASSWORD
is the TPM owner password entered previously via tpm_takeownership -z
.Now that an NVRAM location is defined and is sufficiently large to hold the password, issue the following command in order to load the password into the NVRAM location:
tpm_nvwrite -i 1 -f zfs_password -p PASSWORD
where:
-i 1
is the index of the defined NVRAM location,zfs_password
is a file containing the OpenZFS password created previously,PASSWORD
is the owner password of the TPM device.
At this point the TPM device should contain the plaintext password stored at the index 1
. To check that the NVRAM location contains the password, issue:
tpm_nvread -i 1
The command should not require a password and should print out a hexadecimal representation of the password as well as the ASCII equivalent plaintext password.
To check that everything is working, unmount the ZFS pool and issue:
tpm_nvread -i 1 -f /dev/stdout | \ dd count=1 bs=32 status=none | \ zfs mount -l POOL
where:
bs=32
is the length of the password in bytes,POOL
is the name of the pool.
The command reads the password from the NVRAM index 1, pipes it to the disk dumper command and reads the first 32
bytes (the length of the password) and pipes the result to the ZFS mount command that mounts the pool by prompting for a password.
In order to automate the command such that the pool is mounted on boot, create the file /usr/local/sbin/mount_zfs
with the following contents:
#!/bin/bash ########################################################################### ## Copyright (C) Wizardry and Steamworks 2021 - License: GNU GPLv3 ## ########################################################################### ########################################################################### ## CONFIGURATION ## ########################################################################### # The name of the pool to be mounted. POOL="POOL" # The NVRAM index where the key is stored. TPM_INDEX="1" ########################################################################### ## INTERNALS ## ########################################################################### MOUNTED=`zfs get -H -o value mounted $POOL` if [ x$MOUNTED = x"yes" ]; then exit 0 fi tpm_nvread -i $TPM_INDEX -f /dev/stdout | \ dd count=1 bs=11 status=none | \ zfs mount -l $POOL MOUNTED=`zfs get -H -o value mounted $POOL` if [ x$MOUNTED = x"yes" ]; then exit 1 fi # Lock the TPM to prevent further reads. tpm_nvread -i 1 -s 0
and make the file executable with:
chmod +x /usr/local/sbin/mount_zfs
Next, a systemd service file is created that calls the script on boot. Create a file at /etc/systemd/system/zfs-encrypted-mount.service
with the following contents:
[Unit] Description=Mount encrypted ZFS pool After=zfs.target [Service] Type=oneshot ExecStart = /usr/local/sbin/mount_zfs [Install] WantedBy = multi-user.target
and then enable the service:
systemctl enable zfs-encrypted-mount
The process is now completed and the ZFS pool should be mounted from the TPM on boot.