GNU+Linux command memo

Artix Linux on RAID with full encryption

1. version : en

1.1. The objective

I recently installed an Artix Linux [1] on a computer equipped with two roughly equivalent storage units.

I decided to go for a RAID setup but I still wanted to enjoy the Artix simplicity of storage "full" encryption. Well, it’s not exactly "full" encryption because UEFI boot procedure requires a normal FAT32 partition, but everything else will be encrypted and even this clear partition will be on RAID.

With two drives, you can choose between RAID0 and RAID1 modes. The RAID0 copy half of each files on each disks and can read them at twice the normal speed (to simplify things). It can be interesting for gamers, or video-makers, but it’s not what I was looking for. With the RAID1 mode, all your data are duplicated on both drives, and will survive to a single hardware drive failure (you’ll just hurry to replace the faulty hardware by a new piece, hopping that the other won’t fail at the same time).

And you can mix the two, with RAID10, which ensure data replication and improved reading speeds.

So, after booting from my Artix Linux USB key (so after having disabled the secure boot setting in the BIOS), and while reading this Arch wiki page about RAID, I created two RAID arrays, and partitioned them respectively in FAT32 and Ext4.

1.2. RAID

The 1st array was created in RAID1 and the second in RAID10. I would have prefer to have both in RAID10, and I lost a few hours trying this, before I re-read that UEFI BIOS currently can’t read FAIT32 partitions on RAID10 (and will probably never do). The UEFI BIOS ability to read RAID1 is due to the fact that with `mdadm’s Linux RAID array management, RAID1 is really twice your partition kept sync by software. So while reading a RAID1 the BIOS is not figuring out that there is another drive under the surface, he sees a regular FAT32 partition. But the BIOS will mess things up if it tries to write in the partition, because it would only write on one of the two copies.

To do so, things are done in three steps :

  1. Partition each storage device individually (but symmetrically)

  2. Assemble the partitions in RAID arrays

  3. Format the RAID arrays

$ sudo cgdisk /dev/nvme0n1  (1)
$ sudo cgdisk /dev/nvme1n1  (2)
$ sudo mdadm --create --verbose --level=1 --metadata=1.0 --raid-devices=2 /dev/md/uefi_boot /dev/nvme0n1p1 /dev/nvme1n1p1 (3)
$ sudo mdadm --create --verbose --level=10 --metadata=1.2 --chunk=512 --raid-devices=2 --layout=f2 /dev/md/main_storage /dev/nvme0n1p2 /dev/nvme1n1p1 (4)
1 Create a small \~500MO bootable EFI system partition (type EF00) and all the rest in a regular Linux file system (type 83) partition. Here we need two partitions, but regarding RAID it’s advised not to created full-capacity partitions, as you would need a disk of the same or bigger capacity to replace a faulty unit, while even from the same line of products of a manufacturer and even from the same model, capacities may vary from one unit to an other. Intentionally creating smaller partitions (like 100MO less than nominal storage capacity) may help to find spare units.
2 idem
3 Note the --metadata=1.0 this version of metadata is stored at the end of the partitions and so it won’t get in the way of the BIOS naïvely trying to read a FAT32 boot partition.
4 More modern options

Once here, you can check that everything works well with :

$ cat /proc/mdstat
Personalities : [raid1] [raid10]
md126 : active (auto-read-only) raid1 nvme1n1p1[1] nvme0n1p1[0]
      409536 blocks super 1.0 [2/2] [UU]

md127 : active raid10 nvme1n1p2[1] nvme0n1p2[0]
      976219136 blocks super 1.2 512K chunks 2 far-copies [2/2] [UU]
      bitmap: 6/8 pages [24KB], 65536KB chunk

unused devices: <none>

For more explanation I encourage you to read the Arch RAID wiki page.

Then we format the partitions :

sudo mkfs.fat -n 'boot' /dev/md126
sudo mkfs.ext4 -v -L 'main_storage_filesystem' -b 4096 -E stride=128,stripe-width=256 /dev/md127

1.3. Full LUKS encryption

Then I launched the Artix Linux install application (called calamares [2] ) clicking on the desktop icon of the USB live Artix system. I followed the steps and chose the manual option at the partitioning step. The install wizard showed the RAID partitions and you can configure them to be used for the installation, setting the mount points (respectively to /boot/efi and /).

The installation runs for a few minutes (its really fast to install an Artix Linux, that’s one of the reason why we chose to install it at, and it spares you a lot of instructions from this Artix Linux full encryption wiki page (that you still can read it to understand how it works).

1.4. The grub-install problem on RAID

But I would not have wrote this blog post if things would have run too smoothly. At the end of the installation procedure calamares detects a problem and tells that the installation failed. It’s a bit exaggerated, the installation mostly succeeded, but it misses a last step : the installation of GRUB (the boot manager, a piece of software that runs between the BIOS and your init process). So at this point you have a running system that can’t boot itself…

The error messages is :

Installation for x86_64-efi platform.
efibootmgr: option requires an argument -- 'd' (1)
efibootmgr version 17
1 For the record, the -d option of efibootmgr is : -d|--disk containing loader

The official way of installing GRUB (and what calamares tries) is :

sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Artix --force

It’s this command (in version GRUB 2.06) that tries to run efibootmgr (in version 17) to create UEFI boot entries in the BIOS itself (it stills looks like a bad idea even after some more year). With RAID arrays it fails because the BIOS must be instructed for a real hardware to explore in its quest for bootable EFI files in FAT32 partitions (Linux Torvalds called the UEFI system an Intel brain damage).

The workaround I found was to tell grub-install not to perform this efibootmgr part on one side, and to create entries myself from the BIOS on the other side.

In fact I first ensured that GRUB was configured for both RAID and LUKS encryption via cryptsetup support.

So in /etc/default/grub I checked that those lines (respectively for encryption and for RAID support) was present :

GRUB_CMDLINE_LINUX_DEFAULT="quiet cryptdevice=UUID=XXXX-YYYY-…:luks-XXXX-YYYY-… root=/dev/mapper/luks-XXXX-YYYY-…" (1)
1 The XXXX-YYYY-… tokens should be real UUIDs (lsblk can tell them to you)
2 This line is at the end of my file
GRUB_PRELOAD_MODULES='part_gpt part_msdos mdraid09 mdraid1x' (1)
1 This line was missing mdraid09 mdraid1x

Then you can install GRUB with this series of commands :

sudo grub-mkconfig -o /boot/grub/grub.cfg (1)
sudo mkinitcpio -p linux (2)
sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --no-nvram --bootloader-id=Artix --force (3)
1 This regenerates the GRUB boot-time configuration file
2 This regenerates the initramfs (command in version 30)
3 This actually installs the GRUB in it’s /boot/efi/EFI/Artix folder and partition. Mind the --no-nvram command line argument, it’s the trick to avoid grub-install to fail on efibootmgr.

Don’t forget to create UEFI entries from your BIOS pointing on your /boot/efi/EFI/Artix/grubx64.efi. I made one for each drive. The BIOS should not write on the disk. If you have options to write of the disk (like a folder creation or renaming) avoid them at all costs, it would mess with your RAID array.

1.5. GRUB on RAID : Diskfilter writes are not supported

At this point your system should boot, but GRUB will complain each time about unsupported diskfilter writes : diskfilter writes are not supported. The boot stops and asks you to press any key to continue.

|   |   |   |   |   |   |   |   |   |   |   |   |   | <-    |
| ->| |   |   |   |   |   |   |   |   |   |   |   |   |     |
|-----',--',--',--',----------',--',--',--',--',--',--'|    |
|      |   |   |   |    ANY    |   |   |   |   |   |   |    |
|    |   |   |   |   |   |   |   |   |   |   |   |          |
|      |  |     |                          |      |  |      |
'------'  '-----'--------------------------'------'  '------'

It’s possible to workaround this and boot without questions. As explain here, it consists in commenting-out every occurrence of save_env lines in /boot/grub/grub.cfg (and do it after each grub-mkconfig run).

sudo vim +"%s/save_env/# save_env/" +wq /boot/grub/grub.cfg  (1) (2)
1 Sure, the traditional Unix way of doing this would be with sed
2 If you omit the +wq you’ll end up in an open vim that lets you check if the result is what you expect before saving it.

1.6. A last trap : a missing .img in /boot

If you installed both amd-ucode and intel-ucode packages [3] before regenerating the initramfs of your system (a scenario which should not happen), and then decided to remove one of the two packages, you’ll have to regenerate the initramfs to avoid a boot failure due to a "missing" ucode file.

Surprisingly enough, de-installing one of this packages in Artix (Arch based GNU+Linux distribution) is not triggering an initramfs regeneration.

That’s how what I thought would be an easy install, turned out consuming probably more time than I can expect to save in case of disk failure ! (and let’s forget about the time spent writing this).

2. version : fr

2.1. L’objectif

J’ai récemment installé une Artix Linux sur un ordinateur équipé de deux unités de stockage de capacités équivalentes.

J’ai opté pour une installation en RAID mais je voulais également pouvoir profiter du chiffrement intégral du support en option lors de l’installation d’Artix. Bon, pour commencer ce n’est pas exactement un chiffrement intégral car les BIOS UEFI imposent la présence d’une partition FAT32 non chiffrée quelque part, mais tout le reste est chiffré et même cette partition peut être stockée sur un RAID.

Quand on dispose de deux unités de stockage, on a le choix entre du RAID0 et du RAID1. Le RAID0 c’est grosso-modo un mode de fonctionnement où chaque fichier est coupé en deux, avec une moitié écrite sur chacun des supports de données, ce qui permet ensuite de les lire 2x plus vite. Ça peut être intéressant pour les joueurs ou les monteurs vidéos par exemple, mais ce n’est pas ce que je cherchais. Le RAID1 en revanche écrit la même chose sur les deux stockages, en même temps, de sorte que si un des deux tombe en panne, vous n’avez pas perdu vos données (vous allez juste être subitement très pressé de remplacer le stockage déficient en croisant les doigts pour que le 2e tienne le coup entre temps).

Enfin il est possible d’agréger les qualités des deux modes de fonctionnement avec le RAID10, qui assure à la fois la redondance du stockage et la vitesse de lecture.

J’ai donc commencé par créer des tableaux RAID après avoir démarré sur ma clé USB d’installation d’Artix Linux (et donc avoir désactivé l’option Secure Boot du BIOS). J’ai attentivement lu la page du wiki Arch Linux concernant le RAID et je me suis lancé dans le partitionnement, le formatage et l’assemblage en tableaux RAID de mes supports.

2.2. RAID

Le premier tableau RAID fut créé en RAID1 et le second en RAID10. J’aurais préféré avoir les deux en RAID10 et ai perdu pas mal de temps à essayer comme ça avant de réaliser que les BIOS UEFI ne peuvent pas lire leur partition FAT32 sur du RAID10 (et ne le pourront probablement jamais). La capacité d’un BIOS UEFI à lire une partition RAID1 vient du fait qu’avec la gestion des tableaux RAID sous Linux par mdadm on a vraiment une duplication de partitions maintenues à jour logiciellement. Du coup le BIOS arrive à lire la partition sans se rendre compte qu’elle fait partie d’un ensemble plus grand et il endommagerait le tableau RAID1 s’il devait écrire dans la partition, car il n’écrirait que sur l’un des deux stockages.

Pour créer ces stockages j’ai agis en 3 étapes :

  1. Partitionnement des stockages, chacun leur tour mais de manière symétrique

  2. Assemblage des partitions en tableaux RAID

  3. Formatage des tableaux

sudo cgdisk /dev/nvme0n1  (1)
sudo cgdisk /dev/nvme1n1  (2)
sudo mdadm --create --verbose --level=1 --metadata=1.0 --raid-devices=2 /dev/md/uefi_boot /dev/nvme0n1p1 /dev/nvme1n1p1 (3)
sudo mdadm --create --verbose --level=10 --metadata=1.2 --chunk=512 --raid-devices=2 --layout=f2 /dev/md/main_storage /dev/nvme0n1p2 /dev/nvme1n1p1 (4)
1 J’ai donc d’abord créé une petite partition bootable (±500MO de type EFI — EF00) puis une seconde couvrant tout le reste en système de fichier Linux (type 83). Ici nous avons besoin de deux partitions (pour avoir le /boot séparé), mais même en ne considérant que le stockage en tableau RAID, il est tout de même conseillé de ne pas créer une partition de la taille maximale du support car il faut ensuite un disque de même capacité (ou plus grand) pour remplacer une unité défectueuse. Or, même entre deux productions de même référence chez un constructeur donné, il peut y avoir de petites différences de capacité effective entre les supports. Il est donc conseillé de créer ses partitions de stockage en utilisant volontairement moins de place que la capacité nominale du support (par exemple avec 100MO en moins), pour se donner plus de chances de retrouver un disque compatible avec le tableau le moment venu.
2 idem
3 Notez le --metadata=1.0 cette version des méta-données du tableau RAID est écrite à la fin des partitions et n’interfère pas avec la lecture naïve de la partition par le BIOS.
4 Ici il y a des options plus modernes

Une fois arrivé là, vous pouvez vérifier que tout fonctionne bien avec :

$ cat /proc/mdstat
Personalities : [raid1] [raid10]
md126 : active (auto-read-only) raid1 nvme1n1p1[1] nvme0n1p1[0]
      409536 blocks super 1.0 [2/2] [UU]

md127 : active raid10 nvme1n1p2[1] nvme0n1p2[0]
      976219136 blocks super 1.2 512K chunks 2 far-copies [2/2] [UU]
      bitmap: 6/8 pages [24KB], 65536KB chunk

unused devices: <none>

Pour plus d’explications, je vous encourage à nouveau à lire la page de wiki d’Arch Linux sur le RAID.

Enfin, il faut formater les partitions :

sudo mkfs.fat -n 'boot' /dev/md126
sudo mkfs.ext4 -v -L 'main_storage_filesystem' -b 4096 -E stride=128,stripe-width=256 /dev/md127

2.3. Chiffrement intégral

J’ai ensuite lancé l’installation d’Artix Linux en cliquant sur l’icône du bureau. Une application (nommée calamares) se lance et pose quelques questions puis se charge de l’installation. Arrivé à l’étape du choix des partitions, au lieu de tout laisser en mode automatique j’ai pu préciser que je voulais utiliser les partitions RAID (visibles depuis l’outil) en précisant leurs points de montage (respectivement /boot/efi et /).

L’installation se déroule alors en quelques minutes (elle est vraiment rapide, c’est une des raisons qui nous a encouragé à choisir cette distribution chez, et elle économise plein de commandes et configuration à passer sinon à la main pour avoir un système chiffré, comme on les retrouve détaillées sur cette page de wiki du projet Artix Linux (que vous pouvez quand même aller lire pour comprendre comment ça marche).

2.4. Le problème de grub-install sur RAID

Toutefois, je n’aurais probablement pas pris la peine de rédiger tout ça si les choses s’étaient passées exactement comme prévu. À la fin de la procédure d’installation, calamares détecte un problème et annonce que l’installation a échoué. C’est un peu exagéré car l’installation s’est en fait plutôt bien déroulée, il n’y a que sur la dernière commande qui se prend les pieds dans le tapis et il manque donc GRUB (le gestionnaire de démarrage, un bout de logiciel qui tourne entre le BIOS et votre processus init). Du coup vous avez un système qui tourne mais qui ne peut pas se lancer tout seul…

Le message d’erreur rencontré est :

Installation for x86_64-efi platform.
efibootmgr: option requires an argument -- 'd' (1)
efibootmgr version 17
1 Et pour mémoire, l’option -d de l’efibootmgr correspond à : -d|--disk containing loader

La manière officielle d’installer le GRUB (et donc ce que calamares essaye) est :

sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Artix --force

C’est cette commande qui essaye de lancer efibootmgr pour créer les enregistrements de chemin des fichier UEFI du stockage local dans le BIOS (et ça me semble toujours être une très mauvaise idée même avec quelques années de recul). Quand le stockage local est un tableau RAID, la procédure échoue car le BIOS a besoin d’être instruit d’un chemin précis, sur un disque physique et une partition FAT32 (une façon de faire que Linux Torvalds a décrite comme résultant d’une attaque cérébrale chez son concepteur, Intel).

Pour circonvenir au problème, j’ai trouvé comment indiquer à grub-install d’éviter l’étape efibootmgr d’une part et je me suis résolu à créer les entrées dans le BIOS à la main d’autre part.

En fait j’ai d’abord pris le temps de vérifier que mon GRUB était configuré pour supporter les tableaux RAID et le chiffrement LUKS via cryptsetup.

Dans le fichier /etc/default/grub j’ai vérifié la présence des lignes suivantes :

GRUB_CMDLINE_LINUX_DEFAULT="quiet cryptdevice=UUID=XXXX-YYYY-…:luks-XXXX-YYYY-… root=/dev/mapper/luks-XXXX-YYYY-…" (1)
1 Où les jetons XXXX-YYYY-… doivent être remplacés par l’UUID de votre partition LUKS (lsblk peut vous lister l’UUID en question)
2 Cette ligne est à la fin du fichier chez moi
GRUB_PRELOAD_MODULES='part_gpt part_msdos mdraid09 mdraid1x' (1)
1 Cette ligne était dépourvue des modules mdraid09 mdraid1x

Vous pouvez ensuite enfin installer votre GRUB avec la série de commandes suivantes :

$ sudo grub-mkconfig -o '/boot/grub/grub.cfg' (1)
$ sudo mkinitcpio -p 'linux' (2)
$ sudo grub-install --target='x86_64-efi' --efi-directory='/boot/efi' --no-nvram --bootloader-id='Artix' --force (3)
1 Ceci re-génère le fichier de configuration utilisé par GRUB lors du démarrage
2 Ceci re-génère l’initramfs
3 Et enfin ceci installe vraiment le GRUB dans son dossier /boot/efi/EFI/Artix sur la partition voulue (et montée ! ce qui peut être vérifié via sudo mount | grep /boot). C’est sinon l’argument --no-nvram qui évite que grub-install n’échoue sur efibootmgr.

N’oubliez pas ensuite de créer vos entrées UEFI dans le BIOS. Elles doivent pointer sur le fichier /boot/efi/EFI/Artix/grubx64.efi. J’en ai personnellement créé deux, une pour chaque supportphysique de données. Le BIOS ne devrait pas écrire sur le disque, mais si des options le permettent (comme une création de dossier, ou un renommage) évitez les, vraiment.

2.5. GRUB sur RAID : Diskfilter writes are not supported

Arrivé là, le système devrait démarrer (enfin !), mais le GRUB râle encore à chaque démarrage à propos d’écritures non supportées sur le disque : diskfilter writes are not supported. Le démarrage s’arrête et il vous est demandé d’appuyer sur une touche pour continuer.

Il est possible d’éviter ça et de démarrer d’une traite (une fois le mot de passe de déverrouillage du stockage saisi ; j’ai du mal à écrire "du disque" ici parce qu’une part on parle d’un tableau RAID avec deux supports et d’autre part les supports NVMe — Non-Volatile Memory — n’ont plus aucune pièce mécanique plate et circulaire, c’est plus proche d’une barrette de RAM avec une pile intégrée… sur le principe).

Comme expliqué ici, la solution consiste à commenter les lignes save_env du fichier /boot/grub/grub.cfg (et à recommencer à chaque lancement de grub-mkconfig).

sudo vim +"%s/save_env/# save_env/" +wq /boot/grub/grub.cfg  (1) (2)
1 Certes, la méthode traditionnelle Unix serait plus à base de sed
2 Si vous ne mettez pas le +wq, vous allez vous retrouver dans l’éditeur de texte avec les modifications faîtes et la possibilité de vérifier ce qui se passe avant de sauver le fichier…

2.6. Un dernier piège : le fichier .img manquant dans /boot

Si vous avez installé à la fois les paquets amd-ucode et intel-ucode [4] avant de re-générer l’initaramfs de votre système (un scénario qui ne devrait pas arriver, on est d’accord…), il vous faudra re-générer votre initramfs quand vous déciderez de retirer un des deux paquets pour éviter une incapacité de démarrer à cause d’un fichier ucode manquant.

Aussi surprenant que cela puisse paraître, désinstaller un de ces paquets ne lance pas automatiquement une re-génération de l’initramfs.

Voilà comment ce que j’imaginais comme une installation simple a finalement consommé probablement plus de temps que ce que j’espère en sauver en cas de défaillance matérielle d’un des supports de stockage ! (et je ne compte pas le temps passé à rédiger ce billet)

1. artix-xfce-openrc-20210726-x86_64.iso
2. v3.2.39.3
3. Packages that allow to update your CPU firmware in early boot stage, at each boot, to avoid shameful security breaches delivered by manufacturers for instance
4. Paquets qui permettent de mettre à jour le firmware de votre CPU, très tôt à chaque démarrage, pour éviter d’honteuses failles de sécurité livrées par les constructeur par exemple.