Je viens de faire l’acquisition d’un NVME pour mon laptop, je garde cependant mon SSHD de 500Go afin d’y mettre mes données. Plutôt que de faire une copie de mon SSHD vers mon NVME, je me dis que refaire une installation complète pourrait être sympa.

Ce que je veux

Puisque j’ai un laptop que je bouge partout, il faut qu’il soit crypté …. (non je déconne, on dit chiffré, je voulais en faire râler certains ^^), c’est indispensable. J’ai 2 disques, le disque nvme de 250Go sera donc le disque système, et le deuxième de 500Go, sera le disque des partitions home.
Mon laptop est multi-utilisateurs, et je veux absolument que les homes de mes utilisateurs soient chiffrés indépendamment, donc exit crypttab, à la place j’utiliserai pam_mount.
Ensuite je voudrais utiliser btrfs pour entre autre son système de sous-volumes et de snapshots, le but étant de faire un snapshots à chaque modification systèmes.
Pour le reste, ça restera du basique, un environnement MATE, quelques logiciels, quelques tweaks, et ce sera bien.

Pour l’OS, j’ai choisi Wind…. Archlinux, pourquoi ? PARCE QUE !!!!!!

Pourquoi ArchLinux ???

J’ai commencé à utiliser ArchLinux en 2011, et depuis je n’arrive pas à changer de distribution, de temps en temps je me dis que je vais tester autres choses, mais au bout de quelques semaines, je reviens toujours sous Arch (et/ou dérivés).
J’aime Arch pour plusieurs raisons, déjà c’est du Rolling Release, donc toujours à jour, ensuite y’a un nombre de paquets impressionnants dans les repos, ce qui comble 90% de mes besoins (j’ai jamais atteint ça avec les autres distributions), et en plus il y a AUR qui me permets d’atteindre les 99,99%. Pacman, l’outil de gestion des paquets, est très performant, et très rapide, personnellement j’utilise yay, qui permets en plus de gérer les paquets AUR.
De plus ArchLinux à pour moi une petite histoire, c’est avec lui que j’ai mis les mains dedans (même si j’étais linuxiens depuis un moment), mais j’ai appris énormément, et pour moi, Archlinux est le meilleur compromis d’apprentissage entre des distributions dites “simples” (Ubuntu, Fedora, Debian, Mint etc …), et des sources-based comme Gentoo voir un LFS (y’a pas mieux pour l’apprentissage), y’a beaucoup d’action manuelle, mais cela reste accessible.

Installation de base

Préparation du media

Je pars du principe que vous savez récupérer une ISO et booter dessus, pour les plus faignants d’entre vous, vous pouvez la télécharger ici

Avant de commencer, il faut changer la disposition du clavier avec loadkeys (Attention clavier en qwerty de base) :

$ loadkeys fr-pc # donc on tape loqdkeys fr)pc

Puis si comme moi, vous utilisez un laptop, il faudra le connecter au wifi :

$ iwctl
[iwd]# device list
NetworkConfigurationEnabled: disabled
StateDirectory: /var/lib/iwd
Version: 1.28
[iwd]# device list
                                    Devices                                   *
--------------------------------------------------------------------------------
  Name                Address             Powered   Adapter   Mode
--------------------------------------------------------------------------------
  wlan0               XX:XX:XX:XX:XX:XX   on        phy0      station

[iwd]# station wlan0 scan
[iwd]# station wlan0 get-networks
                               Available networks                             *
--------------------------------------------------------------------------------
    Network name                    Security          Signal
--------------------------------------------------------------------------------
  > myhome_5GHz               psk               ****
    myhome                    psk               ****

[iwd]# station wlan0 connect myhome_5GHz
Type the network passphrase for myhome_5GHz psk.
Passphrase: **************************************
[iwd]# quit

Normalement vous êtes désormais connecté au réseau, pour vérifier, vous pouvez faire un :

$ ip a show dev wlan0
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether XX:XX:XX:XX:XX:XX brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.26/24 metric 600 brd 192.168.1.255 scope global dynamic wlan0
       valid_lft 86050sec preferred_lft 86050sec
    inet6 2a01:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/64 scope global temporary dynamic
       valid_lft 86368sec preferred_lft 568sec
    inet6 2a01:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/64 scope global dynamic mngtmpaddr noprefixroute
       valid_lft 86368sec preferred_lft 568sec
    inet6 fe80::XXXX:XXXX:XXXX:XXXX/64 scope link
       valid_lft forever preferred_lft forever

Personnellement, je vais me connecter sur mon laptop en ssh, pour pouvoir copier des commandes plus rapidement, pour ceci il suffit d’ajouter un mot de passe à root :

$ passwd
New password:
Retype new password:
passwd: password updated successfully

et via l’ip local récupéré plus haut, vous pouvez y accéder.

Partitionnement du disque

Comme dis tout à l’heure, je vais chiffrer mon installation, et utiliser btrfs, mais il faut tout de même une partition /boot.
Personnellement, je ne chiffre pas le /boot, pour une raison simple, je n’ai jamais réussi à changer la disposition du clavier à ce stade, donc compliqué pour mon mot de passe. De plus, mon risque de corruption de mon /boot est plutôt faible, puisque c’est mon PC perso, et à part moi, personnes chez moi et dans mes connaissances ne pourraient le faire.

