diff --git a/docs/Getting Started/Arch Linux/Arch Linux Root on ZFS.rst b/docs/Getting Started/Arch Linux/Arch Linux Root on ZFS.rst index acb3a08..714e3f2 100644 --- a/docs/Getting Started/Arch Linux/Arch Linux Root on ZFS.rst +++ b/docs/Getting Started/Arch Linux/Arch Linux Root on ZFS.rst @@ -73,6 +73,9 @@ without the passphrase being entered at the console. Performance is good. As the encryption happens in ZFS, even if multiple disks (mirror or raidz topologies) are used, the data only has to be encrypted once. +Boot pool can be optionally encrypted with LUKS, see `here <#encrypt-boot-pool-with-luks>`__. +Encrypted boot pool can protect initrd from tempering. + Preinstallation ---------------- Download Arch Linux live image @@ -291,6 +294,9 @@ Format and Partition the Target Disks sgdisk -n4:0:0 -t4:8308 $DISK Adjust the swap partition size to your needs. + If `hibernation <#hibernation>`__ is needed, + swap size should be same or larger than RAM. + Check RAM size with ``free -h``. #. Repeat the above steps for other target disks, if any. @@ -322,6 +328,7 @@ Create Root and Boot Pools zpool create \ -o ashift=12 \ + -o autotrim=on \ -d -o feature@async_destroy=enabled \ -o feature@bookmarks=enabled \ -o feature@embedded_data=enabled \ @@ -374,12 +381,12 @@ Create Root and Boot Pools “invalid dnode type” error. This feature does not matter for ``/boot`` anyway. -#. Create root pool: - - - Unencrypted:: +#. Create root pool:: zpool create \ -o ashift=12 \ + -o autotrim=on \ + -R $INST_MNT \ -O acltype=posixacl \ -O canmount=off \ -O compression=zstd \ @@ -388,26 +395,6 @@ Create Root and Boot Pools -O relatime=on \ -O xattr=sa \ -O mountpoint=/ \ - -R $INST_MNT \ - rpool_$INST_UUID \ - ${DISK}-part3 - - - Encrypted:: - - zpool create \ - -o ashift=12 \ - -O acltype=posixacl \ - -O canmount=off \ - -O compression=zstd \ - -O dnodesize=auto \ - -O normalization=formD \ - -O relatime=on \ - -O xattr=sa \ - -O mountpoint=/ \ - -R $INST_MNT \ - -O encryption=on \ - -O keylocation=prompt \ - -O keyformat=passphrase \ rpool_$INST_UUID \ ${DISK}-part3 @@ -474,36 +461,81 @@ Create Root and Boot Pools Create Datasets ~~~~~~~~~~~~~~~~~~~~~~ +#. Create system boot container:: + + zfs create \ + -o canmount=off \ + -o mountpoint=/boot \ + bpool_$INST_UUID/sys + +#. Create system root container: + + Dataset encryption is set at creation and can not be altered later, + but encrypted dataset can be created inside an unencrypted parent dataset. + + - Unencrypted:: + + zfs create \ + -o canmount=off \ + -o mountpoint=/ \ + rpool_$INST_UUID/sys + + - Encrypted: + + #. Choose a strong password. + + Once the password is compromised, + dataset and pool must be destroyed, + disk wiped and system rebuilt from scratch to protect confidentiality. + `Merely changing password is not enough `__. + + Example: generate passphrase with `xkcdpass `_:: + + pacman -S --noconfirm xkcdpass + xkcdpass -Vn 10 -w /usr/lib/python*/site-packages/xkcdpass/static/eff-long + + Password can be supplied with SSH at boot time, + see `Supply password with SSH <#supply-password-with-ssh>`__. + + #. Create dataset:: + + zfs create \ + -o canmount=off \ + -o mountpoint=/ \ + -o encryption=on \ + -o keylocation=prompt \ + -o keyformat=passphrase \ + rpool_$INST_UUID/sys #. Create container datasets:: - zfs create -o canmount=off -o mountpoint=none bpool_$INST_UUID/BOOT - zfs create -o canmount=off -o mountpoint=none rpool_$INST_UUID/ROOT - zfs create -o canmount=off -o mountpoint=none rpool_$INST_UUID/DATA + zfs create -o canmount=off -o mountpoint=none bpool_$INST_UUID/sys/BOOT + zfs create -o canmount=off -o mountpoint=none rpool_$INST_UUID/sys/ROOT + zfs create -o canmount=off -o mountpoint=none rpool_$INST_UUID/sys/DATA #. Create root and boot filesystem datasets:: - zfs create -o mountpoint=legacy -o canmount=noauto bpool_$INST_UUID/BOOT/default - zfs create -o mountpoint=/ -o canmount=noauto rpool_$INST_UUID/ROOT/default + zfs create -o mountpoint=legacy -o canmount=noauto bpool_$INST_UUID/sys/BOOT/default + zfs create -o mountpoint=/ -o canmount=noauto rpool_$INST_UUID/sys/ROOT/default #. Mount root and boot filesystem datasets:: - zfs mount rpool_$INST_UUID/ROOT/default + zfs mount rpool_$INST_UUID/sys/ROOT/default mkdir $INST_MNT/boot - mount -t zfs bpool_$INST_UUID/BOOT/default $INST_MNT/boot + mount -t zfs bpool_$INST_UUID/sys/BOOT/default $INST_MNT/boot #. Create datasets to separate user data from root filesystem:: - zfs create -o mountpoint=/ -o canmount=off rpool_$INST_UUID/DATA/default + zfs create -o mountpoint=/ -o canmount=off rpool_$INST_UUID/sys/DATA/default for i in {usr,var,var/lib}; do - zfs create -o canmount=off rpool_$INST_UUID/DATA/default/$i + zfs create -o canmount=off rpool_$INST_UUID/sys/DATA/default/$i done for i in {home,root,srv,usr/local,var/log,var/spool,var/tmp}; do - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/$i + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/$i done chmod 750 $INST_MNT/root @@ -513,32 +545,32 @@ Create Datasets If this system will have games installed:: - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/var/games + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/var/games If you use /var/www on this system:: - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/var/www + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/var/www If this system will use GNOME:: - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/var/lib/AccountsService + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/var/lib/AccountsService If this system will use Docker (which manages its own datasets & snapshots):: - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/var/lib/docker + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/var/lib/docker If this system will use NFS (locking):: - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/var/lib/nfs + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/var/lib/nfs If this system will use Linux Containers:: - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/var/lib/lxc + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/var/lib/lxc If this system will use libvirt:: - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/var/lib/libvirt + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/var/lib/libvirt Format and Mount EFI System Partition ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -566,27 +598,27 @@ Package Installation | sed "s|.*${INST_LINVAR}=||" \ | awk '{ print $1 }') -#. Install kernel:: +#. Install kernel. Download from archive if kernel is not available:: + if [ ${INST_LINVER} == \ + $(pacman -Si ${INST_LINVAR} | grep Version | awk '{ print $3 }') ]; then + pacstrap $INST_MNT ${INST_LINVAR} + else pacstrap -U $INST_MNT \ https://archive.archlinux.org/packages/l/${INST_LINVAR}/${INST_LINVAR}-${INST_LINVER}-x86_64.pkg.tar.zst + fi #. Install archzfs package:: pacstrap $INST_MNT zfs-$INST_LINVAR -#. If your computer has hardware that requires firmware to run:: +#. Install firmware:: - pacstrap $INST_MNT linux-firmware + pacstrap $INST_MNT linux-firmware intel-ucode amd-ucode #. If you boot your computer with EFI:: - pacstrap $INST_MNT dosfstools efibootmgr - -#. Microcode: - - - ``pacstrap $INST_MNT amd-ucode`` - - ``pacstrap $INST_MNT intel-ucode`` + pacstrap $INST_MNT efibootmgr #. For other optional packages, see `ArchWiki `__. @@ -614,13 +646,13 @@ System Configuration #. Generate fstab:: - echo bpool_$INST_UUID/BOOT/default /boot zfs rw,xattr,posixacl 0 0 >> $INST_MNT/etc/fstab + echo bpool_$INST_UUID/sys/BOOT/default /boot zfs rw,xattr,posixacl 0 0 >> $INST_MNT/etc/fstab echo UUID=$(blkid -s UUID -o value ${DISK}-part1) /boot/efi vfat \ x-systemd.idle-timeout=1min,x-systemd.automount,noauto,umask=0022,fmask=0022,dmask=0022 0 1 >> $INST_MNT/etc/fstab If a swap partition has been created:: - echo crypt-swap ${DISK}-part4 /dev/urandom swap,cipher=aes-cbc-essiv:sha256,size=256 >> $INST_MNT/etc/crypttab + echo crypt-swap ${DISK}-part4 /dev/urandom swap,cipher=aes-cbc-essiv:sha256,size=256,discard >> $INST_MNT/etc/crypttab echo /dev/mapper/crypt-swap none swap defaults 0 0 >> $INST_MNT/etc/fstab #. Configure mkinitcpio:: @@ -790,6 +822,50 @@ Generate GRUB Boot Menu grub-mkconfig -o /boot/grub/grub.cfg +Optional Configuration +---------------------- + +Supply password with SSH +~~~~~~~~~~~~~~~~~~~~~~~~ + +Optional: + +#. Install mkinitcpio tools:: + + pacman -S mkinitcpio-netconf mkinitcpio-dropbear openssh + +#. Store public keys in ``/etc/dropbear/root_key``:: + + vi /etc/dropbear/root_key + + Note that dropbear only supports RSA keys. + +#. Edit mkinitcpio:: + + tee /etc/mkinitcpio.conf <<- 'EOF' + HOOKS=(base udev autodetect modconf block keyboard netconf dropbear zfsencryptssh zfs filesystems) + EOF + +#. Add ``ip=`` to kernel command line:: + + # example DHCP + echo 'GRUB_CMDLINE_LINUX="ip=::::::dhcp"' >> /etc/default/grub + + Details for ``ip=`` can be found at + `here `__. + +#. Generate host keys:: + + ssh-keygen -Am pem + +#. Regenerate initramfs:: + + mkinitcpio -P + +#. Update GRUB menu:: + + grub-mkconfig -o /boot/grub/grub.cfg + Finish Installation ------------------- @@ -799,8 +875,8 @@ Finish Installation #. Take a snapshot of the clean installation for future use:: - zfs snapshot -r rpool_$INST_UUID/ROOT/default@install - zfs snapshot -r bpool_$INST_UUID/BOOT/default@install + zfs snapshot -r rpool_$INST_UUID/sys/ROOT/default@install + zfs snapshot -r bpool_$INST_UUID/sys/BOOT/default@install #. Unmount EFI system partition:: @@ -838,18 +914,18 @@ Mirror EFI System Partition #. Create a service to monitor and sync EFI partitions:: - tee /usr/lib/systemd/system/boot/efis-sync.path << EOF + tee /etc/systemd/system/efis-sync.path << EOF [Unit] Description=Monitor changes in EFI system partition [Path] - PathModified=/boot/efi/EFI/arch/ - + PathChanged=/boot/efi/EFI/arch/ + #PathChanged=/boot/efi/EFI/BOOT/ [Install] WantedBy=multi-user.target EOF - tee /usr/lib/systemd/system/boot/efis-sync.service << EOF + tee /etc/systemd/system/efis-sync.service << EOF [Unit] Description=Sync EFI system partition contents to backups @@ -878,72 +954,6 @@ This need to be manually applied when GRUB is updated. grub-install /dev/disk/by-id/$i done -Change encryption method -~~~~~~~~~~~~~~~~~~~~~~~~ - -By default the root pool is encrypted with a key file, -created at installation. - -Password -^^^^^^^^ - -After installation, encryption by password can be enabled with:: - - zfs change-key -l -o keylocation=prompt -o keyformat=passphrase rpool_$INST_UUID - -See ``man 8 zfs-change-key``. -If password is enabled, the system will require this password to boot. -Password can be entered locally with keyboard or remotely with SSH. - -Supply password with SSH -^^^^^^^^^^^^^^^^^^^^^^^^ - -#. Install mkinitcpio tools:: - - pacman -S mkinitcpio-netconf mkinitcpio-dropbear - -#. Store authorized keys in ``/etc/dropbear/root_key``:: - - vi /etc/dropbear/root_key - - Note that dropbear only supports RSA keys. - -#. Edit mkinitcpio:: - - tee /etc/mkinitcpio.conf <<- 'EOF' - HOOKS=(base udev autodetect modconf block keyboard netconf dropbear zfsencryptssh zfs filesystems) - EOF - -#. Add ``ip=`` to kernel command line:: - - # example DHCP - echo 'GRUB_CMDLINE_LINUX="ip=::::::dhcp"' >> /etc/default/grub - - Details for ``ip=`` can be found at - `here `__. - -#. If using OpenSSH as SSH server, convert host keys to PEM format:: - - for i in {rsa,dsa,ecdsa,ed25519}; do - ssh-keygen -p -m PEM -f /etc/ssh/ssh_host_${i}_key -qN "" - done - -#. Regenerate initramfs:: - - mkinitcpio -P - -#. Update GRUB menu:: - - grub-mkconfig -o /boot/grub/grub.cfg - -Key file -^^^^^^^^ - -You can also set a new key file for root pool and -store the key file on an external drive:: - - zfs change-key -l -o keylocation=file:///path/to/keyfile -o keyformat=raw rpool_$INST_UUID - Boot Environment Manager ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -963,68 +973,371 @@ see `ArchWiki `__. + +Encrypted boot pool protects initramfs from +malicious modification and supports hibernation +to encrypted swap. + +#. Create encryption keys:: + + mkdir /etc/cryptkey.d/ + chmod 700 /etc/cryptkey.d/ + dd bs=32 count=1 if=/dev/urandom of=/etc/cryptkey.d/lukskey-bpool_$INST_UUID + dd bs=32 count=1 if=/dev/urandom of=/etc/cryptkey.d/zfskey-rpool_$INST_UUID + +#. Backup boot pool:: + + zfs snapshot -r bpool_$INST_UUID/sys@pre-luks + zfs send -R bpool_$INST_UUID/sys@pre-luks > /root/bpool_$INST_UUID-pre-luks + +#. Check boot pool creation command:: + + zpool history bpool_$INST_UUID | head -n2 \ + | grep 'zpool create' > /root/bpool_$INST_UUID-cmd + + Note the vdev disks at the end of the command. + +#. Unmount EFI partition:: + + umount /boot/efi + umount /boot/efis/* # if backups exist + +#. Destroy boot pool:: + + zpool destroy bpool_$INST_UUID + +#. Enter LUKS password:: + + LUKS_PWD=rootpool + +#. Create LUKS containers:: + + for i in {disk1,disk2}; do + cryptsetup luksFormat -q --type luks1 /dev/disk/by-id/$i-part2 --key-file /etc/cryptkey.d/lukskey-bpool_$INST_UUID + echo $LUKS_PWD | cryptsetup luksAddKey /dev/disk/by-id/$i-part2 --key-file /etc/cryptkey.d/lukskey-bpool_$INST_UUID + cryptsetup open /dev/disk/by-id/$i-part2 luks-bpool_$INST_UUID-$i-part2 --key-file /etc/cryptkey.d/lukskey-bpool_$INST_UUID + echo luks-bpool_$INST_UUID-$i-part2 /dev/disk/by-id/$i-part2 /etc/cryptkey.d/lukskey-bpool_$INST_UUID discard >> /etc/crypttab + done + +#. Embed key file in initramfs:: + + tee -a /etc/mkinitcpio.conf <> /etc/default/grub + +#. Install GRUB. See `GRUB Installation <#grub-installation>`__. + +#. Generate GRUB menu:: + + grub-mkconfig -o /boot/grub/grub.cfg + +#. **Important**: Back up root dataset key ``/etc/cryptkey.d/zfskey-rpool_$INST_UUID`` + to a secure location. + + In the possible event of LUKS container corruption, + data on root set will only be available + with this key. + +Secure Boot +~~~~~~~~~~~ +Recommended: With Secure Boot + encrypted boot pool + encrypted root dataset, +a chain-of-trust can be established. + +#. Sign boot loader + + - Use boot loader signed by Microsoft + + Using a boot loader signed with Microsoft's key is the + simplest and most direct approach to booting with Secure Boot active; + however, it's also the most limiting approach. + + Use `shim-signed `__\ :sup:`AUR` + and sign ``grubx64.efi`` with machine owner key. + See `here `__. + + - Customized Secure Boot + + It's possible to replace Microsoft's keys with your own, + which enables you to gain the benefits of Secure Boot + without using either Shim. This can be a + useful approach if you want the benefits of Secure Boot + but don't want to trust Microsoft or any of the others + who distribute binaries signed with Microsoft's keys. + + See `here `__. + +#. Set up a service to monitor and sign ``grubx64.efi``, + as in `mirrored ESP <#mirror-efi-system-partition>`__. + +Hibernation +~~~~~~~~~~~ + +If a separate swap partition and +`encrypted boot pool <#encrypt-boot-pool-with-LUKS>`__ +have been configured, hibernation, +also known as suspend-to-disk, can be enabled. + +#. Unload swap:: + + swapoff /dev/mapper/crypt-swap + cryptsetup close crypt-swap + +#. Check partition name and remove crypttab entry:: + + grep crypt-swap /etc/crypttab | awk '{ print $2 }' + # ${DISK}-part4 + DISK=/dev/disk/by-id/nvme-foo # NO -part4 + sed -i 's|crypt-swap.*||' /etc/crypttab + + Swap will be handled by ``encrypt`` initramfs hook. + +#. Create LUKS container:: + + dd bs=32 count=1 if=/dev/urandom of=/etc/cryptkey.d/lukskey-crypt-swap + cryptsetup luksFormat -q --type luks2 ${DISK}-part4 --key-file /etc/cryptkey.d/lukskey-crypt-swap + cryptsetup luksOpen ${DISK}-part4 crypt-swap --key-file /etc/cryptkey.d/lukskey-crypt-swap --allow-discards + mkswap /dev/mapper/crypt-swap + swapon /dev/mapper/crypt-swap + +#. Configure mkinitcpio:: + + sed -i 's|FILES=(|FILES=(/etc/cryptkey.d/lukskey-crypt-swap |' /etc/mkinitcpio.conf + sed -i 's| zfs | encrypt resume zfs |' /etc/mkinitcpio.conf + +#. Add kernel command line:: + + echo "GRUB_CMDLINE_LINUX=\"cryptdevice=PARTUUID=$(blkid -s PARTUUID -o value ${DISK}-part4):crypt-swap:allow-discards \ + cryptkey=rootfs:/etc/cryptkey.d/lukskey-crypt-swap \ + resume=/dev/mapper/crypt-swap\"" >> /etc/default/grub + +#. Regenerate initramfs and GRUB menu:: + + mkinitcpio -P + grub-mkconfig -o /boot/grub/grub.cfg + +#. Test hibernation:: + + systemctl hibernate + + Close all program before testing, just in case. + + If hibernation works, your computer will shut down. + Power it on. Computer should return to the previous state + seamlessly. + +Enter LUKS password in GRUB rescue +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Using LUKS encryption for boot pool, +if the password entered is wrong, GRUB +will drop to ``grub-rescue``:: + + Attempting to decrypt master key... + Enter passphrase for hd0,gpt2 (c0987ea1a51049e9b3056622804de62a): + error: access denied. + error: no such cryptodisk found. + Entering rescue mode... + grub rescue> + +Try entering the password again with:: + + grub rescue> cryptomount hd0,gpt2 + Attempting to decrypt master key... + Enter passphrase for hd0,gpt2 (c0987ea1a51049e9b3056622804de62a): + Slot 1 opened + grub rescue> insmod normal + grub rescue> normal + +GRUB should then boot normally. + +Change GRUB prefix when disk fails +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Using encryption, when +disk failed, GRUB might fail to boot. + +.. code-block:: text + + Welcome to GRUB! + + error: no such cryptodisk found. + Attempting to decrypt master key... + Enter passphrase for hd0,gpt2 (c0987ea1a51049e9b3056622804de62a): + Slot 1 opened + error: disk `cryptouuid/47ed1b7eb0014bc9a70aede3d8714faf' not found. + Entering rescue mode... + grub rescue> + +Ensure ``Slot 1 opened`` message +is shown. If ``error: access denied.`` is shown, +the password entered is wrong. + +#. Check prefix:: + + grub rescue > set + # prefix=(cryptouuid/47ed1b7eb0014bc9a70aede3d8714faf)/sys/BOOT/default@/grub + # root=cryptouuid/47ed1b7eb0014bc9a70aede3d8714faf + +#. Replace ``cryptouuid/UUID`` with ``crypto0``:: + + grub rescue> prefix=(crypto0)/sys/BOOT/default@/grub + grub rescue> root=crypto0 + +#. Boot GRUB:: + + grub rescue> insmod normal + grub rescue> normal + +GRUB should then boot normally. After entering system, +promote one backup to ``/boot/efi`` and reinstall GRUB with +``grub-install``. + Recovery -------- Load grub.cfg in GRUB command line ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Boot environment menu is stored in ``/boot/grub.cfg``. -But the absolute path of ``grub.cfg`` will -change when you enter another boot environment, -from ``bpool/BOOT/default/@/boot/grub.cfg`` to -``bpool/BOOT/bootenv1/@/boot/grub.cfg``. +#. Press ``c`` at GRUB menu. -This absolute path is stored in the bootloader file: -``grubx64.efi`` for EFI booting, or inside the first sector of the -disk for BIOS booting. +#. Check prefix:: -GRUB will load the wrong ``grub.cfg`` if the bootloader -file has not been updated upon entering another boot environment. -Following are the steps to load the correct ``grub.cfg``, - -#. Enter GRUB command line - - No additional steps if you are already in GRUB rescue. - Otherwise, press ``c`` at the GRUB menu. - -#. List available partitions:: - - grub > ls - (hd0) (hd0,gpt4) (hd0,gpt3) (hd0,gpt2) (hd0,gpt1) (hd1) (hd1,gpt5) ... - - Boot pool is always ``(hdx,gpt2)``:: - - grub > ls (hd0, # press tab after comma - Possible partitions are: - - Partition hd0,gpt1: Filesystem type fat - Label 'EFI', UUID ... - Partition hd0,gpt2: Filesystem type zfs - Label 'bpool' - Last modification time ... - Partition hd0,gpt3: No known filesystem detected ... + grub > set + # ... + # unencrypted bpool + # prefix=(hd0,gpt2)/sys/BOOT/default@/grub + # encrypted bpool + # prefix=(cryptouuid/UUID)/sys/BOOT/default@/grub #. List available boot environments:: - grub > ls (hd0,gpt2) # press tab after bracket - Possible files are: - - @/ BOOT/ - - grub > ls (hd0,gpt2)/BOOT # press tab after 'T' + # unencrypted bpool + grub > ls (hd0,gpt2)/sys/BOOT # press tab after 'T' + # encrypted bpool + grub > ls (crypto0)/sys/BOOT # press tab after 'T' Possible files are: @/ default/ pac-multm2/ -#. Load grub.cfg +#. Set new prefix:: - To load from ``default`` boot environment, append - ``default/@/grub/grub.cfg`` to the last ``ls`` command. + # unencrypted bpool + grub > prefix=(hd0,gpt2)/sys/BOOT/pac-multm2@/grub + # encrypted bpool + grub > prefix=(crypto0)/sys/BOOT/pac-multm2@/grub - Then press ``home`` on the keyboard to move - cursor to the start of the line. +#. Load config from new prefix:: - Change ``ls`` to ``configfile`` and press return:: + grub > normal - grub > configfile (hd0,gpt2)/BOOT/default/@/grub/grub.cfg + New entries are shown below the old ones. Rescue in Live Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1040,10 +1353,6 @@ Rescue in Live Environment INST_MNT=$(mktemp -d) INST_UUID=abc123 -#. If using other keyfile:: - - KEYFILE=/path/to/keyfile - #. Import and unlock root and boot pool:: zpool import -N -R $INST_MNT rpool_$INST_UUID @@ -1051,20 +1360,20 @@ Rescue in Live Environment If using password:: - zfs load-key rpool_$INST_UUID + zfs load-key rpool_$INST_UUID/sys If using keyfile:: - zfs load-key -L file://$KEYFILE rpool_$INST_UUID + zfs load-key -L file:///path/to/keyfile rpool_$INST_UUID/sys #. Find the current boot environment:: zfs list BE=default -#. Mount boot and root filesystem:: +#. Mount root filesystem:: - zfs mount rpool_$INST_UUID/ROOT/$BE + zfs mount rpool_$INST_UUID/sys/ROOT/$BE #. chroot into the system:: diff --git a/docs/Getting Started/Arch Linux/Artix Linux Root on ZFS.rst b/docs/Getting Started/Arch Linux/Artix Linux Root on ZFS.rst index c7df068..be00547 100644 --- a/docs/Getting Started/Arch Linux/Artix Linux Root on ZFS.rst +++ b/docs/Getting Started/Arch Linux/Artix Linux Root on ZFS.rst @@ -320,6 +320,7 @@ Create Root and Boot Pools zpool create \ -o ashift=12 \ + -o autotrim=on \ -d -o feature@async_destroy=enabled \ -o feature@bookmarks=enabled \ -o feature@embedded_data=enabled \ @@ -372,12 +373,12 @@ Create Root and Boot Pools “invalid dnode type” error. This feature does not matter for ``/boot`` anyway. -#. Create root pool: - - - Unencrypted:: +#. Create root pool:: zpool create \ -o ashift=12 \ + -o autotrim=on \ + -R $INST_MNT \ -O acltype=posixacl \ -O canmount=off \ -O compression=zstd \ @@ -386,26 +387,6 @@ Create Root and Boot Pools -O relatime=on \ -O xattr=sa \ -O mountpoint=/ \ - -R $INST_MNT \ - rpool_$INST_UUID \ - ${DISK}-part3 - - - Encrypted:: - - zpool create \ - -o ashift=12 \ - -O acltype=posixacl \ - -O canmount=off \ - -O compression=zstd \ - -O dnodesize=auto \ - -O normalization=formD \ - -O relatime=on \ - -O xattr=sa \ - -O mountpoint=/ \ - -R $INST_MNT \ - -O encryption=on \ - -O keylocation=prompt \ - -O keyformat=passphrase \ rpool_$INST_UUID \ ${DISK}-part3 @@ -472,36 +453,81 @@ Create Root and Boot Pools Create Datasets ~~~~~~~~~~~~~~~~~~~~~~ +#. Create system boot container:: + + zfs create \ + -o canmount=off \ + -o mountpoint=/boot \ + bpool_$INST_UUID/sys + +#. Create system root container: + + Dataset encryption is set at creation and can not be altered later, + but encrypted dataset can be created inside an unencrypted parent dataset. + + - Unencrypted:: + + zfs create \ + -o canmount=off \ + -o mountpoint=/ \ + rpool_$INST_UUID/sys + + - Encrypted: + + #. Choose a strong password. + + Once the password is compromised, + dataset and pool must be destroyed, + disk wiped and system rebuilt from scratch to protect confidentiality. + `Merely changing password is not enough `__. + + Example: generate passphrase with `xkcdpass `_:: + + pacman -S --noconfirm xkcdpass + xkcdpass -Vn 10 -w /usr/lib/python*/site-packages/xkcdpass/static/eff-long + + Password can be supplied with SSH at boot time, + see `Supply password with SSH <#supply-password-with-ssh>`__. + + #. Create dataset:: + + zfs create \ + -o canmount=off \ + -o mountpoint=/ \ + -o encryption=on \ + -o keylocation=prompt \ + -o keyformat=passphrase \ + rpool_$INST_UUID/sys #. Create container datasets:: - zfs create -o canmount=off -o mountpoint=none bpool_$INST_UUID/BOOT - zfs create -o canmount=off -o mountpoint=none rpool_$INST_UUID/ROOT - zfs create -o canmount=off -o mountpoint=none rpool_$INST_UUID/DATA + zfs create -o canmount=off -o mountpoint=none bpool_$INST_UUID/sys/BOOT + zfs create -o canmount=off -o mountpoint=none rpool_$INST_UUID/sys/ROOT + zfs create -o canmount=off -o mountpoint=none rpool_$INST_UUID/sys/DATA #. Create root and boot filesystem datasets:: - zfs create -o mountpoint=legacy -o canmount=noauto bpool_$INST_UUID/BOOT/default - zfs create -o mountpoint=/ -o canmount=noauto rpool_$INST_UUID/ROOT/default + zfs create -o mountpoint=legacy -o canmount=noauto bpool_$INST_UUID/sys/BOOT/default + zfs create -o mountpoint=/ -o canmount=noauto rpool_$INST_UUID/sys/ROOT/default #. Mount root and boot filesystem datasets:: - zfs mount rpool_$INST_UUID/ROOT/default + zfs mount rpool_$INST_UUID/sys/ROOT/default mkdir $INST_MNT/boot - mount -t zfs bpool_$INST_UUID/BOOT/default $INST_MNT/boot + mount -t zfs bpool_$INST_UUID/sys/BOOT/default $INST_MNT/boot #. Create datasets to separate user data from root filesystem:: - zfs create -o mountpoint=/ -o canmount=off rpool_$INST_UUID/DATA/default + zfs create -o mountpoint=/ -o canmount=off rpool_$INST_UUID/sys/DATA/default for i in {usr,var,var/lib}; do - zfs create -o canmount=off rpool_$INST_UUID/DATA/default/$i + zfs create -o canmount=off rpool_$INST_UUID/sys/DATA/default/$i done for i in {home,root,srv,usr/local,var/log,var/spool,var/tmp}; do - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/$i + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/$i done chmod 750 $INST_MNT/root @@ -511,32 +537,32 @@ Create Datasets If this system will have games installed:: - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/var/games + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/var/games If you use /var/www on this system:: - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/var/www + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/var/www If this system will use GNOME:: - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/var/lib/AccountsService + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/var/lib/AccountsService If this system will use Docker (which manages its own datasets & snapshots):: - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/var/lib/docker + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/var/lib/docker If this system will use NFS (locking):: - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/var/lib/nfs + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/var/lib/nfs If this system will use Linux Containers:: - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/var/lib/lxc + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/var/lib/lxc If this system will use libvirt:: - zfs create -o canmount=on rpool_$INST_UUID/DATA/default/var/lib/libvirt + zfs create -o canmount=on rpool_$INST_UUID/sys/DATA/default/var/lib/libvirt Format and Mount EFI System Partition ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -550,7 +576,6 @@ Format and Mount EFI System Partition If you are using a multi-disk setup, this step will only install bootloader to the first disk. Other disks will be handled later. - Package Installation ~~~~~~~~~~~~~~~~~~~~ @@ -621,24 +646,19 @@ Package Installation Kernel must be manually updated, see kernel update section in Getting Started. -#. If your computer has hardware that requires firmware to run:: +#. Install firmware:: - basestrap $INST_MNT linux-firmware + pacstrap $INST_MNT linux-firmware intel-ucode amd-ucode #. If you boot your computer with EFI:: - basestrap $INST_MNT dosfstools efibootmgr + basestrap $INST_MNT efibootmgr #. If a swap partition has been created:: basestrap $INST_MNT cryptsetup basestrap $INST_MNT cryptsetup-openrc -#. Microcode: - - - ``pacstrap $INST_MNT amd-ucode`` - - ``pacstrap $INST_MNT intel-ucode`` - #. For other optional packages, see `ArchWiki `__. @@ -647,7 +667,7 @@ System Configuration #. Generate fstab:: - echo bpool_$INST_UUID/BOOT/default /boot zfs rw,xattr,posixacl 0 0 >> $INST_MNT/etc/fstab + echo bpool_$INST_UUID/sys/BOOT/default /boot zfs rw,xattr,posixacl 0 0 >> $INST_MNT/etc/fstab echo UUID=$(blkid -s UUID -o value ${DISK}-part1) /boot/efi vfat umask=0022,fmask=0022,dmask=0022 0 1 >> $INST_MNT/etc/fstab ``tmpfs`` for ``/tmp`` is recommended:: @@ -822,6 +842,50 @@ Generate GRUB Boot Menu grub-mkconfig -o /boot/grub/grub.cfg +Optional Configuration +---------------------- + +Supply password with SSH +~~~~~~~~~~~~~~~~~~~~~~~~ + +Optional: + +#. Install mkinitcpio tools:: + + pacman -S mkinitcpio-netconf mkinitcpio-dropbear openssh + +#. Store authorized keys in ``/etc/dropbear/root_key``:: + + vi /etc/dropbear/root_key + + Note that dropbear only supports RSA keys. + +#. Edit mkinitcpio:: + + tee /etc/mkinitcpio.conf <<- 'EOF' + HOOKS=(base udev autodetect modconf block keyboard netconf dropbear zfsencryptssh zfs filesystems) + EOF + +#. Add ``ip=`` to kernel command line:: + + # example DHCP + echo 'GRUB_CMDLINE_LINUX="ip=::::::dhcp"' >> /etc/default/grub + + Details for ``ip=`` can be found at + `here `__. + +#. Generate host keys:: + + ssh-keygen -Am pem + +#. Regenerate initramfs:: + + mkinitcpio -P + +#. Update GRUB menu:: + + grub-mkconfig -o /boot/grub/grub.cfg + Finish Installation ------------------- @@ -831,8 +895,8 @@ Finish Installation #. Take a snapshot of the clean installation for future use:: - zfs snapshot -r rpool_$INST_UUID/ROOT/default@install - zfs snapshot -r bpool_$INST_UUID/BOOT/default@install + zfs snapshot -r rpool_$INST_UUID/sys/ROOT/default@install + zfs snapshot -r bpool_$INST_UUID/sys/BOOT/default@install #. Unmount EFI system partition:: @@ -893,72 +957,6 @@ This need to be manually applied when GRUB is updated. grub-install /dev/disk/by-id/$i done -Change encryption method -~~~~~~~~~~~~~~~~~~~~~~~~ - -By default the root pool is encrypted with a key file, -created at installation. - -Password -^^^^^^^^ - -After installation, encryption by password can be enabled with:: - - zfs change-key -l -o keylocation=prompt -o keyformat=passphrase rpool_$INST_UUID - -See ``man 8 zfs-change-key``. -If password is enabled, the system will require this password to boot. -Password can be entered locally with keyboard or remotely with SSH. - -Supply password with SSH -^^^^^^^^^^^^^^^^^^^^^^^^ - -#. Install mkinitcpio tools:: - - pacman -S mkinitcpio-netconf mkinitcpio-dropbear - -#. Store authorized keys in ``/etc/dropbear/root_key``:: - - vi /etc/dropbear/root_key - - Note that dropbear only supports RSA keys. - -#. Edit mkinitcpio:: - - tee /etc/mkinitcpio.conf <<- 'EOF' - HOOKS=(base udev autodetect modconf block keyboard netconf dropbear zfsencryptssh zfs filesystems) - EOF - -#. Add ``ip=`` to kernel command line:: - - # example DHCP - echo 'GRUB_CMDLINE_LINUX="ip=::::::dhcp"' >> /etc/default/grub - - Details for ``ip=`` can be found at - `here `__. - -#. If using OpenSSH as SSH server, convert host keys to PEM format:: - - for i in {rsa,dsa,ecdsa,ed25519}; do - ssh-keygen -p -m PEM -f /etc/ssh/ssh_host_${i}_key -qN "" - done - -#. Regenerate initramfs:: - - mkinitcpio -P - -#. Update GRUB menu:: - - grub-mkconfig -o /boot/grub/grub.cfg - -Key file -^^^^^^^^ - -You can also set a new key file for root pool and -store the key file on an external drive:: - - zfs change-key -l -o keylocation=file:///path/to/keyfile -o keyformat=raw rpool_$INST_UUID - Boot Environment Manager ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -984,62 +982,25 @@ Recovery Load grub.cfg in GRUB command line ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Boot environment menu is stored in ``/boot/grub.cfg``. -But the absolute path of ``grub.cfg`` will -change when you enter another boot environment, -from ``bpool/BOOT/default/@/boot/grub.cfg`` to -``bpool/BOOT/bootenv1/@/boot/grub.cfg``. +#. Press ``c`` at GRUB menu. -This absolute path is stored in the bootloader file: -``grubx64.efi`` for EFI booting, or inside the first sector of the -disk for BIOS booting. +#. List available disks:: -GRUB will load the wrong ``grub.cfg`` if the bootloader -file has not been updated upon entering another boot environment. -Following are the steps to load the correct ``grub.cfg``, + grub > ls (hd # press tab after 'd' + Possible devices are: -#. Enter GRUB command line - - No additional steps if you are already in GRUB rescue. - Otherwise, press ``c`` at the GRUB menu. - -#. List available partitions:: - - grub > ls - (hd0) (hd0,gpt4) (hd0,gpt3) (hd0,gpt2) (hd0,gpt1) (hd1) (hd1,gpt5) ... - - Boot pool is always ``(hdx,gpt2)``:: - - grub > ls (hd0, # press tab after comma - Possible partitions are: - - Partition hd0,gpt1: Filesystem type fat - Label 'EFI', UUID ... - Partition hd0,gpt2: Filesystem type zfs - Label 'bpool' - Last modification time ... - Partition hd0,gpt3: No known filesystem detected ... + hd0 hd1 #. List available boot environments:: - grub > ls (hd0,gpt2) # press tab after bracket - Possible files are: - - @/ BOOT/ - - grub > ls (hd0,gpt2)/BOOT # press tab after 'T' + grub > ls (hd0,gpt2)/sys/BOOT # press tab after 'T' Possible files are: @/ default/ pac-multm2/ -#. Load grub.cfg +#. Load grub.cfg:: - To load from ``default`` boot environment, append - ``default/@/grub/grub.cfg`` to the last ``ls`` command. - - Then press ``home`` on the keyboard to move - cursor to the start of the line. - - Change ``ls`` to ``configfile`` and press return:: - - grub > configfile (hd0,gpt2)/BOOT/default/@/grub/grub.cfg + grub > configfile (hd0,gpt2)/sys/BOOT/default@/grub/grub.cfg Rescue in Live Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1055,10 +1016,6 @@ Rescue in Live Environment INST_MNT=$(mktemp -d) INST_UUID=abc123 -#. If using other keyfile:: - - KEYFILE=/path/to/keyfile - #. Import and unlock root and boot pool:: zpool import -N -R $INST_MNT rpool_$INST_UUID @@ -1068,18 +1025,14 @@ Rescue in Live Environment zfs load-key rpool_$INST_UUID - If using keyfile:: - - zfs load-key -L file://$KEYFILE rpool_$INST_UUID - #. Find the current boot environment:: zfs list BE=default -#. Mount boot and root filesystem:: +#. Mount root filesystem:: - zfs mount rpool_$INST_UUID/ROOT/$BE + zfs mount rpool_$INST_UUID/sys/ROOT/$BE #. chroot into the system:: diff --git a/docs/Getting Started/Arch Linux/index.rst b/docs/Getting Started/Arch Linux/index.rst index 52ed78f..11e77f2 100644 --- a/docs/Getting Started/Arch Linux/index.rst +++ b/docs/Getting Started/Arch Linux/index.rst @@ -78,10 +78,15 @@ Check compatible kernel version:: INST_LINVER=$(pacman -Si zfs-${INST_LINVAR} | grep 'Depends On' | sed "s|.*${INST_LINVAR}=||" | awk '{ print $1 }') -Install compatible kernel:: +Install kernel. Download from archive if kernel is not available:: - pacman -U \ - https://archive.archlinux.org/packages/l/${INST_LINVAR}/${INST_LINVAR}-${INST_LINVER}-x86_64.pkg.tar.zst + if [ ${INST_LINVER} == \ + $(pacman -Si ${INST_LINVAR} | grep Version | awk '{ print $3 }') ]; then + pacstrap $INST_MNT ${INST_LINVAR} + else + pacstrap -U $INST_MNT \ + https://archive.archlinux.org/packages/l/${INST_LINVAR}/${INST_LINVAR}-${INST_LINVER}-x86_64.pkg.tar.zst + fi Install archzfs::