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`.
 | 
					    - 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`.
 | 
					- 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
 | 
					# ZFS setup explained
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The ZFS pool and dataset setup that makes this tick, explained in plain English.
 | 
					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 () {
 | 
					function set_zpool_password () {
 | 
				
			||||||
    # May or may not have a newline at the end, ZFS doesn't care
 | 
					    # May or may not have a newline at the end, ZFS doesn't care
 | 
				
			||||||
    printf -- '%s' 'password' > '/etc/zfs/'"${zpool_name}"'.key'
 | 
					    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 () {
 | 
					function import_pool () {
 | 
				
			||||||
@@ -388,9 +388,14 @@ function create_unpriv_user () {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function unleash_makepkg () {
 | 
					function unleash_makepkg () {
 | 
				
			||||||
 | 
					    local path_prefix
 | 
				
			||||||
 | 
					    path_prefix='/mnt'
 | 
				
			||||||
 | 
					    if we_are_changerooted; then
 | 
				
			||||||
 | 
					        path_prefix=''
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
    sed -ri \
 | 
					    sed -ri \
 | 
				
			||||||
        -e 's'$'\x1''^(#?(MAKEFLAGS=))[^\r\n\f]*'$'\x1''\2"-j$(nproc --ignore 1)"'$'\x1''g' \
 | 
					        -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 () {
 | 
					function get_aur_helper () {
 | 
				
			||||||
@@ -504,7 +509,7 @@ DHCP=ipv4
 | 
				
			|||||||
IPForward=yes
 | 
					IPForward=yes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[DHCP]
 | 
					[DHCP]
 | 
				
			||||||
UseDNS=no
 | 
					UseDNS=yes
 | 
				
			||||||
RouteMetric=10
 | 
					RouteMetric=10
 | 
				
			||||||
EOF
 | 
					EOF
 | 
				
			||||||
    systemctl enable 'systemd-networkd' --root='/mnt'
 | 
					    systemctl enable 'systemd-networkd' --root='/mnt'
 | 
				
			||||||
@@ -514,6 +519,9 @@ EOF
 | 
				
			|||||||
function configure_dns () {
 | 
					function configure_dns () {
 | 
				
			||||||
    rm '/mnt/etc/resolv.conf'
 | 
					    rm '/mnt/etc/resolv.conf'
 | 
				
			||||||
    ln -s '/run/systemd/resolve/stub-resolv.conf' '/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
 | 
					    # sed -i 's/^#DNS=.*/DNS=1.1.1.1/' /mnt/etc/systemd/resolved.conf
 | 
				
			||||||
    systemctl enable 'systemd-resolved' --root='/mnt'
 | 
					    systemctl enable 'systemd-resolved' --root='/mnt'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user