Etrangement, mon NVME est simplement détecté en SSD standard, je l’ai testé sur mon Desktop, et il est pourtant reconnu en NVME. Cela ne bloque en aucun cas la procédure.

Pour le disque system :

$ parted /dev/sdb
(parted) mklabel gpt
(parted) mkpart "EFI system partition" fat32 0% 500MiB 
(parted) set 1 esp on 
(parted) mkpart "system" btrfs 500MiB 100%
(parted) quit

Pour le home, je vais devoir utiliser lvm, car btrfs ne supporte pas le chiffrement d’un sous-volumes :

$ parted /dev/sda
(parted) mkpart "home" btrfs 0% 100%
(parted) quit
$ pvcreate /dev/sda1
  Physical volume "/dev/sda1" successfully created.
$ vgcreate vghome /dev/sda1
  Volume group "vghome" successfully created 

Pour le moment je ne crée pas de volume logique, nous verrons plus tard pour les homes des utilisateurs.

Chiffrement via luks

On commence par chiffrer le disque système :

$ cryptsetup luksFormat /dev/sdb2

WARNING!
========
This will overwrite data on /dev/sdb2 irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/sdb2:
Verify passphrase:
cryptsetup luksFormat /dev/sdb2  19.12s user 0.36s system 84% cpu 23.158 total

Pour le moment j’ai mis une passphrase générique, d’environ 30 caractères, qui servira de passphrase de secours. Ensuite chaque passphrase de chaques utilisateurs sera également ajouté à ce volume, nous y reviendrons.

Puis on ouvre le conteneur system chiffré :

$ cryptsetup luksOpen /dev/sdb2 crypt-system
Enter passphrase for /dev/sdb2:

On peut donc les voir dans /dev/mapper :

$ ls /dev/mapper
control  crypt-system

Formatage des partitions

Nous partitions /dev/sdb1 en fat32, et le reste en btrfs évidemment

$ mkfs.fat -F32 /dev/sdb1
mkfs.fat 4.2 (2021-01-31)
$ mkfs.btrfs /dev/mapper/crypt-system
btrfs-progs v5.18.1
See http://btrfs.wiki.kernel.org for more information.

NOTE: several default settings have changed in version 5.15, please make sure
      this does not affect your deployments:
      - DUP for metadata (-m dup)
      - enabled no-holes (-O no-holes)
      - enabled free-space-tree (-R free-space-tree)

Label:              (null)
UUID:               57c59ad7-848b-41a9-a79c-de2269f01cb5
Node size:          16384
Sector size:        4096
Filesystem size:    223.07GiB
Block group profiles:
  Data:             single            8.00MiB
  Metadata:         DUP               1.00GiB
  System:           DUP               8.00MiB
SSD detected:       yes
Zoned device:       no
Incompat features:  extref, skinny-metadata, no-holes
Runtime features:   free-space-tree
Checksum:           crc32c
Number of devices:  1
Devices:
   ID        SIZE  PATH
    1   223.07GiB  /dev/mapper/crypt-system

Création des sous-volumes btrfs

Pour ceci, nous allons déjà monter nos partitions :

$ mount /dev/mapper/crypt-system /mnt

Puis nous créons différents sous-volumes, sur le system nous aurons :

  • @ pour le /
  • @root pour le /root
  • @log pour le /var/log
  • @opt pour le /opt
  • @tmp pour le /tmp (à voir si j’utilise un tmpfs)
  • @snapshots pour les /.snapshots

Pourquoi utiliser des sous-volumes ?
Ce n’est pas une obligation, mais personnellement, je vais ajouter un hook à pacman, pour qu’à chaque installations ou mise à jours, il génère un snapshots de @, mais je ne veux pas faire de snapshots des logs, des temporaires, du /root ou même du /opt, mais seulement de tout le reste.

Donc pour créer les sous-volumes, nous utiliserons btrfs subvolume create <PATH> :

$ btrfs subvolume create /mnt/@
Create subvolume '/mnt/@'
$ btrfs subvolume create /mnt/@root
Create subvolume '/mnt/@root'
$ btrfs subvolume create /mnt/@log
Create subvolume '/mnt/@log'
$ btrfs subvolume create /mnt/@opt
Create subvolume '/mnt/@opt'
$ btrfs subvolume create /mnt/@tmp
Create subvolume '/mnt/@tmp'
$ btrfs subvolume create /mnt/@snapshots
Create subvolume '/mnt/@snapshots'

Puis nous pouvons démonter notre /mnt :

$ umount -R /mnt

Pour le home, on partira sur un sous-volumes LVM par utilisateurs, mais nous verrons ceci plus tard.

Montage des partitions

Pour pouvoir installer nos paquets, nous devons monter les partitions, nous procédons comme ceci :

$ mount -o subvol=@,defaults,noatime,nodiratime,ssd,compress=zstd /dev/mapper/crypt-system /mnt
$ mkdir -p /mnt/{var/log,boot,root,.snapshots,tmp,opt}
$ mount -o subvol=@root,defaults,noatime,nodiratime,ssd,compress=zstd /dev/mapper/crypt-system /mnt/root
$ mount -o subvol=@log,defaults,noatime,nodiratime,ssd,compress=zstd /dev/mapper/crypt-system /mnt/var/log
$ mount -o subvol=@opt,defaults,noatime,nodiratime,ssd,compress=zstd /dev/mapper/crypt-system /mnt/opt
$ mount -o subvol=@tmp,defaults,noatime,nodiratime,ssd,compress=zstd /dev/mapper/crypt-system /mnt/tmp
$ mount -o subvol=@snapshots,defaults,noatime,nodiratime,ssd,compress=zstd /dev/mapper/crypt-system /mnt/.snapshots
$ mount /dev/sdb1 /mnt/boot

Installation de Archlinux

Installation minimal

Avant d’installer la base, nous allons choisir les meilleurs mirroir pour nous, perso j’utilise reflector pour ceci :

$ reflector --country France --latest 10 --sort rate --save /etc/pacman.d/mirrorlist

Maintenant nous pouvons installer les paquets :

$ pacstrap /mnt \
        base \
        linux-zen \
        linux-firmware \
        vim \
        net-tools \
        wireless_tools \
        btrfs-progs \
        lvm2 \
        wget \
        curl \
        zsh \
        sudo \
        iwd \
        dhclient \
        intel-ucode # ou amd-ucode si processeur amd

J’aime bien le kernel Zen, qui offre de bonne performance, et moins de mise à jour que celui de base.

Puis nous générons le fstab :

$ genfstab -U -p /mnt >> /mnt/etc/fstab
$ cat /mnt/etc/fstab
# Static information about the filesystems.
# See fstab(5) for details.

# <file system> <dir> <type> <options> <dump> <pass>
# /dev/mapper/crypt-system
UUID=50117f74-7c40-43ef-918b-c14d59c47450       /               btrfs           rw,noatime,nodiratime,compress=zstd:3,ssd,space_cache=v2,subvolid=256,subvol=/@       0 0

# /dev/mapper/crypt-system
UUID=50117f74-7c40-43ef-918b-c14d59c47450       /root           btrfs           rw,noatime,nodiratime,compress=zstd:3,ssd,space_cache=v2,subvolid=257,subvol=/@root   0 0

# /dev/mapper/crypt-system
UUID=50117f74-7c40-43ef-918b-c14d59c47450       /var/log        btrfs           rw,noatime,nodiratime,compress=zstd:3,ssd,space_cache=v2,subvolid=258,subvol=/@log    0 0

# /dev/mapper/crypt-system
UUID=50117f74-7c40-43ef-918b-c14d59c47450       /opt            btrfs           rw,noatime,nodiratime,compress=zstd:3,ssd,space_cache=v2,subvolid=259,subvol=/@opt    0 0

# /dev/mapper/crypt-system
UUID=50117f74-7c40-43ef-918b-c14d59c47450       /tmp            btrfs           rw,noatime,nodiratime,compress=zstd:3,ssd,space_cache=v2,subvolid=260,subvol=/@tmp    0 0

# /dev/mapper/crypt-system
UUID=50117f74-7c40-43ef-918b-c14d59c47450       /.snapshots     btrfs           rw,noatime,nodiratime,compress=zstd:3,ssd,space_cache=v2,subvolid=261,subvol=/@snapshots      0 0

Configuration de base

Pour configurer notre système, nous allons chrooter, c’est à dire, changer le répertoire / de notre système, mais avant, je vais copier le mirrorlist :

$ cp /etc/pacman.d/mirrorlist /mnt/etc/pacman.d/mirrorlist
$ arch-chroot /mnt
[root@archiso /]#

Nous allons modifier quelques fichiers :

$ echo "KEYMAP=fr" > /etc/vconsole.conf
$ echo -e "en_US.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8" > /etc/locale.gen
$ locale-gen
$ echo "LANG=fr_FR.UTF-8" >> /etc/locale.conf
$ echo "laptop" > /etc/hostname

Configuration du initramfs

Il faudra modifier la variable HOOKS dans le /etc/mkinitcpio.conf :

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

puis on génére l’image d’init :

$ mkinitcpio -p linux-zen

Installation du chargeur de démarrage

Puisque nous sommes sur arch, avec systemd donc, autant utiliser systemd-boot qui est déjà installé :

$ bootctl --esp-path=/boot install
Created "/boot/EFI".
Created "/boot/EFI/systemd".
Created "/boot/EFI/BOOT".
Created "/boot/loader".
Created "/boot/loader/entries".
Created "/boot/EFI/Linux".
Copied "/usr/lib/systemd/boot/efi/systemd-bootx64.efi" to "/boot/EFI/systemd/systemd-bootx64.efi".
Copied "/usr/lib/systemd/boot/efi/systemd-bootx64.efi" to "/boot/EFI/BOOT/BOOTX64.EFI".
Random seed file /boot/loader/random-seed successfully written (32 bytes).
Not booted with EFI, skipping EFI variable setup.
Not booted with EFI, skipping EFI variable setup.

Récupérez l’UUID de votre partition :

$ blkid | grep sdb2
/dev/sdb2: UUID="50117f74-7c40-43ef-918b-c14d59c47450" TYPE="crypto_LUKS" PARTLABEL="crypt-system" PARTUUID="40178r52-5g10-75gf-541g-c45d75g45785"

