Compare commits

..

6 Commits

2 changed files with 48 additions and 43 deletions

View File

@@ -28,13 +28,13 @@ mkfs.vfat /dev/sda1
The result will be something like this at which point you can start the `setup.sh` script, see [How to run this?](#how-to-run-this) below for more details. The result will be something like this at which point you can start the `setup.sh` script, see [How to run this?](#how-to-run-this) below for more details.
``` ```
# lsblk --paths # lsblk --paths
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
/dev/loop0 7:0 0 688.5M 1 loop /run/archiso/airootfs /dev/loop0 7:0 0 685.5M 1 loop /run/archiso/airootfs
/dev/sr0 11:0 1 810.3M 0 rom /run/archiso/bootmnt /dev/sr0 11:0 1 808.3M 0 rom /run/archiso/bootmnt
/dev/sda 202:0 0 10G 0 disk /dev/sda 202:0 0 20G 0 disk
├─/dev/sda1 202:1 0 512M 0 part ├─/dev/sda1 202:1 0 512M 0 part
└─/dev/sda2 202:2 0 9.9G 0 part └─/dev/sda2 202:2 0 19.5G 0 part
``` ```
## ZFS dataset layout ## ZFS dataset layout
@@ -48,8 +48,7 @@ The script will use the `EF00` partition to install a ZFSBootMenu EFI executable
- Boot an Arch Linux live CD ISO image - Boot an Arch Linux live CD ISO image
- Run: - Run:
``` ```
export SCRIPT_URL='https://quico.space/quico-os-setup/arch-zbm/raw/branch/main/setup.sh' export SCRIPT_URL='https://quico.space/quico-os-setup/arch-zbm/raw/branch/main/setup.sh' && curl -s "${SCRIPT_URL}" | bash
curl -s "${SCRIPT_URL}" | bash
``` ```
During execution the script will call itself when it changes into its `chroot`, that's why we `export SCRIPT_URL`. Feel free to update `"${SCRIPT_URL}"` with whatever branch or revision you want to use from [quico.space/quico-os-setup/arch-zbm](https://quico.space/quico-os-setup/arch-zbm). Typically `.../branch/main/setup.sh` as shown above is what you want. During execution the script will call itself when it changes into its `chroot`, that's why we `export SCRIPT_URL`. Feel free to update `"${SCRIPT_URL}"` with whatever branch or revision you want to use from [quico.space/quico-os-setup/arch-zbm](https://quico.space/quico-os-setup/arch-zbm). Typically `.../branch/main/setup.sh` as shown above is what you want.
@@ -179,7 +178,7 @@ ZFS generates the master key exactly once when you enable encryption on a datase
`man 8 zfs-change-key` from `zfs-utils` version 2.1.9 adds: `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. > 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`. > 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. 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.
@@ -315,7 +314,7 @@ The ZFS pool and dataset setup that makes this tick, explained in plain English.
1. We export the zpool once, we then reimport it by scanning only inside `/dev/disk/by-partuuid`, again setting `-R /mnt` as we did during pool creation a moment ago and we do not mount any file systems. 1. We export the zpool once, we then reimport it by scanning only inside `/dev/disk/by-partuuid`, again setting `-R /mnt` as we did during pool creation a moment ago and we do not mount any file systems.
1. We `zfs load-key <encryptionroot>` which will load the key from `keylocation` after which the `keystatus` property for `<encryptionroot>` and all child datasets will change from `unavailable` to `available`. 1. We `zfs load-key <encryptionroot>` which will load the key from `keylocation` after which the `keystatus` property for `<encryptionroot>` and all child datasets will change from `unavailable` to `available`.
1. We mount our Arch Linux boot environment dataset. It automatically gets prefixed with `-R /mnt` since that's how we imported the pool. 1. We mount our Arch Linux boot environment dataset. It automatically gets prefixed with `-R /mnt` since that's how we imported the pool.
1. We `zfs mount -a` which automounts `zpool/data/home` into `/home`, which again gets auto-prepended by `/mnt`. 1. We `zfs mount -a` which automounts `zpool/data/home` into `/home`, which again gets auto-prepended by `/mnt`.
1. We lastly mount our EFI partition into `/mnt/efi`. 1. We lastly mount our EFI partition into `/mnt/efi`.
1. We instruct ZFS to save its pool configuration via `zpool set cachefile=/etc/zfs/zpool.cache zpool`. 1. We instruct ZFS to save its pool configuration via `zpool set cachefile=/etc/zfs/zpool.cache zpool`.
@@ -424,7 +423,7 @@ Commit _types_ besides `fix` and `feat` are:
The following _scopes_ are known for this project. A Conventional Commits commit message may optionally use one of the following scopes or none: The following _scopes_ are known for this project. A Conventional Commits commit message may optionally use one of the following scopes or none:
- `iso`: Changing Arch Linux ISO CD - `iso`: Changing Arch Linux live CD ISO image
- `zbm`: Adjusting ZFSBootMenu's behavior - `zbm`: Adjusting ZFSBootMenu's behavior
- `zfs`: A change to how ZFS interacts with the system, either a pool or a dataset - `zfs`: A change to how ZFS interacts with the system, either a pool or a dataset
- `os`: Getting an operating system set up to correctly work in a ZFS boot environment - `os`: Getting an operating system set up to correctly work in a ZFS boot environment

View File

@@ -38,18 +38,23 @@ function we_are_changerooted () {
fi fi
} }
function set_ntp () { funcion no_kernel_update_in_iso () {
#1.1 #1.1
sed -r -e 's'$'\x1''#(IgnorePkg)[^\r\n\f]+'$'\x1''\1 = linux linux-headers'$'\x1''g' /etc/pacman.conf
}
function set_ntp () {
#1.2
timedatectl set-ntp true timedatectl set-ntp true
} }
function resize_cow_space () { function resize_cow_space () {
#1.2 #1.3
mount -o remount,size='50%' /run/archiso/cowspace mount -o remount,size='50%' /run/archiso/cowspace
} }
function update_pacman_db () { function update_pacman_db () {
#1.3 #1.4
printf -- '%s\n' 'Refreshing mirror list ...' printf -- '%s\n' 'Refreshing mirror list ...'
systemctl start reflector systemctl start reflector
# In an ISO and for the minimal number of packages we need we do not # In an ISO and for the minimal number of packages we need we do not
@@ -58,13 +63,13 @@ function update_pacman_db () {
} }
function install_pkgs () { function install_pkgs () {
#1.4 #1.5
printf -- '%s\n' 'Installing packages ...' printf -- '%s\n' 'Installing packages ...'
pacman -S --needed --noconfirm "${@}" pacman -S --needed --noconfirm "${@}"
} }
function install_zfs () { function install_zfs () {
#1.5 #1.6
declare reset_colors='\033[0m' declare reset_colors='\033[0m'
curl -s 'https://raw.githubusercontent.com/eoli3n/archiso-zfs/master/init' | bash curl -s 'https://raw.githubusercontent.com/eoli3n/archiso-zfs/master/init' | bash
printf -- "${reset_colors}" printf -- "${reset_colors}"
@@ -229,7 +234,7 @@ function create_pool () {
} }
function create_root_dataset () { function create_root_dataset () {
zfs create -o mountpoint=none -o canmount=off "${zpool_name}"'/root' zfs create -o 'mountpoint=none' -o 'canmount=off' "${zpool_name}"'/root'
# zfs set org.zfsbootmenu:commandline="ro quiet" "${zpool_name}"'/root' # zfs set org.zfsbootmenu:commandline="ro quiet" "${zpool_name}"'/root'
zfs set org.zfsbootmenu:commandline="ro" "${zpool_name}"'/root' zfs set org.zfsbootmenu:commandline="ro" "${zpool_name}"'/root'
} }
@@ -251,7 +256,7 @@ function export_pool () {
} }
function setup_zpool () { function setup_zpool () {
#1.6 #1.7
local drive_by_id local drive_by_id
zpool_drive="$(select_part 'zfs')" zpool_drive="$(select_part 'zfs')"
drive_by_id="$(get_drive_id "${zpool_drive}")" drive_by_id="$(get_drive_id "${zpool_drive}")"
@@ -271,7 +276,7 @@ function setup_zpool () {
} }
function mount_system () { function mount_system () {
#1.7 #1.8
zfs mount "${zpool_name}"'/root/'"${zfs_arch_dataset_name}" zfs mount "${zpool_name}"'/root/'"${zfs_arch_dataset_name}"
zfs mount -a zfs mount -a
@@ -284,7 +289,7 @@ function mount_system () {
} }
function copy_zpool_cache () { function copy_zpool_cache () {
#1.8 #1.9
mkdir -p '/mnt/etc/zfs' mkdir -p '/mnt/etc/zfs'
zpool set 'cachefile=/etc/zfs/'"${zpool_name}"'.cache' "${zpool_name}" zpool set 'cachefile=/etc/zfs/'"${zpool_name}"'.cache' "${zpool_name}"
} }
@@ -304,7 +309,7 @@ function pacman_dont_check_space () {
} }
function install_archlinux () { function install_archlinux () {
#1.9 #1.10
pacman_dl_parallel pacman_dl_parallel
pacman_dont_check_space pacman_dont_check_space
pacstrap /mnt \ pacstrap /mnt \
@@ -331,7 +336,7 @@ function install_archlinux () {
} }
function gen_fstab () { function gen_fstab () {
#1.10 #1.11
genfstab -U /mnt | grep -v "${zpool_name}" | tr -s '\n' | sed -r -e 's/\/mnt//' -e '/./,$!d' > '/mnt/etc/fstab' genfstab -U /mnt | grep -v "${zpool_name}" | tr -s '\n' | sed -r -e 's/\/mnt//' -e '/./,$!d' > '/mnt/etc/fstab'
} }
@@ -344,7 +349,7 @@ EOF
} }
function set_hostname () { function set_hostname () {
#1.11 #1.12
declare new_hostname declare new_hostname
install_pkgs 'pwgen' install_pkgs 'pwgen'
new_hostname="$(pwgen --no-numerals --no-capitalize --ambiguous 8)" new_hostname="$(pwgen --no-numerals --no-capitalize --ambiguous 8)"
@@ -353,7 +358,7 @@ function set_hostname () {
} }
function set_locale () { function set_locale () {
#1.12 #1.13
printf -- '%s\n' \ printf -- '%s\n' \
'KEYMAP=de-latin1' \ 'KEYMAP=de-latin1' \
'FONT=Lat2-Terminus16' \ 'FONT=Lat2-Terminus16' \
@@ -364,7 +369,7 @@ function set_locale () {
} }
function add_zfs_hook_to_initramfs () { function add_zfs_hook_to_initramfs () {
#1.13 #1.14
# Add zfs hook, remove fsck hook from initramfs. # Add zfs hook, remove fsck hook from initramfs.
sed -ri \ sed -ri \
-e 's'$'\x1''(HOOKS=)(.*?[\(| ])(filesystems)([\)| ][^\r\n\f]*)'$'\x1''\1\2zfs \3\4'$'\x1''g' \ -e 's'$'\x1''(HOOKS=)(.*?[\(| ])(filesystems)([\)| ][^\r\n\f]*)'$'\x1''\1\2zfs \3\4'$'\x1''g' \
@@ -379,7 +384,7 @@ function add_zfs_hook_to_initramfs () {
} }
function set_initramfs_build_list () { function set_initramfs_build_list () {
#1.14 #1.15
# No need to build fallback initramfs, our new fallback is ZFS snapshots # No need to build fallback initramfs, our new fallback is ZFS snapshots
sed -ri \ sed -ri \
-e '/^#/d' \ -e '/^#/d' \
@@ -393,7 +398,7 @@ function set_initramfs_build_list () {
} }
function add_zfs_files_to_new_os () { function add_zfs_files_to_new_os () {
#1.15 #1.16
for zfs_file in '/etc/hostid' '/etc/zfs/zpool.cache' $([[ ! "${ARCHZBM_ZFSPROPS_NO_ENCRYPTION}" ]] && printf -- '%s' '/etc/zfs/'"${zpool_name}"'.key'); do for zfs_file in '/etc/hostid' '/etc/zfs/zpool.cache' $([[ ! "${ARCHZBM_ZFSPROPS_NO_ENCRYPTION}" ]] && printf -- '%s' '/etc/zfs/'"${zpool_name}"'.key'); do
rsync -av --itemize-changes {'','/mnt'}"${zfs_file}" rsync -av --itemize-changes {'','/mnt'}"${zfs_file}"
done done
@@ -738,21 +743,22 @@ function main () {
if we_are_changerooted; then if we_are_changerooted; then
install_os_in_chroot #2.2 install_os_in_chroot #2.2
else else
set_ntp #1.1 no_kernel_update_in_iso #1.1
resize_cow_space #1.2 set_ntp #1.2
update_pacman_db #1.3 resize_cow_space #1.3
install_pkgs 'base-devel' 'git' 'jq' #1.4 update_pacman_db #1.4
install_zfs #1.5 install_pkgs 'base-devel' 'git' 'jq' #1.5
setup_zpool #1.6 install_zfs #1.6
mount_system #1.7 setup_zpool #1.7
copy_zpool_cache #1.8 mount_system #1.8
install_archlinux #1.9 copy_zpool_cache #1.9
gen_fstab #1.10 install_archlinux #1.10
set_hostname #1.11 gen_fstab #1.11
set_locale #1.12 set_hostname #1.12
add_zfs_hook_to_initramfs #1.13 set_locale #1.13
set_initramfs_build_list #1.14 add_zfs_hook_to_initramfs #1.14
add_zfs_files_to_new_os #1.15 set_initramfs_build_list #1.15
add_zfs_files_to_new_os #1.16
enter_chroot #2.1 enter_chroot #2.1
# We're done in chroot # We're done in chroot
finalize_os_setup #3.1 finalize_os_setup #3.1