Jump to content

User:Drack/SystemInstallation

From ArchWiki

System Installation

Arch Linux wiki provides two guides for installing an operating system:

Here is a summary of the needed steps to install a system that suits my need.

System-land

Medium preparation

Image download and installation medium creation

First, download the .iso image from an HTTP mirror and check the checksum:

   cd /tmp
   wget https://archlinux.mirrors.ovh.net/archlinux/iso/2024.03.01/archlinux-2024.03.01-x86_64.iso
   sha256sum archlinux-2024.03.01-x86_64.iso

Then, create a [bootable USB key](disk.html) with the .iso image. Once done, boot the live environment with [Secure Boot](security.html) disabled as it not supported by the Arch installation medium. The live environment should display a GRUB menu, entering then a root@archiso prompt. Start a tmux session to work easily with terminals during the installation process.


Console configuration

List available console keymaps and set wanted keyboard layout:

   ls /usr/share/kbd/keymaps/**/*.map.gz
   loadkeys fr-pc # [fr is not supporting "é" | fr-latin1 | fr-latin9 | azerty]

Boot checking

Verify the boot mode checking the UEFI bitness:

   cat /sys/firmware/efi/fw_platform_size

Depending on the returned value:

  • 64 → x64 UEFI.
  • 32 → 32-bit IA32 UEFI, which will limit the boot loader choice to GRUB.
  • Not exist → system may be booted in BIOS (or CSM) mode. If you have a UEFI/GPT system, it will rise a problem during the boot loader installation as GRUB will not use efibootmgr to create a UEFI boot entry pointing to it.

Verify the Secure Boot state and presence of cryptoprocessor:

   bootctl | grep "Secure Boot"
   bootctl | grep "TPM2"

Check that Secure Boot is disabled and that TPM2 is supported for complex setup with btrfs, LUKS, UKI, Secure Boot and TPM (See section 1.1.3).


Internet and time configuration

[Connect to the Internet](network.html), where the simplest method is using an Ethernet cable, where we just have to verify that our interface is listed and use dhclient to obtains an IP address. Or we can also use the shipped iwd to connect to a Wi-Fi network. Once connected to the network, one can enable the [OpenSSH](remote.html) service (and set a password for root) from the live system to access it remotely from another computer.

Local timezone should be synced automatically once a connection to the internet is established. You can check, or set it manually using:

   timedatectl set-timezone Europe/Paris

Choice of installation scenario

One can choose one of the following scenarios, including disk partitioning and formatting:

  1. Simple setup with ext4 and GRUB (See section 1.1.2)
  1. Complex setup with btrfs, LUKS, UKI, Secure Boot and TPM (See section 1.1.3)

Stage 1 – Simple setup

This is a simple scenario without logical volume management, without encryption, without authentication and integrity of the boot process, and with an easy installation of the traditional GRUB bootloader. Typically used for a home desktop computer, were no strong security is needed while being easily compatible with all hardware (BIOS or UEFI, MBR or GPT), features (e.g., hibernation) and repairable with traditional tools.

The following show a summary of the achieved layout:

Table of disk layout.
Mount point Partition Partition type GUID [fdisk code] Filesystem Suggested size
/mnt/boot /dev/efi_partition [EFI System Partition (ESP)](../../notes/boot.html) [1] FAT32 (vfat) Around 512 MiB
[SWAP] /dev/swap_partition Linux swap [19] ext4 At least RAM size
/mnt /dev/root_partition Linux x86-64 root (/) [23] ext4 At least 15 GiB
/mnt/home /dev/home_partition Linux home (/home) [42] ext4 Remainder of the device

![Scheme of the disk layout.](drawio/arch_linux_simple_setup_disk.drawio.svg)

![Scheme of the boot process.](drawio/arch_linux_simple_setup_boot.drawio.svg)


Disk partitioning

The first step is to partition the disk. Optionally, one can create a [RAID](disk.html) before this step, notably if multiple disks needs to be used as a single one. At least the following partitions are required for a computer:

  1. One partition for the root directory /.
  1. An [EFI System Partition (ESP)](../../notes/boot.html) for booting in UEFI mode. If the disk already has an ESP, do not create another one but use the existing partition instead.