On crée un fichier /boot/loader/entries/arch.conf :

title Arch Linux
linux /vmlinuz-linux-zen
initrd /intel-ucode.img # ou /amd-ucode.img
initrd /initramfs-linux-zen.img
options rd.luks.uuid=50117f74-7c40-43ef-918b-c14d59c47450 root=/dev/mapper/luks-50117f74-7c40-43ef-918b-c14d59c47450 rootflags=subvol=@ rd.luks.options=discard quiet nowatchdog splash rw

Nous pouvons également ajouter une entrée pour le fallback (/boot/loader/entries/arch-fallback.conf) :

title Arch Linux
linux /vmlinuz-linux-zen-fallback
initrd /intel-ucode.img # ou /amd-ucode.img
initrd /initramfs-linux-zen-fallback.img
options rd.luks.uuid=50117f74-7c40-43ef-918b-c14d59c47450 root=/dev/mapper/luks-50117f74-7c40-43ef-918b-c14d59c47450 rootflags=subvol=@ rd.luks.options=discard quiet nowatchdog splash rw

ainsi que /boot/loader/loader.conf :

default arch.conf
editor no
timeout 4
console-mode max

Redémarrage

Voici le moment de vérité, il faut maintenant rebooter la machine, mais avant ceci, nous allons créer un mdp root :

[root@archiso /]$ passwd
New password:
Retype new password:
passwd: password updated successfully
[root@archiso /]$ exit
$ umount -R /mnt
$ reboot

Normalement, au boot il est censé vous demander de rentrer le mot de passe de votre disque dur.

Puis vous accédez à l’authentification.

Si vous êtes en wifi, il vous faudra vous reconnecter

$ systemctl start iwd
$ iwctl station wlan0 connect myhome_5GHz
$ dhclient wlan0

Gestion des utilisateurs

Comme vous l’avez remarqué, je n’ai pas créé d’utilisateur pour le moment, mais simplement un VG pour y mettre mes homes.
Beaucoup aurait créer une seul partition home, chiffré avec une clé, et monté via crypttab, cependant, dans le cadre d’un PC multi-utilisateur, je préfère créer une partition par utilisateurs, et de chiffrer celle-ci indépendamment avec un mot de passe unique, afin que l’utilisateur X, n’est pas accès au fichier de l’utilisateur Y et vice-versa.

pam_mount

Pour ceci nous utiliserons pam_mount, qu’il faut donc installer :

$ pacman -S pam_mount

Puis il faut modifier le fichier /etc/pam.d/system-login :

auth       required   pam_shells.so
auth       requisite  pam_nologin.so
auth       optional   pam_mount.so
auth       include    system-auth

account    required   pam_access.so
account    required   pam_nologin.so
account    include    system-auth

password   optional   pam_mount.so
password   include    system-auth

session    optional   pam_loginuid.so
session    optional   pam_keyinit.so       force revoke
session [success=1 default=ignore]  pam_succeed_if.so  service = systemd-user quiet
session    optional   pam_mount.so
session    include    system-auth
session    optional   pam_motd.so          motd=/etc/motd
session    optional   pam_mail.so          dir=/var/spool/mail standard quiet
-session   optional   pam_systemd.so
session    required   pam_env.so           user_readenv=1

Création de l’utilisateur xataz

Création du volume de l’utilisateur

Pour ça c’est plutôt simple :

$ lvcreate -L200G -n xataz vghome
  Logical volume "xataz" created.

Chiffrement du volume

On réutilise cryptsetup pour chiffrer notre volume, en utilisant le mot de passe que nous voudrons pour cet utilisateur :

$ cryptsetup luksFormat /dev/mapper/vghome-xataz

ATTENTION !
===========
Cette action écrasera définitivement les données sur /dev/mapper/vghome-xataz.

Êtes-vous sûr ? (Typez « yes » en majuscules) : YES
Saisissez la phrase secrète pour /dev/mapper/vghome-xataz :
Vérifiez la phrase secrète :

Puis nous déverrouillons notre conteneur chiffré :

$ cryptsetup luksOpen /dev/mapper/vghome-xataz xataz
Saisissez la phrase secrète pour /dev/mapper/vghome-xataz :
$

Formatage et montage du volume

On formate en btrfs donc :
$ mkfs.btrfs /dev/mapper/xataz
btrfs-progs v5.18.1
See http://btrfs.wiki.kernel.org for more information.

NOTE: several default settings have changed in version 5.15, please make sure
      this does not affect your deployments:
      - DUP for metadata (-m dup)
      - enabled no-holes (-O no-holes)
      - enabled free-space-tree (-R free-space-tree)

Label:              (null)
UUID:               40b7a970-333f-44ce-ad82-d2f9e6156bab
Node size:          16384
Sector size:        4096
Filesystem size:    199.98GiB
Block group profiles:
  Data:             single            8.00MiB
  Metadata:         DUP               1.00GiB
  System:           DUP               8.00MiB
SSD detected:       no
Zoned device:       no
Incompat features:  extref, skinny-metadata, no-holes
Runtime features:   free-space-tree
Checksum:           crc32c
Number of devices:  1
Devices:
   ID        SIZE  PATH
    1   199.98GiB  /dev/mapper/xataz

et on monte

