From f5fffb97163b780493841ddf18221d0b41fded52 Mon Sep 17 00:00:00 2001 From: Sam Hadow Date: Sun, 25 Jan 2026 20:10:10 +0100 Subject: [PATCH] new post, install guide, archlinux with SELinux, full disk encryption and secure boot --- ...on-luks-with-selinux-installation-guide.md | 461 ++++++++++++++++++ 1 file changed, 461 insertions(+) create mode 100644 _posts/2026-01-25-archlinux-uefi-lvm-on-luks-with-selinux-installation-guide.md diff --git a/_posts/2026-01-25-archlinux-uefi-lvm-on-luks-with-selinux-installation-guide.md b/_posts/2026-01-25-archlinux-uefi-lvm-on-luks-with-selinux-installation-guide.md new file mode 100644 index 0000000..b0275d5 --- /dev/null +++ b/_posts/2026-01-25-archlinux-uefi-lvm-on-luks-with-selinux-installation-guide.md @@ -0,0 +1,461 @@ +--- +layout: post +author: Sam Hadow +tags: archlinux selinux sysadmin +--- + +This post is a guide to install archlinux in UEFI with full disk encryption (LVM on LUKS), SELinux enabled and optionally secure boot. +**Warning:** apparmor is much easier to use on archlinux, SELinux on archlinux **will** require you to write some policies manually. Fedora is a better solution if you want SELinux working out of the box and don't want to fight SELinux writing policies. This guide is mostly for advanced users. + +## preparing installation media + +Follow the initial steps from archlinux [wiki](https://wiki.archlinux.org/title/Installation_guide) to prepare your installation media, the most convenient solution is to copy the ISO to a [ventoy](https://www.ventoy.net/en/index.html) USB key. +Then boot your archlinux ISO and first check you have internet access on your computer: + +```bash +ping archlinux.org +``` + +If using WiFi, you'll need to use [iwctl](https://wiki.archlinux.org/title/Iwd#iwctl) + +# installation steps + +## 1) setting up LVM and preparing volumes + +### 1.1) loading the required kernel modules + +```bash +modprobe efivarfs +modprobe dm-crypt +modprobe dm-mod +``` + +### 1.2) partition table + +Find the disk you want to use to install your system with `lsblk`. For me it's `vda` as I'm using a virtual machine to write this guide. +**important:** Select a GPT parition table type and not MBR. +Create a partition table with `cfdisk /dev/vda` (or your prefered tool) and create 2 partitions: ++ `/dev/vda1` as ef EFI (FAT-12/16/32) type, a size of 512MB is fine ++ `/dev/vda2` as 83 Linux filesystem type for the rest of the disk + +Write the partition table to the disk. + +### 1.3) setting up the encrypted volume + +Create the encrypted volume, it will ask you for a confirmation and let you choose a passphrase. (Note that PBKDF2 key derivation algorithm is weaker than Argon2 but is required when using the default grub bootloader, the installation using systemd-boot will not be covered in this guide.) + +```bash +cryptsetup luksFormat --type luks2 --pbkdf pbkdf2 /dev/vda2 +``` + +Then open it with the passphrase chosen. + +```bash +cryptsetup luksOpen /dev/vda2 luks +``` + +### 1.4) setting up LVM + +We will create 3 volumes, one for the SWAP, one for the ROOT filesystem and one for the HOME filesystem. Adapt the sizes to what is appropriate for you, in my case I'm using a virtual machine with a 25GB disk so I won't create a huge root volume. + +```bash +pvcreate /dev/mapper/luks +vgcreate system /dev/mapper/luks +lvcreate -L 1G -n swap system +lvcreate -L 10G -n root system +lvcreate -l 100%FREE -n home system +``` + +### 1.5) formating and mounting the volumes + +I'll use a BTRFS filesystem but use the filesystem you prefer. + +```bash +#formatting +mkfs.fat -F32 /dev/vda1 +fatlabel /dev/vda1 BOOT +mkswap -L SWAP /dev/mapper/system-swap +mkfs.btrfs -L ROOT /dev/mapper/system-root +mkfs.btrfs -L HOME /dev/mapper/system-home + +#mounting +swapon /dev/mapper/system-swap +mount -o compress=zstd /dev/mapper/system-root /mnt +mkdir -p /mnt/{home,boot,boot/efi,etc} +mount -o compress=zstd /dev/mapper/system-home /mnt/home +mount /dev/vda1 /mnt/boot/efi +``` + +Then create the fstab. + +```bash +genfstab -pU /mnt >> /mnt/etc/fstab +``` + +## 2) base installation + +### 2.1) installing required packages + +We'll use reflector to generate the mirrorlist. Adapt the country code to pick the closest mirrors. + +```bash +reflector -c FR -p https -a 12 --sort rate --save /etc/pacman.d/mirrorlist +``` + +Then install the required packages and some useful packages. + +```bash +pacstrap -i /mnt base base-devel linux linux-firmware linux-headers pacman-contrib man-pages btrfs-progs vim git bash-completion +``` + +### 2.2) chroot + +Chroot into the system to continue the installation. + +```bash +arch-chroot /mnt /bin/bash +``` + +#### 2.2.1) locales, hostname, clock and timezone + +In the file `/etc/locale.gen`, uncomment your locales (for example `en_US.UTF-8 UTF-8`) +You can also set your preferences for the virtual console in `/etc/vconsole.conf`, for example for a QWERTY layout: + +```ini +KEYMAP=us +FONT=lat9w-16 +``` + +And in `/etc/locale.conf` (LC_COLLATE=C for case sensitive sorting): + +```ini +LANG=en_US.UTF-8 +LC_COLLATE=C +``` + +And finally generate the locales: + +```bash +locale-gen +``` + +You can set your hostname in `/etc/hostname`. + +For your clock and timezone: (adapt to your timezone) + +```bash +ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime +hwclock --systohc --utc +``` + +#### 2.2.2) root password and user creation + +Set your root password with `passwd` +Then create a user (named sam here) in the wheel group (to use sudo) and set its password with: + +```bash +useradd -m -G wheel sam +passwd sam +``` + +and uncomment the line containing `%wheel ALL=(ALL:ALL) ALL` in `/etc/sudoers` + +#### 2.2.3) SELinux installation (from AUR) + +Log in as your created user and install an AUR helper to make things easier: + +```bash +su sam +cd +git clone https://aur.archlinux.org/yay.git +cd yay +makepkg -si +cd +``` + +Then install the required packages for SELinux to work. It will ask you for replacements with conflicting packages, answer yes every time. + +```bash +yay -S libsepol libselinux checkpolicy secilc setools libsemanage semodule-utils policycoreutils selinux-python python-ipy mcstrans restorecond +yay -S pam-selinux pambase-selinux coreutils-selinux findutils-selinux iproute2-selinux logrotate-selinux openssh-selinux psmisc-selinux shadow-selinux cronie-selinux +yay -S sudo-selinux +``` + +Note: If `sudo-selinux` fails to build, build it with `--nocheck` option: + +```bash +cd ~/.cache/yay/sudo-selinux +makepkg -si --nocheck +``` + +Then exit your user, remodify `/etc/sudoers` to uncomment the line containing `%wheel ALL=(ALL:ALL) ALL` and relog as your user. After that: + +```bash +sudo pacman -S less +yay -S systemd-selinux systemd-libs-selinux util-linux-selinux util-linux-libs-selinux +cd ~/.cache/yay/systemd-selinux +makepkg -si --nocheck +``` + +Due to a [cyclic dependency which won't be fixed](https://bugs.archlinux.org/task/39767) the complete build will fail at first, that's why you need to manually build systemd-selinux again after. For some reason less is also required for the build but not a build dependency. +Then more SELinux packages and a policy: + +```bash +yay -S selinux-alpm-hook dbus-selinux selinux-refpolicy-arch +``` + +If the check fails for `dbus-selinux` build it with `--nocheck` option: + +```bash +cd ~/.cache/yay/dbus-selinux +makepkg -si --nocheck +``` + +If you want to apply a fedora-style user context (as root): + +```bash +semanage login -m -s unconfined_u __default__ +``` + +#### 2.2.4) necessary packages + +Network for next boot: + +```bash +pacman -S networkmanager +systemctl enable NetworkManager +``` + +grub and lvm2: + +```bash +pacman -S grub efibootmgr lvm2 +``` + +Secure boot: +*Note: If you don't want to bother with secure boot, do not run sbctl related command, and later when generating the boot image with grub, remove* `--modules="tpm" --disable-shim-lock` *from the command* + +```bash +pacman -S sbctl +sbctl create-keys +sbctl enroll-keys -m +``` + +If you also want to enroll hardware security keys, use [systemd-cryptenroll](https://wiki.archlinux.org/title/Systemd-cryptenroll) + +#### 2.2.5) opional packages + +If you have an intel CPU: + +```bash +pacman -S intel-ucode +``` + +If you have a laptop and want battery optimization: + +```bash +pacman -S tlp +systemctl enable tlp +``` + +If you need bluetooth: + +```bash +pacman -S bluez +systemctl enable bluetooth +``` + +If you want 32bits apps (necessary for some packages), in `/etc/pacman.conf` uncomment these lines: + +```ini +#[multilib] +#include = /etc/pacman.d/mirrorlist +``` + +#### 2.2.5) generating boot images + +in `/etc/mkinitcpio.conf` on the `MODULES=()` line, add `dm-mod` and in the `HOOKS=()` line you should have: + +```ini +HOOKS=(base udev autodetect modconf block keyboard encrypt lvm2 filesystems fsck) +``` + +Then: + +```bash +mkinitcpio -p linux +``` + +sbctl post-hook should automatically sign `/boot/vmlinuz-linux`. Otherwise run: + +```bash +sbctl sign -s /boot/vmlinuz-linux +``` + +Then in `/etc/default/grub` ++ uncomment the line `GRUB_UNABLE_CRYPTODISK=y` ++ in `GRUB_CMDLINE_LINUX=""` add `cryptdevice=/dev/vda2:system root=/dev/mapper/system-root` ++ in `GRUB_CMDLINE_LINUX_DEFAULT=""` add `lsm=selinux,landlock,lockdown,yama,integrity,bpf` + +Then: + +```bash +grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=arch_grub --modules="tpm" --disable-shim-lock --recheck +grub-mkconfig -o /boot/grub/grub.cfg +sbctl sign -s /boot/efi/EFI/arch_grub/grubx64.efi +``` + +*Please note that in a virtual machine you'll need an emulated TPM for the virtual machine to boot if you want secure boot enabled.* + +### 3) exit and reboot + +```bash +exit # until you exit the chroot +umount -R /mnt +swapoff -a +reboot +``` + +### 4) post reboot steps + +#### 4.1) relabel files + +check SELinux status with `sestatus`, it should be in permissive with refpolicy-arch as the loaded policy. +Relabel all the files correctly with the following command: + +```bash +restorecon -RFv +``` + +you might want to clean yay cache before doing that to have less files to relabel: + +```bash +rm -rf ~/.cache/yay/* +``` + +#### 4.2) enable auditd + +enable auditd service to read AVC denials from SELinux later. + +```bash +systemctl enable --now auditd +``` + +#### 4.3) create and load necessary policy + +Create a file `requiredmod.te` with the following content: + +```text +module requiredmod 1.0; + +require { + type auditd_etc_t; + type getty_t; + type var_run_t; + type tmpfs_t; + type local_login_t; + type systemd_tmpfiles_t; + type init_runtime_t; + type devpts_t; + type kernel_t; + type device_t; + type udev_t; + type hugetlbfs_t; + type udev_tbl_t; + type policy_config_t; + type tmp_t; + type unconfined_t; + type var_lib_t; + type systemd_userdbd_runtime_t; + type systemd_user_runtime_dir_t; + type systemd_sessions_t; + type systemd_userdbd_t; + type etc_runtime_t; + type systemd_logind_t; + type file_context_t; + type semanage_t; + type selinux_config_t; + type initrc_runtime_t; + type sshd_t; + class dir { write add_name remove_name getattr open read search }; + class file { getattr open read write create getattr ioctl lock relabelfrom relabelto setattr unlink }; + class sock_file write; + class unix_stream_socket { read write ioctl connectto}; + class capability2 block_suspend; + class filesystem { associate quotaget quotamod }; + class key { link search }; + class process { noatsecure rlimitinh siginh transition }; + +} + +#============= getty_t ============== +allow getty_t tmpfs_t:dir { getattr open read }; +allow getty_t var_run_t:file { getattr open read }; +allow getty_t initrc_runtime_t:dir { getattr open read }; + +#============= local_login_t ============== +allow local_login_t init_runtime_t:sock_file write; +allow local_login_t systemd_logind_t:unix_stream_socket connectto; +allow local_login_t var_lib_t:dir { add_name remove_name }; +allow local_login_t var_lib_t:file { create getattr lock open read setattr unlink write }; + +#============= sshd_t ============== +allow sshd_t local_login_t:key { link search }; +allow sshd_t systemd_logind_t:unix_stream_socket connectto; +allow sshd_t unconfined_t:process { noatsecure rlimitinh siginh }; + +#============= systemd_tmpfiles_t ============== +allow systemd_tmpfiles_t auditd_etc_t:dir search; +allow systemd_tmpfiles_t auditd_etc_t:file getattr; + +#============= systemd_sessions_t ============== +allow systemd_sessions_t kernel_t:dir search; +allow systemd_sessions_t kernel_t:file { getattr ioctl open read }; + +#============= systemd_user_runtime_dir_t ============== +allow systemd_user_runtime_dir_t etc_runtime_t:file { open read }; +allow systemd_user_runtime_dir_t kernel_t:dir search; +allow systemd_user_runtime_dir_t kernel_t:file { getattr ioctl open read }; +allow systemd_user_runtime_dir_t systemd_userdbd_runtime_t:sock_file write; +allow systemd_user_runtime_dir_t systemd_userdbd_t:unix_stream_socket connectto; +allow systemd_user_runtime_dir_t tmp_t:dir read; +allow systemd_user_runtime_dir_t tmpfs_t:filesystem { quotaget quotamod }; + +#============= systemd_userdbd_t ============== +allow systemd_userdbd_t initrc_runtime_t:dir { getattr open read search }; + +#============= devpts_t ============== +allow devpts_t device_t:filesystem associate; + +#============= hugetlbfs_t ============== +allow hugetlbfs_t device_t:filesystem associate; + +#============= kernel_t ============== +allow kernel_t self:capability2 block_suspend; + +#============= tmpfs_t ============== +allow tmpfs_t device_t:filesystem associate; + +#============= udev_t ============== +allow udev_t kernel_t:unix_stream_socket { read write ioctl }; +allow udev_t udev_tbl_t:dir { write add_name }; +allow udev_t var_run_t:sock_file write; +``` + +Run the following command to compile and load the module: +```bash +checkmodule -m -o requiredmod.mod requiredmod.te +semodule_package -o requiredmod.pp -m requiredmod.mod +semodule -i requiredmod.pp +``` + +And set a few booleans: + +```bash +setsebool -P allow_polyinstantiation on +setsebool -P systemd_tmpfiles_manage_all on +setsebool -P ssh_sysadm_login on +``` + +Then in `/etc/selinux/config`, set SELinux mode to enforcing instead of permissive and reboot. +And that's it, you now have a minimal archlinux installation in UEFI with full disk encryption, secure boot, and SELinux in enforcing mode.