Here, we make the following choices:

  • Use of UEFI for booting and GPT as partition table with traditional partitions.
  • We ensure the size of the ESP is enough to hold multiple kernel versions.
  • We ensure the size of the SWAP is enough to save RAM for hibernation.
  • We ensure the size of the root partition is enough to hold a full system.
  • We mount the ESP at /boot for easiest administration.

See [disk partitioning](disk.html) for details, but one can achieve the layout presented in Table 1 using [fdisk](disk.html) or [gdisk](disk.html).


Partition formatting

Once done, you will have to format the partitions. Here, we will demonstrating it using [FAT](disk.html) for the [ESP](../../notes/boot.html) and [ext4](disk.html) filesystems for system and user data:

   mkfs.fat -F 32 /dev/efi_partition # Only if it has been newly created.
   mkswap /dev/swap_partition
   mkfs.ext4 /dev/root_partition
   mkfs.ext4 /dev/home_partition

Our partitions are ready to be mounted and enabled, they will automatically be detected later by genfstab:

   mount --mkdir /dev/root_partition /mnt
   mount --mkdir /dev/home_partition /mnt/home
   mount --mkdir /dev/efi_partition /mnt/boot
   swapon /dev/swap_partition

Stage 1 – Complex setup

This setup is inspired of:

This is an advanced scenario with:

  • Logical volume management through [BtrFS](disk.html).
  • Full disk encryption though [LUKS](security.html) and [device-mapper (dm)](linux_kernel.html)'s dm-crypt.
  • Bootloader-less installation leveraging [Unified Kernel Image (UKI)](linux_kernel.html).
  • Boot process authenticity and integrity using [Secure Boot](security.html) and [TPM](../../notes/boot.html).
  • Hibernation support with [Initial RAMDisk (initramfs)](linux_kernel.html) in Systemd mode.

Typically used for traveling laptop, it provides performance and strong security, but requires recent hardware for the TPM, some features may be harder to configure, and specialized tool must be used to repair the system.

In the following, we will assume that /dev/sda is the block device that will hold our disk layout. If an installation spanning on multiple disk is needed, setup the [RAID](disk.html) in the first place and use the new mapped device instead of /dev/sda. The following show a summary of the achieved layout:

Table of disk layout.
Mount point (w/o chroot) Partition Function Partition type GUID [gdisk code] Filesystem Suggested size
/mnt/efi /dev/sda1 EFI partition [EFI System Partition (ESP)](../../notes/boot.html) [ef00] FAT32 (vfat) Around 512 MiB
/dev/mapper/rootfs /dev/sda2 LUKS partition Linux LUKS [8309] LUKS Remainder of the device
Table of LUKS device-mapper layout.
Mount point (w/o chroot) Partition Function Partition type GUID [gdisk code] Filesystem Suggested size
/mnt /dev/mapper/rootfs Btrfs partition Linux x86-64 root (/) [8304] btrfs Remainder of the device
Table of btrfs root partition layout.
Mount point (w/ chroot) Subvolume Type
/ @ btrfs
/home @home btrfs
/var @var btrfs
/swap @swap SWAP

![Scheme of the disk layout.](drawio/arch_linux_complex_setup_disk.drawio.svg)

![Scheme of the boot process.](drawio/arch_linux_complex_setup_boot.drawio.svg)

TODO: Should I add a dedicated subvolume @storage mounted in /home/storage?


Disk partitioning and formatting for ESP and LUKS

The first step is to format our disk to hold the [EFI System Partition (ESP)](../../notes/boot.html) and our [Linux Unified Key Setup (LUKS)](security.html) container. The mountpoint for the ESP is /efi instead of /boot. It is necessary since, by choosing /boot as the ESP, the traditional /boot files such as the kernel image and the initramfs will resides on the ESP instead of the root Btrfs subvolume (@). Therefore, they will not be able to be included in the subvolume snapshot and restored from backup. This choice also allows to encrypt /boot.

