Extended Brain Storage

Artix Linux: Full Disk Encryption with UEFI

Posted on April 5, 2021

Not everyone fells happy and confident about systemd. In order to keep peace within a linux-based operating system, administrators may study, serve and use the art of mystical energy of the Force…

Introduction

Artix Linux is a systemd-free linux-based distribution derived from Arch Linux. Therefore, it is somewhat “backward-compatible”, as it uses its repositories including the AUR. However, it uses OpenRC instead of the intrusive systemd.

The installation process is “somewhat” described on the project Wiki, including encryption. The installation ISO can be downloaded from several mirrors and in various flavours (base, cinnamon, lxde, lxqt, mate, plasma, xfce, etc.)

The graphical user interface (GUI)-flavoured ISOs provide an installation wizard that can be triggered by the calamares command which is a distribution-independent installer framework. The base-flavoured option lacks these features, due to which it is very light-weighted (and preferred).

The downloaded ISO image can be transferred to a USB flash medium using the dd command as follows:

$ dd bs=4M if=/source/image of=/dev/target status=progress oflag=sync

The Goal

This is a brief tutorial to install Artix linux on a computer which is:

The aforementioned requirements will provide an “almost perfect” full disk encryption (FDE) installation, i.e. the root and swap partitions (the lvm-volRoot and lvm-volSwap volumes, to be more precise) will be encrypted using the LVM on LUKS method. The only unencrypted partition will be the first partition, i.e. the ESP; and thus, the kernels and initramfs files in the /boot/ directory will be encrypted as well.

UEFI GRUB Disk Partitioning Scheme

UEFI GRUB Disk Partitioning Scheme


Other Disk Format and Firmware Options

Other ideas of disk formatting and firmware options are discussed in: Linux: Full Disk Encryption with BIOS, UEFI using MBR, GPT, LUKS, LVM and GRUB


The Installation Process

The calamares-based installation is not described here.

In order to manipulate disk partitions, the ISO image (live CD) comes with cfdisk. However, it does not align partitions to block device I/O limits. It may seem useful to work with tools that do support such elementary features, such as parted (fdisk, gdisk, etc.) which can be installed from the repository by running:

$ pacman -S parted

Disks Availability

Using the parted command, available disks can be checked as follows:

$ parted -l
$ parted -s /dev/nvme0n1 print

Disk Format and Partitioning

The following commands WILL DELETE DATA. As discussed earlier, the NVMe disk (/dev/nvme0n1) will be partitioned using the GPT, since the target machine (notebook) comes with a UEFI firmware (instead of BIOS).

$ parted -s /dev/nvme0n1 mklabel gpt

Due to the UEFI firmware, an EFI System Partition of 512MiB should be created in Linux environment. Additionally, all parted commands can be run with -a optimal parameter in order to align partitions accordingly as follows:

$ parted -s -a optimal /dev/nvme0n1 mkpart "primary" "fat32" "0%" "512MiB"
$ parted -s /dev/nvme0n1 set 1 esp on

Optionally, parted can align partitions at any time by running:

$ parted -s /dev/nvme0n1 print
$ parted -s /dev/nvme0n1 align-check optimal <PARTITION_NUMBER>

Furthermore, an empty disk partition needs to be created in the rest of the space:

$ parted -s -a optimal /dev/nvme0n1 mkpart "primary" "ext4" "512MiB" "100%"
$ parted -s /dev/nvme0n1 set 2 lvm on

Disk Encryption and Logical Volumes

The disk encryption will utilise the Linux Unified Key Setup (LUKS), which is now part of an enhanced version of cryptsetup, using dm-crypt (device-mapper crypt) as the disk encryption backend.

LUKS physical partition can be created and formatted as follows (No released version of GRUB recognises LUKS2 format):

$ cryptsetup luksFormat -v --type=luks1 /dev/nvme0n1p2

Alternatively, including more details (the following is the default):