$ mkdir /home/xataz
$ mount /dev/mapper/xataz /home/xataz

J’ai pour habitude de toujours créer 2 sous-volumes, un pour la racine et l’autre pour les snapshots :

$ btrfs subvolume create /home/xataz/@
Create subvolume '/home/xataz/@'
$ btrfs subvolume create /home/xataz/@snapshots
Create subvolume '/home/xataz/@snapshots'

Création de l’utilisateur

$ useradd --no-create-home --home-dir /home/xataz/ --shell /bin/zsh xataz
$ chown -R xataz: /home/xataz
$ passwd xataz
Nouveau mot de passe :
Retapez le nouveau mot de passe :
passwd: password updated successfully

Ajout du mdp de l’utilisateur dans le volume chiffré system

Afin que mon utilisateur n’ai pas à connaitre le mot de passe super-admin de fou du volume system, j’ajoutes son mot de passe à celui-ci :

$ cryptsetup luksAddKey /dev/sdb2
Entrez une phrase secrète existante :
Entrez une nouvelle phrase secrète pour l'emplacement de clé :
Vérifiez la phrase secrète :

Configuration du pam_mount.conf.xml

Il ne nous reste plus qu’à créer la configuration pour pam_mount, afin de monter la partition home, seulement lors de la connexion.
Pour cela, nous allons modifier le fichier /etc/security/pam_mount.conf.xml :

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE pam_mount SYSTEM "pam_mount.conf.xml.dtd">
<pam_mount>
  <debug enable="0" />
  <mntoptions allow="nosuid,nodev,loop,encryption,fsck,nonempty,allow_root,allow_other" />
  <mntoptions require="nosuid,nodev" />
  <logout wait="0" hup="no" term="no" kill="no" />
  <mkmountpoint enable="1" remove="true" />

  <volume user="xataz" fstype="crypt" path="/dev/vghome/xataz" mountpoint="~" options="subvol=@,allow_discard,fstype=btrfs,compress=zstd" />
  <volume user="xataz" path="/dev/disk/by-uuid/54cd455hdf-d613-47fd-b1fc-2f24daf12dbe" mountpoint="~/.snapshots" options="subvol=@snapshots,allow_discard,fstype=btrfs,compress=zstd" />
</pam_mount>

Par contre nous avons un soucis lors de la déconnexion, les répertoires home ne se démontent pas.
Je n’ai trouvé aucune solution satisfaisante, certains utilisent une crontrab par exemple qui check toutes les minutes la présence ou non d’un processus utilisateur, je trouvais cela pas très propre.

En regardant les logs, j’ai vu qu’a la déconnexion, le service user@.service était appelé, j’ai donc décidé de créer un service systemd pour ceci, qui s’exécutera lors de la dernière session fermé, pour ceci il suffit :

Création du script /usr/lib/systemd/systemd-user-crypthome-dir :

#!/bin/bash

user=$(id -nu $2)

if [ "$1" == "stop" ]; then
    luksMapper=$(mount | grep -w $user | awk '{print $1}')
    umount -R /home/$user
    cryptsetup luksClose $luksMapper
fi

Puis on le rends exécutable avec chmod +x /usr/lib/systemd/systemd-user-crypthome-dir

Ensuite nous créons un service, via le fichier /usr/lib/systemd/system/systemd-user-crypthome-dir@.service :

[Unit]
Description=Umount encrypted home dir
After=systemd-user-sessions.service dbus.service
StopWhenUnneeded=yes
IgnoreOnIsolate=yes

[Service]
ExecStart=/usr/lib/systemd/systemd-user-crypthome-dir start %i
ExecStop=/usr/lib/systemd/systemd-user-crypthome-dir stop %i
Type=oneshot
RemainAfterExit=yes
Slice=user-%i.slice

Il faut forcément un ExecStart, il ne fera rien ici, mais ce n’est pas grave.

Et ensuite, il faut ajouter ce service en Require dans /usr/lib/systemd/system/user@.service :

[...]
Requires=user-runtime-dir@%i.service systemd-user-crypthome-dir@%i.service
[...]

En fait avec systemd-login, le service user@.service est exécuté, et sera réexécuté lors de la fermeture de la dernière session, ce qui aura pour but de démonter votre home.

Création d’un script pour simplifier ceci

Maintenant que nous l’avons fait à la main, c’est toujours mieux de simplifier, je vous donne donc mon script fait rapidement pour l’occasion :

#!/bin/bash


## Config ##
VG=vghome
TYPEFS=btrfs
DEFAULT_SIZE=100G
DEFAULT_SHELL=/bin/zsh
############


echo -e "Username: \c"
read USERNAME
echo -e "Password: \c"
read -s PASSWORD
echo -e "\nRetype Password: \c"
read -s RETYPEPASSWORD
echo -e "\nSize home: (default: $DEFAULT_SIZE) \c"
read SIZE
echo -e "Shell: (default: $DEFAULT_SHELL) \c"
read SHELL

if [ "$PASSWORD" != "$RETYPEPASSWORD" ]; then
	echo "Password doesn't match"
	exit 1	
fi

tmpfile=$(mktemp)
echo -n "$PASSWORD" > $tmpfile

