Compare commits
4 Commits
a5f32cfe76
...
a2ca77b70a
Author | SHA1 | Date | |
---|---|---|---|
a2ca77b70a | |||
58919e0d7f | |||
dd1fcb0c72 | |||
96ab417c72 |
43
README.md
43
README.md
@@ -61,6 +61,49 @@ After installation you're going to want to at least touch these points in your n
|
||||
- Local `root` account: The local `root` account's password is `password`.
|
||||
- Arch User Repository (AUR) helper: We installed [paru](https://github.com/Morganamilo/paru) as our AUR helper, we installed from GitHub via `makepkg -si`.
|
||||
|
||||
# Password change
|
||||
|
||||
## Steps
|
||||
|
||||
After installation you're going to want to change your ZFS encryption password. This generally means in a running OS:
|
||||
|
||||
1. Change password in `keylocation` file, e.g. `/etc/zfs/zpool.key` or whatever other `"${zpool_name}"'.key'` file you used during setup
|
||||
1. Set this key as the new encryption key:
|
||||
```
|
||||
zfs change-key -l zpool
|
||||
```
|
||||
Quoting `man 8 zfs-change-key` from `zfs-utils` version 2.1.9 for the `-l` argument: "Ensures the key is loaded before attempting to change the key." When successful the command will not output data, it'll just silently change your encryption key.
|
||||
1. Rebuild initramfs:
|
||||
```
|
||||
mkinitcpio -P
|
||||
```
|
||||
Here for example with `-P` (`--allpresets`) which processes all presets contained in `/etc/mkinitcpio.d`. This step puts the changed key file into your initramfs. During setup we've adjusted `/etc/mkinitcpio.conf` so that it contains `FILES=(/etc/zfs/zpool.key)` which causes the file to be added to initramfs as-is.
|
||||
|
||||
## Boot flow
|
||||
|
||||
With your password changed in two locations (key file and initramfs) The boot process works as follows.
|
||||
|
||||
At boot time ZFSBootMenu will scan all pools that it can import for a `bootfs` property. If it only finds one pool with that property the dataset given as `bootfs` will be selected for boot with a 10-second countdown allowing manual interaction. With `bootfs` set ZFSBootMenu will not actively search through datasets for valid kernel and initramfs combinations, it'll instead accept `bootfs` as the default boot entry without entering the pool decryption passphrase.
|
||||
|
||||
Upon loading into a given dataset ZFSBootMenu will attempt to auto-load the matching decryption key. In our setup this will fail because we purposely stored the encryption key inside our `zpool/root/archlinux` dataset. ZFSBootMenu will prompt us to type in the decryption key.
|
||||
|
||||
Lastly ZFSBootMenu loads our OS' kernel and initramfs combination via `kexec`. For this step we don't need to enter the decryption key again. Our initramfs file contains the plain-text `/etc/zfs/zpool.key` file which allows it to seamlessly import the right dataset, load its key and mount it.
|
||||
|
||||
## Caveats in a password change
|
||||
|
||||
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.
|
||||
|
||||
`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.
|
||||
>
|
||||
> In the event of a master key compromise, ideally the drives should be securely erased to remove all the old data (which is readable using the compromised master key), a new pool created, and the data copied back. This can be approximated in place by creating new datasets, copying the data (e.g. using `zfs send | zfs recv`), and then clearing the free space with `zpool trim --secure` if supported by your hardware, otherwise `zpool initialize`.
|
||||
|
||||
On one hand changing the ZFS encryption password is generally a good and useful thing to do. On the other hand changing your password does not currently overwrite previous wrapped master keys on disk. A sufficiently motivated party that gains access to a wrapped master key and the matching user key is able to decrypt the master key and use it to read all data encrypted with it.
|
||||
|
||||
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.
|
||||
|
||||
# ZFS setup explained
|
||||
|
||||
The ZFS pool and dataset setup that makes this tick, explained in plain English.
|
||||
|
14
setup.sh
14
setup.sh
@@ -147,7 +147,7 @@ function no_zpool_exists () {
|
||||
function set_zpool_password () {
|
||||
# May or may not have a newline at the end, ZFS doesn't care
|
||||
printf -- '%s' 'password' > '/etc/zfs/'"${zpool_name}"'.key'
|
||||
chmod '600' '/etc/zfs/'"${zpool_name}"'.key'
|
||||
chmod '000' '/etc/zfs/'"${zpool_name}"'.key'
|
||||
}
|
||||
|
||||
function import_pool () {
|
||||
@@ -388,9 +388,14 @@ function create_unpriv_user () {
|
||||
}
|
||||
|
||||
function unleash_makepkg () {
|
||||
local path_prefix
|
||||
path_prefix='/mnt'
|
||||
if we_are_changerooted; then
|
||||
path_prefix=''
|
||||
fi
|
||||
sed -ri \
|
||||
-e 's'$'\x1''^(#?(MAKEFLAGS=))[^\r\n\f]*'$'\x1''\2"-j$(nproc --ignore 1)"'$'\x1''g' \
|
||||
'/mnt/etc/makepkg.conf'
|
||||
"${path_prefix}"'/etc/makepkg.conf'
|
||||
}
|
||||
|
||||
function get_aur_helper () {
|
||||
@@ -504,7 +509,7 @@ DHCP=ipv4
|
||||
IPForward=yes
|
||||
|
||||
[DHCP]
|
||||
UseDNS=no
|
||||
UseDNS=yes
|
||||
RouteMetric=10
|
||||
EOF
|
||||
systemctl enable 'systemd-networkd' --root='/mnt'
|
||||
@@ -514,6 +519,9 @@ EOF
|
||||
function configure_dns () {
|
||||
rm '/mnt/etc/resolv.conf'
|
||||
ln -s '/run/systemd/resolve/stub-resolv.conf' '/mnt/etc/resolv.conf'
|
||||
|
||||
# Optionally you may want /etc/systemd/network/50-wired.network to use
|
||||
# UseDNS=no and hardcode DNS server(s) here:
|
||||
# sed -i 's/^#DNS=.*/DNS=1.1.1.1/' /mnt/etc/systemd/resolved.conf
|
||||
systemctl enable 'systemd-resolved' --root='/mnt'
|
||||
}
|
||||
|
Reference in New Issue
Block a user