Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ZFS encryption #373

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

techhazard
Copy link

@techhazard techhazard commented May 24, 2022

Why

As I stated a while ago in #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 -N is 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)
  • Maybe: multiple "slots" support. Currently only one "slot" is available. Added label support
  • clean up commits if this is not squashed

@techhazard
Copy link
Author

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.

@techhazard
Copy link
Author

@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.

@ghost
Copy link

ghost commented Jun 10, 2022

Keeping an eye on this.

@ghost
Copy link

ghost commented Jun 10, 2022

@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.

@ghost
Copy link

ghost commented Dec 1, 2022

Might be easy enough to port to initramfs hooks. I'm finally looking into this...

Why has the pull req been ignored?

@techhazard
Copy link
Author

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.

@jeschero
Copy link

quick questions, what is the status for initramfs hooks integration?

Thanks.

@techhazard
Copy link
Author

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.

@m2Giles
Copy link

m2Giles commented Apr 26, 2023

For an initramfs hook I think the zfs-initramfs script would need changes. I see two main issues:

  1. 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.

  2. 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".

@lowjoel
Copy link

lowjoel commented Jun 11, 2024

@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?

@lowjoel
Copy link

lowjoel commented Jun 11, 2024

@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.

@lowjoel
Copy link

lowjoel commented Jun 11, 2024

@m2Giles It appears that your concern about having a hook in the initramfs script has been merged: openzfs/zfs@6e01593, available in zfs 2.2+

@lowjoel
Copy link

lowjoel commented Jun 11, 2024

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.

@lowjoel lowjoel mentioned this pull request Jun 12, 2024
5 tasks
@lowjoel
Copy link

lowjoel commented Jun 12, 2024

See reworked PR at #467.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants