mirror of
https://git.sr.ht/~nabijaczleweli/tzpfms
synced 2025-04-11 09:30:02 +03:00
160 lines
7.6 KiB
Markdown
160 lines
7.6 KiB
Markdown
# tzpfms [](//builds.sr.ht/~nabijaczleweli/tzpfms)
|
||
TPM-based encryption keys for ZFS datasets.
|
||
|
||
See also [fzifdso](//git.sr.ht/~nabijaczleweli/fzifdso) for FIDO2/WebAuthn-based (YubiKey, Somu, &c.) keys.
|
||
|
||
## [Manpages](//ra.ws.co.ls/~nabijaczleweli/tzpfms/blob/man/zfs-tpm-list.8.html) ([PDF](//ra.ws.co.ls/~nabijaczleweli/tzpfms/blob/man/tzpfms.pdf))
|
||
|
||
### Why?
|
||
|
||
```
|
||
T P M
|
||
Z F S
|
||
```
|
||
|
||
Plus it's a pretty good annoyed sigh onomatopoeia.
|
||
|
||
### What?
|
||
|
||
Essentially BitLocker, but for ZFS –
|
||
a random raw key is generated and sealed to the TPM (both 2 and 1.x supported) with an additional optional password in front of it,
|
||
tying the dataset to the platform and an additional optional secret (or to the posession of the back-up).
|
||
|
||
Additionally, 1.x TPMs support PCR binding with and without passwords.
|
||
2 TPMs support PCR binding without a password and PCR binding *OR* a password – both may be set, and any can be used to unseal (exclusive by default to prevent foot-guns).
|
||
|
||
Both dracut (with/without Plymouth) (with/without hostonly) (only on systemd systems, I don't have a test-bed for the non-systemd path)
|
||
and initramfs-tools (with/without Plymouth) are supported for [ZFS-on-root](//nabijaczleweli.xyz/content/blogn_t/005-low-curse-zfs-on-root.html) set-ups.
|
||
|
||
### Building
|
||
|
||
You'll need `pkgconf`, `shellcheck`, `libzfslinux-dev` (0.8.x and 2.[012].x work), `libtss2-dev`, `libtspi-dev`, `libssl-dev`, and `make` should hopefully Just Work™ if you have a C++17-capable compiler.
|
||
The output binaries are trimmed of extraneous dependencies, so they're all just libc + libzfs and friends + the chosen TPM back-end, if any + libcrypto for TPM2 PCR handling.
|
||
|
||
`mandoc` is required for HTML manuals. Set `MANDOC=true` to forgo this.
|
||
|
||
The default `$TZPFMS_PASSPHRASE_HELPER` is the null string.
|
||
To set a different default, set `TZPFMS_PASSPHRASE_HELPER` and `TZPFMS_PASSPHRASE_HELPER_MAN` for `make` — `$`s need to be double-escaped and `'`s need to be full-`'` escaped (i.e. `'\''`).
|
||
|
||
As an example, for a sensible default value of `exec systemd-ask-password --id="tzpfms:$2" "$1:"` for OOB systemd integration, pass `TZPFMS_PASSPHRASE_HELPER='exec systemd-ask-password --id="tzpfms:$$2" "$$1:"'` and `TZPFMS_PASSPHRASE_HELPER_MAN='Ic exec Nm systemd-ask-password Fl -id Ns Li = Ns Qo Li tzpfms:\& Ns Ar $$2 Qc Qo Ar $$1 Ns Li ":\&" Qc'`.
|
||
|
||
### Installation
|
||
|
||
Copy the `out/zfs-tpm*` binaries corresponding to the back-ends you want to `/sbin`,
|
||
continue as the [manual](//ra.ws.co.ls/~nabijaczleweli/tzpfms/blob/man/zfs-tpm2-change-key.8.html) [page](//ra.ws.co.ls/~nabijaczleweli/tzpfms/blob/man/zfs-tpm1x-change-key.8.html) instructs.
|
||
|
||
For initrd support, copy the content of either `out/dracut/` or `out/initramfs-tools/` over `/`;
|
||
these need `zfs-tpm-list` but will work with any combination of back-end `*-load-key` binaries
|
||
(local TPM1.X initrds need to be updated when the system state changes (e.g. the TPM is taken ownership of)).
|
||
|
||
To integrate with [zfs-mount-generator(8)](//manpages.debian.org/bookworm/zfsutils-linux/zfs-mount-generator.8.html)
|
||
[copy](//lfs.nabijaczleweli.xyz/0017-twitter-export#1472986504272261124) `out/systemd/` over `/`.
|
||
|
||
#### From Debian repository
|
||
|
||
The following line in `/etc/apt/sources.list` or equivalent:
|
||
```apt
|
||
deb [signed-by=/etc/apt/keyrings/nabijaczleweli.asc] https://debian.nabijaczleweli.xyz sid main
|
||
```
|
||
|
||
With [my PGP key](//nabijaczleweli.xyz/pgp.txt) (the two URLs are interchangeable):
|
||
```sh
|
||
sudo wget -O/etc/apt/keyrings/nabijaczleweli.asc https://debian.nabijaczleweli.xyz/nabijaczleweli.gpg.key
|
||
sudo wget -O/etc/apt/keyrings/nabijaczleweli.asc https://nabijaczleweli.xyz/pgp.txt
|
||
```
|
||
(you may need to create /etc/apt/keyrings on apt <2.4.0 (<=bullseye) manually).
|
||
|
||
Then the usual
|
||
```sh
|
||
sudo apt update
|
||
sudo apt install tzpfms-tpm2 tzpfms-dracut
|
||
```
|
||
will work on amd64, x32, and i386.
|
||
|
||
See the [repository README](//debian.nabijaczleweli.xyz/README) for more information.
|
||
|
||
#### From tar-ball
|
||
|
||
Release tarballs are signed with <nabijaczleweli@nabijaczleweli.xyz> (pull with WKD, but `7D69 474E 8402 8C5C C0C4 4163 BCFD 0B01 8D26 58F1`).
|
||
аnd stored in git notes as-if via [the example program](//man.sr.ht/git.sr.ht/#signing-tagsx27-tarballs)
|
||
and are thus available on the [refs listing](https://git.sr.ht/~nabijaczleweli/tzpfms/refs)/tag page as .tar.gz.asc.
|
||
|
||
### Testing
|
||
#### TPM2
|
||
|
||
Install [`swtpm`](//github.com/stefanberger/swtpm), then prepare and run it:
|
||
```sh
|
||
swtpm_setup --tpmstate tpm2-state --tpm2 --createek --display --logfile /dev/tty --overwrite
|
||
swtpm socket --server type=tcp,port=2321 --ctrl type=tcp,port=2322 --tpm2 --tpmstate dir=tpm2-state --flags not-need-init --log level=10
|
||
```
|
||
|
||
If your platform has a TPM, switch to `swtpm` by default:
|
||
```
|
||
ln -s /usr/lib/i386-linux-gnu/libtss2-tcti-{swtpm,default}.so
|
||
```
|
||
#### TPM1.x
|
||
|
||
Install [`swtpm`](//github.com/stefanberger/swtpm), then prepare and run it and
|
||
([hopefully](//github.com/stefanberger/swtpm/issues/5#issuecomment-210607890)) [TrouSerS](//sourceforge.net/projects/trousers), as `root`/`tpm`:
|
||
```sh
|
||
swtpm_setup --tpmstate tpm1x-state --createek --display --logfile /dev/tty --overwrite
|
||
swtpm cuse -n tpm --tpmstate dir=tpm1x-state --seccomp action=none --log level=10,file=/dev/fd/4 4>&1
|
||
swtpm_ioctl -i /dev/tpm
|
||
TPM_DEVICE=/dev/tpm swtpm_bios
|
||
tcsd -f
|
||
|
||
swtpm_ioctl -s /dev/tpm # to shut down, apparently
|
||
```
|
||
|
||
If your platform has a TPM, occupy it first by running `exec 100<>/dev/tpm0` or equivalent. `tcsd` looks at `/dev/tpm0` before `/dev/tpm`.
|
||
|
||
#### initrd
|
||
|
||
Running
|
||
```sh
|
||
swtpm socket --ctrl type=unixio,path=/tmp/swtpm --tpm2 --tpmstate dir=tpm2-state --flags not-need-init --log level=10
|
||
# or
|
||
swtpm socket --ctrl type=unixio,path=/tmp/swtpm --tpmstate dir=tpm1x-state --log level=10
|
||
```
|
||
instead, alongside passing
|
||
```
|
||
-chardev socket,id=chrtpm,path=/tmp/swtpm -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0
|
||
```
|
||
to QEMU will create a TPM device on the guest which Should® be fully funxional.
|
||
|
||
## Reporting bugs
|
||
|
||
There's [the tracker](//todo.sr.ht/~nabijaczleweli/tzpfms), but also see the list below.
|
||
|
||
## Contributing
|
||
|
||
Send a patch inline, as an attachment, or a git link and a ref to pull from to
|
||
[the list](//lists.sr.ht/~nabijaczleweli/tzpfms) ([~nabijaczleweli/tzpfms@lists.sr.ht](mailto:~nabijaczleweli/tzpfms@lists.sr.ht)) or [me](mailto:nabijaczleweli@nabijaczleweli.xyz)
|
||
directly. I'm not picky, just please include the repo name in the subject prefix.
|
||
|
||
### "Ecosystem"
|
||
|
||
Put a line containing the `zfs-{...}-load-key` program name followed by a list of required services (if any) into `/usr/share/tzpfms/${tzpfms.backend}`
|
||
and the `zfs-load-key@.service` drop-in will understand it and use it to load.
|
||
|
||
Known compatible backends:
|
||
|
||
| `/usr/share/tzpfms/` | data | from | for |
|
||
| -------------------- | ------------------------------------- | ---------------------------------------------- | -------------- |
|
||
| `TPM1.X` | `zfs-tpm1x-load-key trousers.service` | [tzpfms](//sr.ht/~nabijaczleweli/tzpfms) | TPM |
|
||
| `TPM2` | `zfs-tpm2-load-key` | [tzpfms](//sr.ht/~nabijaczleweli/tzpfms) | TPM |
|
||
| `FIDO2` | `zfs-fido2-load-key` | [fzifdso](//git.sr.ht/~nabijaczleweli/fzifdso) | FIDO2/WebAuthn |
|
||
|
||
## Discussion
|
||
|
||
Please use the tracker, the list, or [mastussy](//101010.pl/@nabijaczleweli) (formerly [Twitter](//lfs.nabijaczleweli.xyz/0017-twitter-export#1315137083380559873)).
|
||
|
||
## Special thanks
|
||
|
||
To all who support further development on Patreon, in particular:
|
||
|
||
* ThePhD
|
||
* Embark Studios
|
||
* Jasper Bekkers
|
||
* EvModder
|