new post, install guide, archlinux with SELinux, full disk encryption and secure boot
This commit is contained in:
@@ -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.
|
||||||
Reference in New Issue
Block a user