One can see [disk partitioning](disk.html) for details on how to achieve the layout presented in Table 2, but in summary:

  1. Partition the disk with [gdisk](disk.html) and create the two aforementioned partitions:
   gdisk /dev/sda # o # n # ENTER # ENTER # +512M # ef00 # n # ENTER # ENTER # ENTER # 8309 # w
  1. Format the [ESP](../../notes/boot.html) using [FAT](disk.html):
   mkfs.vfat -F 32 -n ESP /dev/sda1
  1. Format (create) the [LUKS](security.html) container, choose a passphrase, and mount it (open) with the rootfs device mapper name:
   cryptsetup --type luks2 luksFormat /dev/sda2 cryptsetup open /dev/sda2 rootfs

Disk partitioning and formatting for Btrfs

Our LUKS device-mapper is now available at /dev/mapper/rootfs and is ready to be formatted as a [BtrFS](disk.html) filesystem:

   mkfs.btrfs -L rootfs /dev/mapper/rootfs

For now, it is not necessary to use any special options to mount the root partition. Mount our Btrfs root partition under /mnt to manage its subvolumes:

   mount --mkdir /dev/mapper/rootfs /mnt

Subvolumes partitioning

Our Btrfs root partition is now available at /mnt and is ready to be logically partitioned using subvolumes. Create several subvolumes:

  • @ for / such that we can snapshot the system state (including /boot files).
  • @home for /home such that we can snapshot the user data and configuration.
  • @var for /var such that it is not included in @ snapshots – lots of useless write operations and noisy state.
  • @swap for [SWAP] such that we can have an encrypted SWAP file.
   btrfs subvolume create /mnt/@
   btrfs subvolume create /mnt/@home
   btrfs subvolume create /mnt/@var
   btrfs subvolume create /mnt/@swap

Now that our subvolumes are created, unmount the Btrfs root partition, which will not be needed anymore unless it is needed to perform Btrfs subvolume management:

   umount /mnt

We can now mount our root subvolume first. Then, we can mount the other previously created subvolumes as well as the ESP under the root subvolume:

   mount --mkdir -o noatime,nodiratime,compress=zstd,subvol=@ /dev/mapper/rootfs /mnt
   mount --mkdir -o noatime,nodiratime,compress=zstd,subvol=@home /dev/mapper/rootfs /mnt/home
   mount --mkdir -o noatime,nodiratime,compress=zstd,subvol=@var /dev/mapper/rootfs /mnt/var
   mount --mkdir -o noatime,nodiratime,compress=zstd,subvol=@swap /dev/mapper/rootfs /mnt/swap
   mount --mkdir /dev/sda1 /mnt/efi

Note that we use [optimization flags](disk.html) for compression and access time bypass for Btrfs subvolumes.


SWAP formatting

Instruct Btrfs to create a swap file (remember to adjust its size) and activate it using [/usr/share/man/man8/swapon.8.gz swapon]:

   btrfs filesystem mkswapfile --size 16g --uuid clear /mnt/swap/swapfile
   swapon /mnt/swap/swapfile

The mounting points and their flags will automatically be detected later by genfstab.

System bootstrapping

Package bootstrapping

Use the pacstrap script to install packages inside the root partition:

  1. Install the base package, the Linux kernel, and firmware for common hardware, installing only the very minimal system:
   pacstrap -K /mnt base linux linux-firmware
  1. Stopping here would be limited, if it cannot connect to the internet, edit files or compile packages. Hence, we also add network tools, basic text editors, base packages for compilation (e.g. gcc, make), terminal multiplexer, the GRUB boot loader, UEFI management tools, and the [BtrFS](disk.html) filesystem:
   pacstrap -K /mnt dhclient iwd networkmanager pacstrap -K /mnt nano vi vim pacstrap -K /mnt base-devel less man man-pages pacstrap -K /mnt tmux pacstrap -K /mnt grub pacstrap -K /mnt efibootmgr efitools sbctl pacstrap -K /mnt btrfs
  1. If you have an Intel or AMD CPU, enable microcode updates in addition:
   pacstrap -K /mnt amd-ucode   # For AMD CPUs. pacstrap -K /mnt intel-ucode # For Intel CPUs.

