clevis
clevis copied to clipboard
Add support for ZFS encryption
Why
As I stated a while ago in https://github.com/latchset/clevis/issues/218, I would like clevis to be able to unlock ZFS datasets that have native encryption enabled. This is my attempt at adding this by storing the data in zfs properties.
How
This is achieved by storing the clevis data (output of clevis-encrypt) in ZFS User Properties.
From zfsprops(8):
User Properties
In addition to the standard native properties, ZFS supports arbitrary user properties. User
properties have no effect on ZFS behavior, but applications or administrators can use them
to annotate datasets (file systems, volumes, and snapshots).
User property names must contain a colon (":") character to distinguish them from native
properties. They may contain lowercase letters, numbers, and the following punctuation
characters: colon (":"), dash ("-"), period ("."), and underscore ("_"). The expected
convention is that the property name is divided into two portions such as module:property,
but this namespace is not enforced by ZFS. User property names can be at most 256
characters, and cannot begin with a dash ("-").
When making programmatic use of user properties, it is strongly suggested to use a reversed
DNS domain name for the module component of property names to reduce the chance that two
independently-developed packages use the same property name for different purposes.
The values of user properties are arbitrary strings, are always inherited, and are never
validated. All of the commands that operate on properties (zfs list, zfs get, zfs set, and
so forth) can be used to manipulate both native properties and user properties. Use the zfs
inherit command to clear a user property. If the property is not defined in any parent
dataset, it is removed entirely. Property values are limited to 8192 bytes.
Properties
All clevis user properties are prefixed with latchset.clevis
- one property to check if a dataset is bound:
latchset.clevis:labels, should be a space-separated list of bound labels. or absent when unbound. - one or more properties to store the clevis data:
latchset.clevis.label:LABEL_NAME[-N]where-Nis an integer suffix when the data for label LABEL_NAME is too large for one property.
If there are more than 10 properties needed, the integer will be 0-padded to help with sorting to easily combine them when unlocking.
As noted above (at the end), the limit of the value of a user property is 8192 bytes.
A simple 1-host tang setup will probably not go over this limit, but with a more complicated setup with clevis-encrypt-sss, it is possible.
Because of that, the clevis data is split in 8k chunks, and saved in multiple user-properties. These are combined upon unlock.
"Works": (works on my machine, needs more testing)
- binding ZFS dataset with
clevis-zfs-bind - unbinding ZFS dataset with
clevis-zfs-unbind - testing and unlocking ZFS dataset with
clevis-zfs-unlock - splitting and combining zfs-properties (tested with a limit of 800 instead of 8000)
To Do:
- [ ] manpages
- [ ] initramfs hooks
- [ ] rebinding support? (like clevis-luks-rebind)
- [x] Maybe: multiple "slots" support. Currently only one "slot" is available. Added label support
- [ ] clean up commits if this is not squashed
Update: I had a succesful boot using the clevis binding on a zfs user property with a TPM binding, but that was on my arch laptop. (i.e. mkinitcpio instead of dracut). Next step would be to test the initramfs with dracut in a VM.
@npmccallum do you (or other maintainers) know if this PR would be welcome at all?
If not, I'll close it, but If it is, I'll try to finish it in the next few weeks.
Keeping an eye on this.
@npmccallum do you (or other maintainers) know if this PR would be welcome at all?
If not, I'll close it, but If it is, I'll try to finish it in the next few weeks.
I would say it is definitely useful, your work is much appreciated. Consider making a fork, if needed.
Might be easy enough to port to initramfs hooks. I'm finally looking into this...
Why has the pull req been ignored?
I haven't worked on this for a while, because it's been working for me fine on Arch+clevis+mkinitramfs :p But I'm glad to see more people are interested in this, I'll try to work on this next week.
quick questions, what is the status for initramfs hooks integration?
Thanks.
The scripts in my branch are functional. There is mostly some polish missing.
I haven't worked on this PR at all, and I don't have time anytime soon. Feel free to contribute or take over if you want.
For an initramfs hook I think the zfs-initramfs script would need changes. I see two main issues:
-
There doesn't seem to be a point to inject a script between the pools being imported and attempting to load-keys for decrypting. Right now {init,local}-top, {init,local}-premount are ran before import. local-bottom is ran after mount and I'm unsure where init-bottom is then run. If the clevis-script doesn't block then this shouldn't be an issue but you would have a race condition of trying to load-key before the interactive prompt for decryption appears. I feel like this would just drop us into the recovery shell.
-
The decrypt_fs function goes immediately interactive if the keylocation is set to prompt. If it's set to a file location it will load that. If it can't load a file or bad prompt it goes to the recovery shell.
As a workaround to have some sort of support I just include a jwe in the initramfs and have it decrypt to file location. The zfs script then runs as normal and imports the key from the file location. The decryption of the jwe happens pre-import and I haven't thought through the implications of writing to the initramfs. This is probably not the correct way to do things but it does "work".
@npmccallum @techhazard I'd love to give some time to look into this. I'll give it a shot over the next couple days. Should I rebase @techhazard's changes onto the latest tip of master?
@techhazard did you commit clevis-zfs.in? Meson is failing because it's missing:
../src/initramfs-tools/scripts/local-top/meson.build:7:0: ERROR: File clevis-zfs.in does not exist.
@m2Giles It appears that your concern about having a hook in the initramfs script has been merged: openzfs/zfs@6e015933f88fe7ba5de45cf263028de1ee04460a, available in zfs 2.2+
I'm building test packages available in PPA and with the updated source on GitHub. I've had to update the Debian packaging to work with the new code.
See reworked PR at #467.