if [ "$SIZE" == "" ]; then SIZE=$DEFAULT_SIZE; fi
if [ "$SHELL" == "" ]; then SHELL=$DEFAULT_SHELL; fi

echo "Create partition"
lvcreate -L $SIZE -n $USERNAME $VG

echo "Encrypt partition"
cat $tmpfile | cryptsetup luksFormat /dev/mapper/vghome-$USERNAME

echo "Open partition"
cat $tmpfile | cryptsetup luksOpen /dev/mapper/vghome-$USERNAME $USERNAME

echo "Format partition"
mkfs.$TYPEFS /dev/mapper/$USERNAME

echo "Mount partition"
mkdir -p /home/$USERNAME/.snapshots
mount /dev/mapper/$USERNAME /home/$USERNAME
UUID=$(blkid | grep "/dev/mapper/$USERNAME" | awk '{print $2}' | cut -d'"' -f2)

echo "Create subvolume"
btrfs subvolume create /home/$USERNAME/@
btrfs subvolume create /home/$USERNAME/@snapshots

echo "Create user"
useradd --no-create-home --home-dir /home/$USERNAME/ --shell $SHELL $USERNAME
echo -e "$PASSWORD\n$PASSWORD" | passwd $USERNAME
chown -R $USERNAME: /home/$USERNAME

echo "Add password on system partition"
cryptsetup luksAddKey /dev/sdb2 $tmpfile

echo "Configuration du pam_mount"
sed -i "s#</pam_mount>#  <volume user=\"$USERNAME\" fstype=\"crypt\" path=\"/dev/vghome/$USERNAME\" mountpoint=\"~\" options=\"subvol=@,allow_discard,fstype=btrfs,compress=zstd\" />\n</pam_mount>#" /etc/security/pam_mount.conf.xml
sed -i "s#</pam_mount>#  <volume user=\"$USERNAME\" path=\"/dev/disk/by-uuid/$UUID\" mountpoint=\"~/.snapshots\" options=\"subvol=@snapshots,allow_discard,fstype=btrfs,compress=zstd\" />\n</pam_mount>#" /etc/security/pam_mount.conf.xml

echo "Cleanup"
umount /home/$USERNAME
cryptsetup luksClose /dev/mapper/$USERNAME
unset $PASSWORD
unset $RETYPEPASSWORD
unset $USERNAME
unset $SIZE
unset $SHELL
rm -rf $tmpfile

C’est loin d’être parfait, mais ça fonctionne, y’a surement de l’optimisation à faire, et ajouter une option pour supprimer l’utilisateur, mais aussi le modifier.

Et quand on l’exécute :

$ create_user
Username: copine
Password:
Retype Password:
Size home (default: 100G): 
Shell (default: /bin/zsh): 
Create partition
WARNING: crypto_LUKS signature detected on /dev/vghome/copine at offset 0. Wipe it? [y/n]: y
  Wiping crypto_LUKS signature on /dev/vghome/copine.
WARNING: crypto_LUKS signature detected on /dev/vghome/copine at offset 16384. Wipe it? [y/n]: y
  Wiping crypto_LUKS signature on /dev/vghome/copine.
  Logical volume "copine" created.
Encrypt partition
Open partition
Format partition
btrfs-progs v5.18.1
See http://btrfs.wiki.kernel.org for more information.

NOTE: several default settings have changed in version 5.15, please make sure
      this does not affect your deployments:
      - DUP for metadata (-m dup)
      - enabled no-holes (-O no-holes)
      - enabled free-space-tree (-R free-space-tree)

Label:              (null)
UUID:               2c5107c8-8aea-49ba-b507-8cec54183fc6
Node size:          16384
Sector size:        4096
Filesystem size:    99.98GiB
Block group profiles:
  Data:             single            8.00MiB
  Metadata:         DUP               1.00GiB
  System:           DUP               8.00MiB
SSD detected:       no
Zoned device:       no
Incompat features:  extref, skinny-metadata, no-holes
Runtime features:   free-space-tree
Checksum:           crc32c
Number of devices:  1
Devices:
   ID        SIZE  PATH
    1    99.98GiB  /dev/mapper/copine

Mount partition
Create snapshots subvolume
Create subvolume '/home/copine/@snapshots'
Create user
Nouveau mot de passe : Retapez le nouveau mot de passe : passwd: password updated successfully
Add password on system partition
Entrez une phrase secrète existante :
Configuration du pam_mount
Cleanup

Et voilà, mon nouvel utilisateur est correctement créer, avec sa partition, chiffré par son mot de passe unique que je ne connais pas, de plus, elle peux aussi déchiffrer le disque système avec son mot de passe à elle.

Tweak de Archlinux

Snapshots automatique

Archlinux étant une distribution en rolling Release, et même si les régressions sont devenu très rare, je pense qu’il est indispensable de faire un snapshots avant chaque modification de paquets (Installation, Mise à jour ou même suppression). Pour ceci, nous avons les Hooks pacman.
Un hook est une action qui sera exécutée avant ou après la modification de paquet.

Les snapshots avec btrfs

Pour faire un snapshots avec btrfs, c’est plutôt simple :

$ btrfs subvolume snapshot / /.snapshot/testsnapshot
Create a snapshot of '/' in '/.snapshots/testsnapshot'