To make our drives automatically mounted in the new system, generate an fstab file (use -U or -L to define path by UUID or labels, respectively) representing the current mounting under /mnt:

   genfstab -U /mnt >> /mnt/etc/fstab

Now, chroot into the new system:

   arch-chroot /mnt

From here, follow the correct stage 2 guide according to the scenario chosen before, either the simple setup (See section 1.1.5) or the complex setup (See section 1.1.6).

Stage 2 – Simple setup

Bootloader installation

Once chrooted in the new system, we will install a Linux-capable boot loader on the ESP, here [GRUB](../../notes/boot.html). Refer to the dedicated section for details about the installation, but in summary, execute the following for a UEFI-based system:

   grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=grub
   grub-mkconfig -o /boot/grub/grub.cfg

Our system is ready to boot now.

Stage 2 – Complex setup

Initramfs configuration for LUKS

We need to allow the [Initial RAMDisk (initramfs)](linux_kernel.html) image to:

  1. Mount the ESP partition which is [FAT](disk.html).
  1. Decrypt a LUKS encrypted block device – by asking the passphrase to the user or fetching it from the TPM.
  1. Mount a btrfs subvolume as root filesystem.

Since all of this has to be done in the early userspace, we need to execute appropriate hooks for the additional features (keyboard handling, decryption handling, filesystem access drivers). Asking for the LUKS password in the early userspace is possible with the initramfs in the init mode (from busybox), but not fetching the LUKS password from the TPM. To do so, we need to use the systemd mode since we will use systemd-cryptenroll for the TPM management later.

Configure the /etc/mkinitcpio.conf file by ensuring and/or add the following hooks while removing the udev hook: systemd, keyboard, sd-vconsole, sd-encrypt, filesystems (incl. btrfs). It may differ but should look like to:

   HOOKS=(base systemd autodetect modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck)

Configure the /etc/mkinitcpio.conf file by ensuring and/or add the following modules: vfat. It may differ but should look like to:

   MODULES=(fat vfat)

Then, regenerate the initramfs image:

   mkinitcpio -P

Creation of the UKI

We will use [mkinitcpio](arch_linux.html) to create the [Unified Kernel Image (UKI)](linux_kernel.html).

First, store the appropriate kernel's [command-line parameters](linux_kernel.html) in the /etc/kernel/cmdline file, allowing the UKI to find and mount the root system. Here, we use the systemd version of the kernel command-line parameters for LUKS decryption using rd.luks.name:

   rd.luks.name=DEVUUID=rootfs root=/dev/mapper/rootfs rootflags=subvol=@

Where:

  1. DEVUUID is the UUID of the block device containing the LUKS container, which can be found using:
   lsblk -o UUID /dev/sda2 | tail -n 1
  1. rootfs is the device mapper name used above.
  1. @ is the Btrfs root subvolume name.

Note that since we use Secure Boot, those command-line parameters will not be able to be changed from the UEFI boot manager or interactively – because signed and embedded in the UKI.

