Arch Linux: Nest system datasets for more flexibility; encryption warning messages

Arch Linux Root on ZFS: Encrypt boot pool with LUKS

Typo fixes; tweaks

Add Secure Boot

Secure Boot key enrollment differs

Secure Boot: rm HP laptop ref

Strictly follow manu. instructions. I bricked my EliteBook 820 G2 with KeyTool.efi

Example Secure Boot customization links

Back up Secure Boot signing keys

Secure Boot: Add link to bricked motherboard

Replace Secure Boot with a link; out of scope

Signed-off-by: Maurice Zhou <ja@apvc.uk>
This commit is contained in:
Maurice Zhou
2021-02-26 14:53:27 +08:00
committed by Richard Laager
parent 13271f2467
commit c25037beb0
3 changed files with 617 additions and 350 deletions

View File

@@ -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 <https://openzfs.github.io/openzfs-docs/man/8/zfs-change-key.8.html>`__.
Example: generate passphrase with `xkcdpass <https://github.com/redacted/XKCD-password-generator>`_::
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 <https://wiki.archlinux.org/index.php/Installation_guide#Installation>`__.
@@ -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 <https://www.kernel.org/doc/html/latest/admin-guide/nfs/nfsroot.html#kernel-command-line>`__.
#. 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 <https://www.kernel.org/doc/html/latest/admin-guide/nfs/nfsroot.html#kernel-command-line>`__.
#. 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 <https://wiki.archlinux.org/index.php/Installation_guide#Post-inst
Remember to create separate datasets for individual users.
Encrypt boot pool with LUKS
---------------------------
If encryption is enabled earlier, boot pool can be optionally encrypted.
This step will rebuild boot pool
on a LUKS 1 container. Password must
be entered interactively at GRUB and thus incompatible with
`Supply password with SSH <#supply-password-with-ssh>`__.
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 <<EOF
FILES=(/etc/cryptkey.d/lukskey-bpool_$INST_UUID /etc/cryptkey.d/zfskey-rpool_$INST_UUID)
EOF
#. Recreate boot pool.
Reuse command from ``/root/bpool_$INST_UUID-cmd``.
Remove ``-R $INST_MNT``
and replace devices with ``/dev/mapper/luks-bpool_$INST_UUID-$DISK-part2``.
Example::
zpool create \
-o ashift=12 \
-o autotrim=on \
-d -o feature@async_destroy=enabled \
-o feature@bookmarks=enabled \
-o feature@embedded_data=enabled \
-o feature@empty_bpobj=enabled \
-o feature@enabled_txg=enabled \
-o feature@extensible_dataset=enabled \
-o feature@filesystem_limits=enabled \
-o feature@hole_birth=enabled \
-o feature@large_blocks=enabled \
-o feature@lz4_compress=enabled \
-o feature@spacemap_histogram=enabled \
-O acltype=posixacl \
-O canmount=off \
-O compression=lz4 \
-O devices=off \
-O normalization=formD \
-O relatime=on \
-O xattr=sa \
-O mountpoint=/boot \
# remove -R $INST_MNT
bpool_$INST_UUID \
/dev/mapper/luks-bpool_$INST_UUID-$disk1-part2
#. Restore boot pool backup::
cat /root/bpool_$INST_UUID-pre-luks | zfs recv bpool_$INST_UUID/sys
#. Mount boot dataset and EFI partitions::
mount /boot
mount /boot/efi
mount /boot/efis/*
#. Change root pool password to key file::
zfs change-key -l \
-o keylocation=file:///etc/cryptkey.d/zfskey-rpool_$INST_UUID \
-o keyformat=raw \
rpool_$INST_UUID/sys
#. Remove ``zfsencryptssh`` hook.
Encrypted boot pool is incompatible with
password by SSH::
sed -i 's|zfsencryptssh||g' /etc/mkinitcpio.conf
If ``zfsencryptssh`` is not removed, initramfs will
stuck at ``fail to load key material`` and fail to boot.
#. Generate initramfs::
mkinitcpio -P
#. Import boot pool after starting systemd::
tee /etc/systemd/system/zfs-bpool-import-cache.service <<EOF
[Unit]
Description=Import boot pool by cache file
Documentation=man:zpool(8)
DefaultDependencies=no
Requires=systemd-udev-settle.service
After=zfs-import-cache.service
After=zfs-import.target
Before=boot.mount
ConditionFileNotEmpty=/etc/zfs/zpool.cache
ConditionPathIsDirectory=/sys/module/zfs
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/zpool import -c /etc/zfs/zpool.cache -aN
[Install]
WantedBy=zfs-import.target
EOF
systemctl enable zfs-bpool-import-cache.service
Initramfs will still try to import boot pool
before mapping LUKS containers. This will fail
and delay boot for a few seconds.
#. Enable GRUB cryptodisk::
echo "GRUB_ENABLE_CRYPTODISK=y" >> /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 <https://aur.archlinux.org/packages/shim-signed/>`__\ :sup:`AUR`
and sign ``grubx64.efi`` with machine owner key.
See `here <https://www.rodsbooks.com/efi-bootloaders/secureboot.html#shim>`__.
- 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 <https://www.rodsbooks.com/efi-bootloaders/controlling-sb.html>`__.
#. 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::

View File

@@ -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 <https://openzfs.github.io/openzfs-docs/man/8/zfs-change-key.8.html>`__.
Example: generate passphrase with `xkcdpass <https://github.com/redacted/XKCD-password-generator>`_::
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 <https://wiki.archlinux.org/index.php/Installation_guide#Installation>`__.
@@ -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 <https://www.kernel.org/doc/html/latest/admin-guide/nfs/nfsroot.html#kernel-command-line>`__.
#. 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 <https://www.kernel.org/doc/html/latest/admin-guide/nfs/nfsroot.html#kernel-command-line>`__.
#. 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::

View File

@@ -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 \
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::