$ cryptsetup -v --cipher aes-xts-plain64 --key-size 256 --hash sha256 --iter-time 2000 --use-urandom --verify-passphrase luksFormat /dev/nvme0n1p2

The LUKS-encrypted partition (/dev/nvme0n1p2) needs to be opened and mounted using the device mapper (into e.g. lvm-system):

$ cryptsetup luksOpen /dev/nvme0n1p2 lvm-system

Note: If any of the commands produces the following warning, it can be ignored, as: “This is because /run is not available inside the chroot.

WARNING: Failed to connect to lvmetad. Falling back to device scanning.

or

/run/lvm/lvmetad.socket: connect failed: No such file or directory

or

WARNING: failed to connect to lvmetad: No such file or directory. Falling back to internal scanning.

Now, it is possible to create a physical volume using the Logical Volume Manager (LVM) and the previously used id (lvm-system) as follows:

$ pvcreate /dev/mapper/lvm-system

Having the physical volume, it is possible to create a logical volume group named lvmSystem as follows:

$ vgcreate lvmSystem /dev/mapper/lvm-system

And having the logical volume group, logical volumes can be created. As an example, a 16GB for swap (volSwap) and the rest for the root partition (volRoot) can be created as follows:

$ lvcreate -L 16G lvmSystem -n volSwap
$ lvcreate -l +100%FREE lvmSystem -n volRoot

Note: The size of a swap partition has always been part of many discussions. Basically, in order to have suspend-to-disk (hibernation) mechanism working, it is not necessary to have the swap of the same size as RAM, but it is a habit of doing so. Reader discretion advised.

Having all physical and virtual disk partitions ready, it is possible to format them as follows (swap, fat for ESP and ext4 for /):

$ mkswap /dev/lvmSystem/volSwap
$ mkfs.fat -n ESP -F 32 /dev/nvme0n1p1
$ mkfs.ext4 -L volRoot /dev/lvmSystem/volRoot

Having each partition formatted, they can be mounted as follows:

$ swapon /dev/lvmSystem/volSwap
$ mount /dev/lvmSystem/volRoot /mnt
$ mkdir -p /mnt/boot/efi
$ mount /dev/nvme0n1p1 /mnt/boot/efi

Installation of Packages and Compilation of a Hardened Kernel

Finally, the operating system parts can be downloaded and installed as follows:

$ basestrap /mnt base base-devel openrc

Instead of the standard kernel shipped with Artix (kernel, kernel-headers), the preferred hardened version will be installed (linux-hardened, linux-hardened-headers, usbctl):

$ basestrap /mnt linux-firmware linux-hardened linux-hardened-headers usbctl

The /etc/fstab file can be created using various system identifiers, the following step uses UUIDs:

$ fstabgen -U /mnt >> /mnt/etc/fstab

tmpfs is a temporary filesystem that resides in memory or swap partitions. Without systemd, only the /run directory uses tmpfs by default:

$ findmnt --target /run
TARGET SOURCE FSTYPE OPTIONS
/run   run    tmpfs  rw,nosuid,nodev,relatime,mode=755,inode64

Optionally, the /tmp directory can be set up similarly as follows:

$ echo "tmpfs	/tmp	tmpfs	rw,nosuid,noatime,nodev,size=4G,mode=1777	0 0" >> /mnt/etc/fstab

After restart, the setup can be verified as follows:

$ findmnt --target /tmp
TARGET SOURCE FSTYPE OPTIONS
/tmp   tmpfs  tmpfs  rw,nosuid,nodev,noatime,size=4194304k,inode64

Now, it is time to change root (chroot) to the newly installed environment:

$ artix-chroot /mnt /bin/bash # formerly artools-chroot

System-wide locale (e.g. en_AU.UTF-8) can be set up as follows:

$ echo -e "en_AU.UTF-8 UTF-8" >> /etc/locale.gen
$ locale-gen
$ echo LANG=en_AU.UTF-8 > /etc/locale.conf
$ export LANG=en_AU.UTF-8