Cependant il est facile de créer et supprimer des snapshots, mais les restaurer et faire des rollbacks, c’est beaucoup plus compliqué. Le but ici n’est pas d’expliquer toute les possibilité de btrfs, ceci fera surement l’objet d’un futur article.

Création du hook

Pour ceci, il faut créer le fichier /etc/pacman.d/hooks/snapshots.hook :

[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = *

[Action]
Depends = coreutils
When = PreTransaction
Exec = /usr/local/bin/btrfs-snapshots

Donc là en gros, avant toute transaction (When = PreTransaction), et pour les installations, mises à jour et Suppression de paquet, il faut exécuter /usr/local/bin/btrfs-snapshots.

Et voici le script (très simple) de la génération de snapshots /usr/local/bin/btrfs-snapshots :

#!/bin/bash

DATE=$(date +%Y%m%d%H%M%S)

echo "Snapshot /"
btrfs subvolume snapshot / /.snapshots/auto-snapshot-$DATE

Là par exemple, ça tombe bien, j’avais des mises à jour à faire, donc je le lance :

$ pacman -Syu
pacman -Syu
:: Synchronisation des bases de données de paquets…
 core                                                                                                                                  158,3 KiB   464 KiB/s 00:00 [#####################################################################################################] 100% extra                                                                                                                                1827,3 KiB  20,7 MiB/s 00:00 [#####################################################################################################] 100% community                                                                                                                               6,8 MiB  28,7 MiB/s 00:00 [#####################################################################################################] 100%:: Début de la mise à jour complète du système…
résolution des dépendances…
recherche des conflits entre paquets…

Paquets (11) binutils-2.39-3  btrfs-progs-5.19-1  ca-certificates-mozilla-3.82-1  gcc-libs-12.2.0-1  glibc-2.36-3  gnutls-3.7.7-3  ldns-1.8.3-1  linux-zen-5.19.3.zen1-1  tzdata-2022c-1  vim-9.0.0236-1  vim-runtime-9.0.0236-1

Taille totale du téléchargement :  249,94 MiB
Taille totale installée :          460,41 MiB
Taille de mise à jour nette :       -0,09 MiB

:: Procéder à l’installation ? [O/n]
[...]
:: Exécution des crochets (« hooks ») de pré-transaction…
(1/2) Removing linux initcpios...
(2/2) snapshots.hook
Snapshot /
Create a snapshot of '/' in '/.snapshots/auto-snapshot-20220823125324'
:: Traitement des changements du paquet…
( 1/11) mise à jour de tzdata                                                                                                                                      [#####################################################################################################] 100%
[...]
:: Exécution des crochets (« hooks ») de post-transaction…
(1/7) Reloading system manager configuration...
(2/7) Creating temporary files...
(3/7) Reloading device manager configuration...
(4/7) Arming ConditionNeedsUpdate...
(5/7) Rebuilding certificate stores...
(6/7) Updating module dependencies...
(7/7) Updating linux initcpios...
[...]

et comme on peux le voir, j’ai bien un snapshot :

$ btrfs subvolume list -s /
ID 274 gen 396 cgen 396 top level 261 otime 2022-08-23 12:53:25 path @snapshots/auto-snapshot-20220823125324

Purge des snapshots

Il peux être sympa de purger un peu les snapshots, j’ai également un petit script pour ceci :

NB_REMEMBER_SNAPSHOTS=5
NB_SNAPSHOTS=$(btrfs subvol list -s / | wc -l)
if [ $NB_REMEMBER_SNAPSHOTS -lt $NB_SNAPSHOTS ]; then
    NB_DELETE_SNAPSHOTS=$(($NB_SNAPSHOTS-$NB_REMEMBER_SNAPSHOTS))
    for i in $(btrfs subvol list -s / | head -$NB_DELETE_SNAPSHOTS | awk '{print $14}' | sed 's#@#/.#'); do btrfs subvol delete $i; done
fi

Là il garde seulement les 5 derniers snapshots.
Nous pouvons ajouter ce script au script de snapshots.

Génération du menu systemd-boot

Alors là c’est un peu plus compliqué, perso, je suis un bourrin, je vous code :

rm -rf /boot/loader/entries/snapshots*

LIST_SNAPSHOTS=$(ls /.snapshots)

for snapshot in $LIST_SNAPSHOTS; do
    date=$(echo $snapshot | cut -d"-" -f3)
    sed -e "s#^title.*#title Arch Linux Snapshot ($date)#" \
        -e "s#rootflags=subvol=@#rootflags=subvol=@snapshots/$snapshot#" \
        /boot/loader/entries/arch.conf > /boot/loader/entries/${snapshot}.conf
done

Nous pouvons également l’ajouter ce script au script de snapshots.

/usr/local/bin/btrfs-snapshots complet

Une fois complet, mon script de snapshots ressemble à ceci :

#!/bin/bash

### CONFIG ###
NB_REMEMBER_SNAPSHOTS=5
##############

DATE=$(date +%Y%m%d%H%M%S)

echo "Snapshot /"
btrfs subvolume snapshot / /.snapshots/auto-snapshot-$DATE

echo "Remove old snapshots"
NB_SNAPSHOTS=$(btrfs subvol list -s / | wc -l)
if [ $NB_REMEMBER_SNAPSHOTS -lt $NB_SNAPSHOTS ]; then
    NB_DELETE_SNAPSHOTS=$(($NB_SNAPSHOTS-$NB_REMEMBER_SNAPSHOTS))
    for i in $(btrfs subvol list -s / | head -$NB_DELETE_SNAPSHOTS | awk '{print $14}' | sed 's#@#/.#'); do btrfs subvol delete $i; done
fi

echo "Generate systemd-boot menu"
rm -rf /boot/loader/entries/snapshots*

LIST_SNAPSHOTS=$(ls /.snapshots)

for snapshot in $LIST_SNAPSHOTS; do
    date=$(echo $snapshot | cut -d"-" -f3)
    sed -e "s#^title.*#title Arch Linux Snapshot ($date)#" \
        -e "s#rootflags=subvol=@#rootflags=subvol=@snapshots/$snapshot#" \
        /boot/loader/entries/arch.conf > /boot/loader/entries/${snapshot}.conf
done

Backup du noyau

Le problème, c’est que ma partition /boot est séparée, donc les kernels ne sont pas inclus dans le snapshot. Il est important aussi de sauvegarder ceci, donc nous pouvons également le faire via les hooks :

Création du hook

On crée donc le hook /etc/pacman.d/hooks/linux-zen.hook :

[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = linux-zen

[Action]
When = PreTransaction
Exec = /usr/local/bin/backup-linux-zen

la petite particularité, c’est le Target = linux-zen, qui veut dire en gros que ce hook ne sera exécuté que si c’est le package linux-zen qui est modifié.

Création du script

On crée également le script /usr/local/bin/backup-linux-zen :

#!/bin/bash

cp -f /boot/vmlinuz-linux-zen{,.old}
cp -f /boot/initramfs-linux-zen.img{,.old}
cp -f /boot/initramfs-linux-zen-fallback.img{,.old}

Puis on le rend exécutable :

$ chmod +x /usr/local/bin/backup-linux-zen

Création de l’entrée systemd-boot

Pour ceci c’est plutôt simple, nous allons créer le fichier /boot/loader/entries/archold.conf :

title Arch Linux OLD kernel
linux /vmlinuz-linux-zen.old
initrd /intel-ucode.img.old
initrd /initramfs-linux-zen.img.old
options rd.luks.uuid=b432b224-c656-4ba8-9010-3475da5aafbc root=UUID="57c59ad7-848b-41a9-a79c-de2269f01cb5" rootflags=subvol=@ rd.luks.options=discard quiet nowatchdog splash rw

Et voilà, désormais notre kernel sera sauvegardé s’il y a une modification de celui-ci, bon là je ne garde que la dernière version, mais pour moi c’est suffisant.

Installation de MATE

Cette partie n’aura rien de particulier, car c’est du basique pour ceux ayant déjà installé une Archlinux

Installation des paquets

On installe quelques paquets, alors que certains installent d’abord xorg, puis mate, et pour finir par lightdm (ou autre), moi je préfère installer tout en une seule fois.

$ pacman -S xorg xorg-server mate mate-extra lightdm lightdm-gtk-greeter networkmanager network-manager-applet xdg-user-dirs
[...]

pour configurer le bon clavier sur x11 :

$ localectl set-x11-keymap fr

On configure network-manager pour utiliser iwd en créant le fichier /etc/NetworkManager/conf.d/wifi_backend.conf :

[device]
wifi.backend=iwd

puis on lance lightdm :

$ systemctl enable iwd
$ systemctl enable NetworkManager
$ systemctl enable lightdm
$ reboot

Installation des logiciels

Premier logiciel à installer, c’est yay, mais non disponible sur les repos, mais sur AUR, assez marrant, yay permets l’installation depuis AUR, mais est sur AUR aussi.
Pour l’installer, nous aurons besoin de base-devel et git :

$ pacman -S git base-devel

On télécharge le repo git (a faire avec un utilisateur non root):

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

il va également falloir activer les repos multilib, pour installer des logiciels comme Steam ou lutris, pour ceci on modifie le fichier /etc/pacman.conf :

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

et c’est good, maintenant plus qu’à installer mes logiciels, je vous mets la commande en vrac, elle n’est pas forcément complète :

$ yay -Syu firefox firefox-i18n-fr brave-bin mpv libreoffice-fresh libreoffice-fresh-fr \
ulauncher youtube-dl \
bitwarden bitwarden-cli \
terminator code postman-bin neovim rustup python-pip pgadmin4 \
teams discord element-desktop \
steam steam-native-runtime lutris vulkan-intel lib32-vulkan-intel \
qemu-full virt-manager virt-viewer dnsmasq vde2 bridge-utils openbsd-netcat ebtables libguestfs snapd \
vagrant podman terraform minio-client scaleway-cli aws-cli azure-cli-bin ansible kubectl helm kubectx \
rclone restic \
pipewire-jack \
mpv inskape gimp darktable spotify playerctl

Conclusion

Et voilà, mon archlinux est installé, et configuré, il reste un peu de personnalisation (thème gtk, pack d’icone etc …), mais globalement, c’est totalement fonctionnel et il ne me manque pas grand chose.
J’espère être sortie des sentiers battus de chacun, avec une installation un peu spécifique.