From bfc6f814ef948676c2d693c3d010911c54622359 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 5 Mar 2023 03:34:59 +0100 Subject: [PATCH] docs(zfs): Explain how to rekey all data with new master key after user key change (#1) --- README.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index aa36ef1..aa90fcb 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ Lastly ZFSBootMenu loads our OS' kernel and initramfs combination via `kexec`. F ZFS differentiates between user keys - also called wrapping keys - and the master key for any given encryption root. You never interact with the master key, you only pick your personal user key. Subsequently a user key change (in our use case we perceive this simply as a password change) has zero effect on data that's already encrypted. The operation is instant and merely reencrypted the already existing master key, the so-called _wrapped_ master key. -ZFS generates the master key exactly once when you enable encryption on a dataset. Among other inputs it uses your user key to encrypt (to _wrap_) the master key. So when you change your user key it just means that the master key stays exactly the same and only the encrypted (_wrapped_) key changes. +ZFS generates the master key exactly once when you enable encryption on a dataset - technically when it becomes an encryption root. Among other inputs it uses your user key to encrypt (to _wrap_) the master key. So when you change your user key it just means that the master key stays exactly the same and only the encrypted (_wrapped_) key changes. `man 8 zfs-change-key` from `zfs-utils` version 2.1.9 adds: > If the user's key is compromised, `zfs change-key` does not necessarily protect existing or newly-written data from attack. Newly-written data will continue to be encrypted with the same master key as the existing data. The master key is compromised if an attacker obtains a user key and the corresponding wrapped master key. Currently, `zfs change-key` does not overwrite the previous wrapped master key on disk, so it is accessible via forensic analysis for an indeterminate length of time. @@ -104,6 +104,66 @@ On one hand changing the ZFS encryption password is generally a good and useful By extension this means after a password change your data remains at risk until you've copied it to a new dataset and erased previously used space thereby erasing any previous wrapped master keys. +## Changing master key + +In order to generate a new master key after you've changed your user key as mentioned in `man 8 zfs-change-key` from `zfs-utils` version 2.1.9 one example workflow goes like this: + +1. Change user key + - Update `/etc/zfs/zpool.key` + - Generate new initramfs with `mkinitcpio -P` +1. Create a snapshot from current system dataset + ``` + # Assuming current system dataset is zpool/root/archlinux-sxu + # where '-sxu' is a random suffix to differentiate datasets + # and has no real meaning + zfs snapshot zpool/root/archlinux-sxu@rekey + ``` +1. Within same pool `send`/`receive` snapshot + ``` + zfs send \ + --large-block \ + --compressed \ + 'zpool/root/archlinux-sxu@rekey' | \ + + zfs receive \ + -Fvu \ + -o 'encryption=on' \ + -o 'keyformat=passphrase' \ + -o 'keylocation=file:///etc/zfs/zpool.key' \ + -o 'mountpoint=/' \ + -o 'canmount=noauto' \ + -o 'org.zfsbootmenu:commandline=rw nowatchdog rd.vconsole.keymap=de-latin1' \ + 'zpool/root/archlinux-frn' + ``` + Explanation: + - We specifically don't `zfs send -R` (`--replicate`). While it would normally be nice to transfer all of a dataset's children at once such as all of its snapshots the `-R` argument conflicts with the `encryption` property. See [comment by Tom Caputi on GitHub openzfs/zfs issue 10507 from June 2020](https://github.com/openzfs/zfs/issues/10507#issuecomment-651162104) for details. Basically if `encryption` is set then `-R` doesn't work. We could transfer existing encryption properties with `-w`/`--raw` but we don't actually want to transfer encryption properties at all. We want them to change during transfer, see the bullet point four points down from here talking about `encryption`. + - We `zfs receive -F` destroying any target snapshots and file systems beyond the snapshot we're transferring. In this example the target `zpool/root/archlinux-frn` doesn't even exist so `-F` isn't necessary to clean anything up. It's just good practice. + - With `-v` we get verbose progress output + - Argument `-u` makes sure the dataset does not get mounted after transfer. ZFS would mount it into `/` which wouldn't be helpful since we're currently using that filesystem ourselves. + - We set encryption properties `keyformat`, `keylocation` and most importantly `encryption`. The latter will turn our transferred dataset into its own `encryptionroot` which in turn generates a new master key. The auto-generated new master key gets wrapped with our updated passphrase in `keylocation`. This basically rekeys all data on our pool during transfer. + - We set `mountpoint` and `canmount` as well as a `org.zfsbootmenu:commandline` as we would for any new system dataset. +1. Change zpool's `bootfs` property to new system dataset + ``` + zpool set bootfs=zpool/root/archlinux-frn zpool + ``` +1. Boot into new system dataset +1. Update the new system dataset's `encryptionroot` by letting it inherit key data from its parent: + ``` + zfs change-key -i -l zpool/root/archlinux-frn + ``` + The parent `zpool/root` is inheriting this property from `zpool` which will make sure that `zpool/root/archlinux-frn` essentially gets its key now from `zpool`. Both `zpool/root/archlinux-frn` and `zpool` use the same exact `keylocation` with identical content. This operation is instant. + +Optionally you may want to clean up: + +1. In newly keyed/reencrypted system dataset destroy its snapshot + ``` + zfs destroy zpool/root/archlinux-frn@rekey + ``` +1. Recursively destroy source dataset + ``` + zfs destroy -r zpool/root/archlinux-sxu + ``` + # ZFS setup explained The ZFS pool and dataset setup that makes this tick, explained in plain English.