Time zone (Continent/City) and hostname (e.g. 4rt1x) can be configured as follows:

$ ln -s /usr/share/zoneinfo/Continent/City /etc/localtime
$ echo "hostname=4rt1x" > /etc/conf.d/hostname

The /etc/mkinitcpio.conf file enables to set up various parameters of a kernel. Within the HOOKS part, the encrypt lvm2 needs to be put between block and filesystems keywords in order to enable the FDE. It may also be useful to include the resume keyword to enable suspend to disk options. However, this may not work at all times, such as with hardened kernels.

$ sed -i "s/modconf block/modconf block encrypt lvm2 resume/g" /etc/mkinitcpio.conf

A random-byte file can be generated in order to serve as key to automatically decrypt the system partition during boot by GRUB, which looks for /crypto_keyfile.bin file by default. For more details regarding usage of /dev/random and /dev/urandom for keys generation, this ArchWiki page can be visited.

$ dd if=/dev/random of=/crypto_keyfile.bin bs=512 count=8 iflag=fullblock
$ chmod 000 /crypto_keyfile.bin
$ sed -i "s/FILES=(/FILES=(\/crypto_keyfile.bin/g" /etc/mkinitcpio.conf

dm-crypt is a transparent disk encryption subsystem which uses kernel’s crypto API framework (XTS, AES, SHA, etc.) and Device-mapper subsystem. The LVM is a device-mapper framework that provides logical volume management for the Linux kernel. As both are intended to be used, the appropriate lvm2 and cryptsetup packages and related services need to be installed:

$ pacman -S lvm2 lvm2-openrc cryptsetup cryptsetup-openrc

Finally, the newly created key can be added as follows:

$ cryptsetup luksAddKey /dev/nvme0n1p2 /crypto_keyfile.bin

Now, the kernel can be compiled and a new initramdisk created (the default kernel is now linux):

$ mkinitcpio -p linux-hardened

Consequently, the root password needs to be set up:

$ passwd

Boot Loader Installation

There are various bootloaders. However, the following commands use the GRUB (and its optional dependencies):

$ pacman -S grub efibootmgr
$ pacman -S dosfstools freetype2 fuse2 gptfdisk libisoburn mtools os-prober

Optionally when required and after considering that hibernation/resume will not work with hardened kernels, the resume partition needs to be configured in the /etc/default/grub file as follows:

$ sed -i "s/quiet/quiet resume=UUID=`blkid -s UUID -o value /dev/lvmSystem/volSwap`/g" /etc/default/grub

As discussed earlier, in order to prevent the password to open the LUKS volume to be asked the second time (the first time it is asked by GRUB), the /etc/mkinitcpio.conf file (the FILES variable) needs to be updated with the key file path reference as follows:

$ sed -i "s/GRUB_CMDLINE_LINUX=\"\"/GRUB_CMDLINE_LINUX=\"cryptdevice=UUID=`blkid -s UUID -o value /dev/nvme0n1p2`:lvm-system\"/g" /etc/default/grub

Grub needs to be configured in /etc/default/grub in order to find the LUKS-encrypted partition as follows:

$ sed -i "s/#GRUB_ENABLE_CRYPTODISK/GRUB_ENABLE_CRYPTODISK/g" /etc/default/grub

Optionally, GRUB colours can be modified as follows:

$ sed -i "s/#GRUB_COLOR_NORMAL/GRUB_COLOR_NORMAL/g" /etc/default/grub
$ sed -i "s/#GRUB_COLOR_HIGHLIGHT/GRUB_COLOR_HIGHLIGHT/g" /etc/default/grub

Finally, GRUB can be installed at the beginning of the first disk (/dev/nvme0n1) that contains the ESP mounted in the /boot/efi directory as follows:

$ grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=artix --recheck /dev/nvme0n1
$ grub-mkconfig -o /boot/grub/grub.cfg

Note: Every change in the configuration of GRUB needs to be followed by the following command in order to be applied:

$ grub-mkconfig -o /boot/grub/grub.cfg

Note: When reinstalling GRUB, the following warnings may be observed and ignored:

/run/lvm/lvmetad.socket: connect failed: No such file or directory

or

WARNING: failed to connect to lvmetad: No such file or directory. Falling back to internal scanning.

This is because /run is not available inside the chroot. These warnings will not prevent the system from booting, provided that everything has been done correctly, so you may continue with the installation.

Optionally, the GRUB setup needs to be changed in order to prevent the (e)udev from renaming the kernel eth0, wlan0 interfaces to enp0s25, wlp4s0 etc. using the optional net.ifnames=0 parameter as follows:

$ vi /etc/default/grub
GRUB_CMDLINE_LINUX="... net.ifnames=0"
$ grub-mkconfig -o /boot/grub/grub.cfg

Necessary Services Setup

The haveged service is a simple entropy daemon useful for unpredictable random number generation, which can be installed and activated as follows:

$ pacman -S haveged haveged-openrc
$ rc-update add haveged default

Cron job daemons (cronie, fcron etc.) can be installed and activated as follows (e.g. cronie):

$ pacman -S cronie cronie-openrc
$ rc-update add cronie default

Adding Unprivileged User Accounts

As an example, the following list of commands adds a non-privileged user (USERNAME) into the system as part of the wheel and users groups and including a prompt for password:

$ useradd -m -G wheel -s /bin/bash USERNAME
$ passwd USERNAME

Sudoers setup for the wheel group can be simply changed as follows:

$ sed -i "s/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/g" /etc/sudoers

Network Setup using Network Manager

If Network Manager GUI is the desired choice to manage network interfaces, the following needs to be run in order to install and activate the service:

$ pacman -S networkmanager networkmanager-openrc networkmanager-openvpn network-manager-applet
$ rc-update add NetworkManager default

Optionally, more plugin options for NetworkManager can be looked up as follows:

$ pacman -Ss networkmanager

Since the unprivileged user should be in either wheel or network group in order to manage network interfaces, it may be necessary to run, e.g.:

$ usermod -a -G wheel USERNAME

One of the downsides is that the passwords are stored in clear text in:

