OpenZFS encryption and the TPM
Since writing this, I’ve collected some of the below in a git
repository. There you’ll find a key loader and a systemd unit that
will make sure it runs before zfs-mount.service
. Give the unit file the same name as the generated key loader
unit1 and place it in /etc/systemd/system
.
Right now, this implementation uses NVRAM to store the key directly. An obvious improvement would be to use sealed data
(tpm_sealdata
, tpm_unsealdata
).
original content from 2020-11-29 follows
I wanted to have an encrypted OpenZFS dataset whose key was stored with my TPM. Using @morbitzer’s guide to doing the same for LUKS, I divined a couple commands that helped me out.
- Install (Debian)
tpm-tools
,zfs-dkms
. Make sure TrouserStcsd
is running. - Create a key
dd if=/dev/urandom of=/dev/shm/key.bin bs=32 count=1
- Load the key into TPM NVRAM
- Define a slot; here I chose index 1.
tpm_nvdefine -i 1 -s 32 -r0 -r1 -r2 -r3 -r4 -r5 -r6 -r7 -p "OWNERWRITE|READ_STCLEAR"
- This seals the NVRAM index to PCRs 0-7 (the ones measured into by the system firmware)
- Fill that slot with the key.
tpm_nvwrite -i 1 -f /dev/shm/key.bin
- Define a slot; here I chose index 1.
- Create the dataset
zfs create rpool/dataset -o encryption=aes-256-gcm -o keyformat=raw -o keylocation=file:///dev/shm/key.bin
- Destroy the key
Loading the key⌗
This is somewhat silly: tpm_nvread
has unsuppressable logging to stdout
, so we direct its output to /dev/stdout
(it doesn’t support -f -
) and chop off the first $KEYLENGTH
bytes.
-l none
seems like it would work to suppress the logging. It does not.
zfs load-key
likewise does not support -L -
or -L file://-
. We’ll just use the /dev/stdin
trick again.
tpm_nvread -i 1 -f /dev/stdout |
dd bs=32 count=1 |
zfs load-key -L file:///dev/stdin rpool/dataset
Locking the key⌗
Because we set READ_STCLEAR
when we defined the NVRAM slot, sending the TPM a read of size 0 will lock the key to
prevent future reading.
tpm_nvread -i 1 -s 0
On one of my test systems, I had the problem that the secret stored in the NVRAM could be read even when the PCRs it was sealed to had changed. It took me quite a long time to figure out what went wrong: Apparently, the TPM manufacturer didn’t set the
nvLocked
bit, which means that reading the NVRAM was always possible, no matter if you sealed it to some PCRs or assigned a password to it. Thanks to this discussion at the TrouSers mailing list, I was finally able to figure out what to do:
tpm_nvdefine -i 0xFFFFFFFF –size=0
@morbitzer’s guide
-
look in
/run/systemd/generator
forzfs-load-key*.service
↩︎