Then, we will have to configure mkinitcpio for the [generation of an UKI](arch_linux.html). In such, set the following in the default linux preset of mkinitcpio located at [file:///etc/mkinitcpio.d/linux.preset /etc/mkinitcpio.d/linux.preset]:

   default_uki="/efi/EFI/Linux/arch-linux.efi"
   # Optionnal.
   # If you want an additional boot entry to a fallback initramfs to add later:
   fallback_uki="/efi/EFI/Linux/arch-linux-fallback.efi"

Then, re-generate the preset to create the UKI on the ESP:

   mkdir -p /efi/EFI/Linux
   mkinitcpio -p linux

Thanks to the default mkinitcpio hooks, the UKI will be regenerated by a [Pacman hook](arch_linux.html) at appropriate times after upgrading.


Boot manager configuration

We do not use any third-party software bootloader in this setup, since we leverage the UEFI ability to load EFI binaries and use an UKI acting as an EFI binary. The only needed configuration is to create an entry in the boot manager using [efibootmgr](../../notes/boot.html) loading the UKI located on /dev/sda1:

   efibootmgr --create --disk /dev/sda --part 1 --label "archlinux" --loader '\EFI\Linux\arch-linux.efi' --unicode

System configuration

We can now configure various little aspects of the system:

  • Set the time zone and run hwclock to generate /etc/adjtime:
   ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime hwclock --systohc # If you need to manually configure the system and hardware clock/time/date after a CMOS reset: # sudo hwclock --set --date='2023-10-06 17:47' # sudo hwclock --hctosys
  • Configure /etc/locale.gen to enable the desired locales (time, date, currency, etc.), then generate the configured locales:
   cat /etc/locale.gen echo "fr_FR.UTF-8 UTF-8" > /etc/locale.gen locale-gen 

Then, create the /etc/locale.conf file and set the LANG variable accordingly to activate the desired and generated locale:

   echo "LANG=fr_FR.UTF-8" > /etc/locale.conf 

Make the console keyboard layout changes persistent in /etc/vconsole.conf:

   echo "KEYMAP=fr-pc" > /etc/vconsole.conf 

Make the X11 keyboard layout changes persistent using [localectl](setup.html):

   localectl set-x11-keymap fr
  • Create the hostname file:
   echo "citadel" > /etc/hostname
  • Enable the [fstrim](optimization.html) timer and service if you have at least one SSD:
   systemctl enable --now fstrim.timer
  • Set the root password:
   passwd

Exit the chroot environment by typing exit or pressing Ctrl+d. Optionally manually unmount all the partitions:

   swapoff -a
   umount -R /mnt

Finally, restart the machine by typing reboot. Any partitions still mounted will be automatically unmounted by systemd. Remember to remove the installation medium and then login into the new system with the root account.

Stage 3 – Complex setup

If the system has been able to reboot correctly and the passphrase for the LUKS container has been asked to the user, everything is correctly configured. We can finally sign our binaries and enroll our keys.


Secure Boot enrolling

It is now time to establish the cryptographic verification between the UEFI and the kernel through the Secure Boot mechanism and the UKI.

First, backup EFI variables (keys and certificates) in case of error:

   for var in PK KEK db dbx; do efi-readvar -v $var -o uefi_backup_${var}.esl; done

Check the Secure Boot status and ensure it is in Setup Mode, when the Platform Key is removed. If not, enter the UEFI firmware setup and deletes / clears the keys and certificates.

   sbctl status

We will create our custom secure boot keys and enroll them alongside the Microsoft's keys shipped with the motherboard (ensuring not bricking the device, see [1]):

   sbctl create-keys
   sbctl enroll-keys -m

If a File is ummutable error is encountered, simply execute the following command against the specified file:

   chattr -i FILE

It will allows for the sbctl command writing to those files – being UEFI variables exposed through sysfs by the kernel. Check the Secure Boot status again, and ensure the Setup Mode is disabled, hence being in User Mode. If so, Secure Boot will be able to check the UKI integrity using our keys.

User-land

User management

First, create a new user that will be the main user of the machine, set its password and its home directory:

   useradd -m $username
   passwd $username
   mkdir -p /home/$username
   usermod -d /home/$username -m $username

Allow this user to run root commands by making him a sudoer:

   pacman -S sudo
   groupadd sudo
   usermod -aG sudo $username

And don't forget to uncomment the %sudo ALL=(ALL:ALL) ALL line in /etc/sudoers file.

Package management

Then, we need to [connect to the Internet](network.html) just like above to continue installing new packages. Update the Pacman database:

   pacman -Sy

You can then install the graphical stack:

  • My video server.
  • My window manager.
  • Required to run demanding applications (e.g., [Nvidia](linux_kernel.html) or [Intel Graphics](linux_kernel.html)).
  • [GTK from GNOME](unix.html) and [Qt from KDE](unix.html).

You can then install the network stack:

  • My network manager.
  • Required to run some specific network interfaces.

You can then install the sound stack:

  • The kernel sound card driver.
  • The main multimedia framework and sound server.

You should have now a system ready to use that can be compared to an automatic installer in other distros. You can now install user applications, like web browsing and mail, file synchronization, editors, shells and terminals, etc.:

  • Text editor and LISP machine.
  • Web browser and bookmarks synchronizer.
  • Terminal with Alacritty, multiplexer with Tmux, shell with ZSH.
  • VCS with Git, local monitoring with GR, real-time synchronization with Syncthing.
  • Remote access with SSH and SSHFS, remote copy with RSync, remote viewing with TigerVNC.
  • Key management with Pass and KeePass, file encryption with eCryptFS and GPG.

Personal files

I have one repository used to configure and administrate my computer. Find a way to get the SSH key located in my dotfiles (SSH-based copy using password authentication, USB key transfer, Syncthing synchronization). For instance, using SSH on a machine which have the key:

   ip=192.168.1.1
   ssh-copy-id drac@$ip
   ssh drac@$ip "echo '$(cat ~/.ssh/id_rsa.pub)' > ~/.ssh/id_rsa.pub"
   ssh drac@$ip "echo '$(cat ~/.ssh/id_rsa)'     > ~/.ssh/id_rsa"
   ssh drac@$ip "chmod 600 ~/.ssh/id_rsa"

Then, clone and follow the README:

   git clone git@github.com:pierreay/bootstrap.git

Footnotes

[1] https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Creating_and_enrolling_keys


UKI signing

Check what specific files need to be signed for secure boot to work:

   sbctl verify

The UKI (/efi/EFI/Linux/arch-linux.efi) should be detected as an unsigned file. Let's sign it and register the signature inside the sbctl database:

   sbctl sign --save /efi/EFI/Linux/arch-linux.efi

Our UKI is now signed and Secure Boot is ready to work. Reboot into the firmware settings, enable Secure Boot, and reboot again to check it works the intended way and display the status:

   sbctl status

sbctl comes with a [Pacman hook](arch_linux.html) that automatically signs all new files that are registered into its database whenever the kernel or systemd is updated.


TPM2 enrolling

We can now enroll the TPM in order to use it unlock the LUKS volume. To do so, we will use the [SystemD](unix.html) cryptenroll command. First, automatically generate a recovery key that can be used in case of a problem with the TPM:

   systemd-cryptenroll /dev/sda2 --recovery-key

Store this recovery key in another location than the LUKS container (e.g., USB key or a trusted computer).

Second, remove the passphrase created during the LUKS format process and create a key bound to the TPM PCR 7 (Secure Boot state and firmware certificates (PK, KEK, etc.)):

   systemd-cryptenroll /dev/sda2 --wipe-slot=empty --tpm2-device=auto

As of now, the TPM will automatically release the key as long as the boot chain is not tampered.

To make the UKI grab the key in order for the [initramfs](linux_kernel.html) to unlock the LUKS container, we need to embed the tpm2-device=auto LUKS option in the kernel command-line parameter inside the UKI. To do so, referring to the UKI creation section above, add the LUKS option in a new rd.luks.options kernel parameter:

   rd.luks.options=DEVUUID=tpm2-device=auto

Don't forget to regenerate and resign the UKI after this step – or simply, regenerating the initramfs will execute the Pacman hooks performing those two tasks.


UEFI protection

Since the TPM will automatically provides the LUKS key for decryption if the UEFI configuration integrity is validated, it is necessary to protect the UEFI firmware with a strong password. You can use the same password for:

  • Prevents an attacker to disable Secure Boot by entering the UEFI setup. If this happens despite the protection, the attacker could not boot the encrypted drive since the TPM would not release the key, but still use the laptop to boot another OS. Enable Boot Device List protection by password as well.
  • Requests the physical presence of the user at boot time.

Kernel protection

Using all of those security systems against attacker from boot-time, one may surely want to protect also from run-time by enabling [kernel lockdown](optimization.html).