$ grep -H '^psk=' /etc/NetworkManager/system-connections/*

Another issue is a bit privacy-concerned, since the NetworkManager service periodically connects to http://www.archlinux.org/check_network_status.txt (formerly apollo.archlinux.org) to check its online status.

$ curl http://www.archlinux.org/check_network_status.txt
NetworkManager is online

Luckily, the URL can be changed as follows:

$ vi /etc/NetworkManager/conf.d/11-connectivity-check.conf
[connectivity]
uri=http://server.domain.tld/nm-status/index.php
interval=120
response="You're up, buddy!"
#response="NetworkManager is online"

Obviously, a replacement URL needs to be accessible on another web server. Assuming that the web server runs HTTPD with PHP Support, the configuration can be updated as follows:

### server.domain.tld:80
server "server.domain.tld" {
...
  # NetworkManager
  location "/nm-status/index.php" {
    root "/htdocs/nm-status"
    root strip 1
    fastcgi socket "/run/php-fpm.sock"
  }
...
}

Naturally, the index.php script needs to be created. The example is as follows:

$ mkdir /var/www/htdocs/nm-status
$ vi /var/www/htdocs/nm-status/index.php
<?php
  header('X-NetworkManager-Status: online');
  header('Content-Type: text/plain');
  echo "You're up, buddy!";
  header("HTTP/1.1 200 OK");
?>

Testing and verification:

$ curl http://server.domain.tld/nm-status/index.php
You're up, buddy!

Network Setup using RC scripts (Alternative)

If Network Manager GUI is not the preferred solution, relevant RC services need to be started during system startup (in the default runlevel). In order to activate such option, the following commands need to be run to activate all interfaces (found in the /sys/class/net directory):

$ rc-update add net.lo default
$ for i in `ls /sys/class/net | grep -v lo`; do
  ln -s /etc/init.d/net.lo /etc/init.d/net.$i
  rc-update add net.$i default
done

Note: The previous will not work if the default interface names recognised by udev were changed to eth0 etc. It needs to be run manually and not as per the /sys/class/net directory in chroot enviroment, e.g. for eth0, it needs to be run as: ln -s /etc/init.d/net.lo /etc/init.d/net.eth0; rc-update add net.eth0 default.

A WiFi interface can be configured using the WPA supplicant as follows:

$ pacman -S iw wpa_supplicant
$ wpa_passphrase "SSID" "PASSWORD" > /etc/wpa_supplicant/wpa_supplicant.conf
$ echo "modules_INTERFACE_ID=\"wpa_supplicant dhcpcd\"" >> /etc/conf.d/net

Optionally, the configuration of WPA supplicant can be verified using:

$ wpa_supplicant -iINTERFACE_ID -c/etc/wpa_supplicant/wpa_supplicant.conf

Optionally, to fine-tune any interface, there are many options present in the /etc/conf.d/net file. The following may come handy to decrease the carrier timeout (in seconds), which is ten seconds by default (i.e. waiting until the physical interface is “brought up”):

$ echo "carrier_timeout_INTERFACE_ID=5" >> /etc/conf.d/net

Additional Services Setup (Optional)

Numlock can be automatically enabled after system start (generally not desirable for laptops/notebooks):

$ pacman -S numlockx
$ rc-update add numlock default

The bloody system beeper can be disabled as follows:

$ echo "blacklist pcspkr" > /etc/modprobe.d/nobeep.conf

SSH daemon can be installed as follows:

$ pacman -S openssh openssh-openrc
$ rc-update add sshd default

NTP, ACPI, Syslog-NG daemons can be installed and activated as follows:

$ pacman -S ntp ntp-openrc acpid acpid-openrc syslog-ng syslog-ng-openrc
$ rc-update add ntpd default
$ rc-update add acpid default
$ rc-update add syslog-ng default

Useful commands (will include samba, samba client):

$ pacman -S vi artools bash-completion lsof strace
$ pacman -S wget htop mc zip samba unrar p7zip unzip
$ pacman -S hdparm smartmontools hwinfo dmidecode
$ pacman -S whois rsync nmap tcpdump inetutils net-tools ndisc6

In order to access AUR and other unofficial repositories, a preferred AUR helper must be installed, e.g. yay:

$ cd /tmp
$ git clone https://aur.archlinux.org/yay.git
$ cd yay
$ makepkg -si

The pacman.conf file needs to be updated in order to enable multilib and add AUR repos:

$ sudo vi /etc/pacman.conf
...

[multilib]
Include = /etc/pacman.d/mirrorlist-arch

#
# AUR
#

[archlinuxfr]
Server = http://repo.archlinux.fr/$arch

Usage:

$ yay --noeditmenu --nodiffmenu --save # to prevent questions
$ yay -Syu # to update the system

Congratulations

The chroot can be escaped as follows:

$ exit

Optionally, everything can be unmounted (should be done automatically, though):

$ umount -R /mnt
$ swapoff -a

The system now can be rebooted:

$ reboot

Post Installation Steps

The very first step after the system restart and successful login attempt is to BACKUP THE LVM METADATA. The process is as simple as follows:

$ cp /etc/lvm/backup/* /somewhere/safe

Furthermore, a brief tutorial of how to install XFCE4 desktop environment is described in Artix Linux: Installation of XFCE4.

Tags: #Artix Linux #security #encryption #FDE #systemd #OpenRC #UEFI #MBR #GPT #LUKS #LVM

⏴ Previous Post