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/nvme1n1p2 (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.

In practice, you’ll have to wait for the devices to synchronise, and this is very slow because mdadm is configured to synchronise devices at a maximum rate of 200ko/s. This can be permanently unlocked via sysctl :

$ sudo nano /etc/sysctl.d/99_unlock_mdadm_sync_speed.conf = 5000000 = 5000000000
$ sudo sysctl -p /etc/sysctl.d/99_unlock_mdadm_sync_speed.conf

With modern NVME hardware this will seriously speed up re-sync operations at the expense of high loads.

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

1.5. Install Grub

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.6. 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.7. 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.

1.8. Update 2022-06 : if mdadm does not mount the arrays RAID

After an update the machine refused to boot. init was announcing an unexpected failure and dropping me in an emergency shell ash. This problem is usually linked to the fact that the init process can’t mount the designated main storage partition.

I my case, an update of mdadm introduced a new behavior regarding drives and partitions naming by the tool, resulting in mdadm being unable to auto-detect RAID arrays during early boot.

I could mdadm --assemble … my arrays but couldn’t resume booting as ./init (even if running fine) could not get me out of the emergency shell (if you know why, please tell me).

After some readings in Artix forums I learnt that such problems are not exceptional and that the official way of dealing with it is to boot from a live Artix ISO, chroot from the live ISO to your machine storage via the artix-chroot command, and run commands from the Install grub section again to update the initramfs (and if your partitions did change their naming or you change your drive and got another UUID you might have to update GRUB configuration files also).

Note for self : if a RAID disk dies, I probably should regenerate the initramfs after repairing the array. I think that Debian manage to regenerate its initramfs when its needed.

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/nvme1n1p2 (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.

En pratique il faudra attendre que les supports de stockage se synchronisent et c’est long parce que mdadm est configuré pour synchroniser les périphériques à une vitesse maximum de 200ko/s. Cette limitation peut être relevée via sysctl :

$ sudo nano /etc/sysctl.d/99_unlock_mdadm_sync_speed.conf = 5000000 = 5000000000
Ctrl+X (1)
Y (2)
$ sudo sysctl -p /etc/sysctl.d/99_unlock_mdadm_sync_speed.conf

Avec un NVME moderne il y a des chances d’atteindre les ±5GO/s au prix d’une charge machine importante pendant l’opération.

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

2.5. Installer Grub

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.6. 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.7. 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.

2.8. Mise à jour 2022-06 : si mdadm ne monte plus les tableaux RAID

Après une mise à jour, la machine a refusé de démarrer. Le processus init annonçait une erreur inattendue et me laissant une invite de commande d’urgence pour inspecter la situation ash. Ce problème est généralement lié au fait qu’init n’arrive pas à monter la partition désignée pour la racine du système à démarrer.

Dans mon cas, une mise à jour de mdadm avait introduit un changement dans le nommage des disques et partitions par la commande, rendant mdadm incapable d’auto-détecter les tableaux RAID pendant cette phase préliminaire du démarrage.

Je pouvais monter mes tableaux via mdadm --assemble … mais pas terminer le bout en relançant ./init. Ce dernier s’exécutait désormais sans erreur mais ne m’extrayait pas de l’environnement de récupération sur panne. Si vous savez pourquoi, n’hésitez pas à me l’apprendre.

Après quelques lectures sur le forum et le wiki d’Artix, j’ai appris que ce genre de pannes n’était pas tout à fait exceptionnelles et que la méthode officielle pour régler le problème est de démarrer la machine via une ISO récente d’Artix en live sur une clé USB puis de déplacer son environnement d’exécution vers le disque de la machine via la commande artix-chroot et d’exécuter à nouveau les commandes de la section Installation Grub pour mettre à jour l’initramfs (et si vos partitions ont vraiment changé de nom ou que vous avez changé de support de stockage et obtenu un nouvel UUID, vous pouvez aussi avoir à retoucher à la configuration de GRUB).

Note pour plus tard : si un disque RAID devait être changé, il serait probablement nécessaire de regénérer l’initramfs après la réparation du tableau. Il me semble que Debian se débrouille pour regénèrer son initramfs tout seul quand il y a besoin…

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.