Un NAS presque parfait

Le dans «Infonuagique» par Eldeberen
Mots-clés:

Comment, à partir d'une carte Odroid, installer et configurer un NAS aux petits oignons ? Avec du RAID, du chiffrement LUKS, et une touche de DIY.

L'Odroid sur son étagère

NB : Ce "tuto" est avant tout destiné à mon propre usage pour le jour où je souhaiterais réinstaller la machine. Muni de cette information, faites-en ce que vous voulez.


Ce billet est le deuxième de sa série. Vous pouvez retrouver les autres ici :

  1. Un datacenter à la maison
  2. Un NAS presque parfait (cet article)
  3. Du monitoring avec Prometheus
  4. Backup to the sky (à paraître)

Matériel

Rien de nouveau, j'utilise ce que j'ai présenté dans le précédent article, à savoir ceci :

  • 1× Odroid H2+ (Intel J4115 x86_64)
  • 1× 4 Go de LPDDR4
  • 1× 500 Go de SSD nvme
  • 2× 2 To de HDD
  • de quoi alimenter et brancher tout ce bazar

Architecture cible

Partitionnement

En ce qui concerne la table de partition, j'ai décidé d'utiliser celle ci-dessous. C'est pas forcément le plus optimal ni le plus standard, mais au moins je m'y retrouve.

Table de partitionnement

Je planifie de tout chiffrer avec LUKS, à l'exception de /boot/efi. Mon modèle de menace étant un cambriolage, cela suffit amplement. Le SSD sera déchiffré par l'initramfs, tandis que le HDD sera déchiffré de manière chainée avec crypttab.

Système d'exploitation

Pour l'OS, je pars sur une Archlinux1. C'est un système que je maitrise à peu près, et surtout dont les dépôts officiels sont plus que complets. Ne pas avoir à faire ses propres paquets à la main, ni suivre les mises à jour de chaque soft de son coté, et j'en passe, est un confort que je ne suis pas prêt de lacher. Peut-être que je ferais un test avec du Gentoo/Alpine, mais ce sera sur les systèmes satellites. Pour le moment je reste dans un sentier battu.

NB : je vois venir les trolls comme quoi Archlinux n'est pas stable, que c'est pas fait pour de la prod, que chaque mise à jour casse tout, etc. Mon avis est que d'une part ces allégations sont de moins en moins valides, et que d'autre part quelle que soit la distro un entretien régulier est la clé de la durabilité. Ceci étant dit, mon datacenter à la maison comprends 3~4 machines, portant au total à une grosse demi-douzaine le nombre d'installations que j'ai à maintenir. Je peux me permettre d'y passer un peu plus de temps qu'un hébergeur ayant un à trois ordres de grandeurs plus de machines.


Installation depuis le LiveUSB

On rentre dans les choses sérieuses. Je considère que ces prérequis sont remplis :

  • avoir un accès à internet sur la machine cible ;
  • posséder un LiveUSB pas trop vieux d'Archlinux ;
  • copier ses clés SSH dans un fichier authorized_keys sur une clé USB.

Si c'est ok, on peut commencer.

Initialisation

On commence par charger un layout qui nous convient, ici de l'azerty. Idem, on synchronise le temps en NTP pour pas planter les vérifications TLS lorsqu'on va interroger les dépôts avec pacman.

loadkeys fr
timedatectl set-ntp true

Partitionnement physique

On se réfère à la table de partitions, et on attaque par le SSD.

fdisk /dev/nvmeOn1
> g  # Nouvelle table GPT
> n  # Nouvelle partition pour /boot/efi
> +1G  # Taille
> t  # Type : EFI
> n  # Nouvelle partition pour cryptssd
> w  # Écriture

On continue avec les HDD, à répéter deux fois : une pour /dev/sda, l'autre pour /dev/sdb. Il est recommandé de laisser un peu de place à la fin de la partition, car en cas de changement du disque il se peut que le nouveau n'ait pas exactement la même taille que l'ancien. Laisser 100 Mo à la fin permet de garder un peu de marge et d'ajuster en cas de besoin. Ici mes deux disques ont bien la même taille, donc pas d'ajustement à prévoir.

fdisk /dev/sda
> g  # Nouvelle table GPT
> n  # Nouvelle partition pour /dev/md/hdd
> -100M  # Taille
> t  # Type RAID
> w  # Écriture

RAID

Pour créer la grappe RAID, rien de plus facile :

mdadm --create --verbose --level=1 --metadata=1.2 --raid-devices=2 /dev/md/hdd /dev/sda1 /dev/sdb1

On configurera celle-ci un peu plus tard.

Chiffrement

Rien de bien foufou, c'est du LUKS tout ce qu'il y a de plus classique.

cryptsetup luksFormat /dev/nvme0n1p2
cryptsetup open /dev/nvme0n1p2 cryptssd

Partitionnment logique

Par dessus LUKS, on colle du LVM. Idem, se référer à la table de partition pour la taille de celles-ci.

pvcreate /dev/mapper/cryptssd
vgcreate ssd /dev/mapper/cryptssd
lvcreate -L 32G ssd -n root
lvcreate -L 32G ssd -n home
lvcreate -L 32G ssd -n log
l -lvcreate 100%FREE ssd -n lib

Système de fichier

Par soucis de compatibilité, je mets du FAT32 pour /boot/efi. Le reste est du Btrfs, parce que je préfère à zfs. Les goûts, les couleurs…

mkfs.vfat -F32 /dev/nvme0n1p1
mkfs.btrfs /dev/ssd/root
mkfs.btrfs /dev/ssd/home
mkfs.btrfs /dev/ssd/log
mkfs.btrfs /dev/ssd/lib

Points de montage

Les disques sont prêts, on passe au montage dans /mnt.

mount /dev/ssd/root /mnt
mkdir -p /mnt/boot/efi
mkdir /mnt/home
mkdir -p /mnt/var/{log,lib,storage,backup}
mount /dev/nvme0n1p1 /mnt/boot/efi
mount /dev/ssd/home /mnt/home
mount /dev/ssd/var/log /mnt/var/log
mount /dev/ssd/var/lib /mnt/var/lib

Paquets de base

Voici la liste des paquets que j'installe de base :

  • base linux linux-firmware
  • vim pour l'éditeur de texte
  • fish ou zsh pour un shell sympa, tmux pour le multiplexage
  • mdadm lvm2 btrfs-progs pour les systèmes de fichier
  • man-db man-pages texinfo pour les pages de man
pacstrap /mnt base linux linux-firmware vim fish tmux mdadm lvm2 btrfs-progs man-db man-pages texinfo

fstab

On peut alors générer le fstab :

genfstab -U /mnt >> /mnt/etc/fstab

Chroot

Si tout s'est bien passé jusque là, on peut chrooter dans le nouveau système. La suite des commandes se fera depuis ce dernier.

arch-chroot /mnt

Installation dans le système cible

Système de base

Changement du mot de passe root, réglage de la date, de la locale, du layout par défaut.

passwd
ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime
hwclock --systohc
vim /etc/locale-gen  # Décommenter fr_FR.UTF-8
locale-gen
echo "LANG=fr_FR.UTF-8" > /etc/locale.conf
echo "KEYMAP=fr-latin1" > /etc/vconsole.conf

Chiffrement et configuration de la grappe RAID

On va maintenant configurer la grappe RAID : chiffrement de la partition de base, partitionnement, formattage du système de fichier, ajout de la la config crypttab, ajout des points de montage.

cryptsetup luksFormat /dev/md/hdd
cryptsetup open /dev/md/hdd crypthdd
pvcreate /dev/mapper/crypthdd
vgcreate hdd /dev/mapper/crypthdd
lvcreate -L 1T hdd -n backup
lvcreate -l 100%FREE hdd -n storage
mkfs.btrfs /dev/hdd/backup
mkfs.btrfs /dev/hdd/storage

On ajoute ensuite la configuration qui va bien dans /etc/crypttab. On n'oublie pas de créer le fichier de mot de passe et de lui donner des droits restrictifs. Attention, il ne faut pas mettre de nouvelle ligne à la fin du fichier de mot de passe, pensez à activez l'option noeol dans vim.

ll /dev/md/hdd
lrwxrwxrwx 1 root root 8 Apr 11 17:15 /dev/md/hdd -> ../md127

ll /dev/disk/by-uuid
[...]
lrwxrwxrwx 1 root root 11 Apr 11 17:15 5cadb6c4-0937-4d3a-bf51-8cfa9bf5eb71 -> ../../md127
[...]

echo "hdd            UUID=5cadb6c4-0937-4d3a-bf51-8cfa9bf5eb71   /etc/cryptsetup-keys.d/hdd.key   luks" >> /etc/crypttab

mkdir /etc/cryptsetup-keys.d
chmod 700 /etc/cryptsetup-keys.d
vim /etc/cryptsetup-keys.d/hdd.key
> MaSuperPassphrase
chmod 400 /etc/cryptsetup-keys.d/hdd.key

Puis on fini par la configuration des points de montage.

mkdir /var/{backup,storage}

ll /dev/hdd
lrwxrwxrwx 1 root root 7 Apr 11 17:15 backup -> ../dm-6
lrwxrwxrwx 1 root root 7 Apr 11 17:15 storage -> ../dm-7

ll /dev/disk/by-uuid
[...]
lrwxrwxrwx 1 root root 10 Apr 11 17:15 e331f904-9aa7-46aa-9963-d35b7a1c4b13 -> ../../dm-6
lrwxrwxrwx 1 root root 10 Apr 11 17:15 6c43e2b1-6585-42df-9dae-1a2a0e6a6f9c -> ../../dm-7
[...]

cat << EOF >> /etc/fstab
# /dev/mapper/hdd-backup
UUID=e331f904-9aa7-46aa-9963-d35b7a1c4b13       /var/backup     btrfs           rw,relatime,space_cache,subvolid=5,subvol=/ 0 0

# /dev/mapper/hdd-storage
UUID=6c43e2b1-6585-42df-9dae-1a2a0e6a6f9c       /var/storage    btrfs           rw,relatime,space_cache,subvolid=5,subvol=/ 0 0
EOF

On en profite pour générer la config mdadm qui va bien.

mdadm --detail --scan >> /etc/mdadm.conf

Initramfs

Maintenant que tout est ok, on peut créer l'initramfs. Pour résumé, c'est le système qui se situe au milieu de la chaine bootloader → initramfs → OS. Lord a fait un très bon article sur le sujet2. Dans notre cas, il embarque les outils qui vont bien pour gérer :

  • le déchiffrement des disques
  • le montage de la grappe RAID
  • la gestion du réseau
  • la création d'un serveur SSH pour déchiffrer à distance

On commence donc par installer les paquets nécessaires :

pacman -S mkinitcpio-netconf mkinitcpio-tinyssh mkinitcpio-utils

Puis on récupère le fichier de clés SSH qui seront autorisées à se connecter au NAS lors de la phase de boot, que l'on pose dans /etc/tinyssh/root_key

mkdir /tmp/usb
mount /dev/sdd1 /tmp/usb
cp /tmp/usb/authorized_keys /etc/tinyssh/root_key

Étant donné qu'on va travailler sur de l'UEFI, on aura besoin de copier les fichiers générés par mkinitcpio dans un dossier à la con. Pour cela, on va créer un crochet personnalisé3.

On modifie le mkinitcpio.conf pour ajouter les modules qui vont bien et réorganiser les crochets dans le bon sens :

  1. base : met en place la structure des répertoires et copie les utilitaires
  2. udev : détecte et charge les modules nécessaires pour entre autre créer et utiliser la partition racine
  3. autodetect : allége l'image en enlevant les modules dont le matériel n'est pas détecté
  4. keyboard : ajoute le support du clavier USB
  5. keymap : modifie le layout du clavier
  6. modprobe : ajoute les dossiers /etc/modprobe.d et /usr/lib/modprobe.d
  7. block : ajoute le support des périphériques de bloc
  8. mdadm_udev : ajoute le support de gestion du RAID
  9. netconf : gère la partie réseau
  10. tinyssh : créé le serveur SSH
  11. encryptssh : déchiffre la partition root via SSH ou le clavier (remplace encrypt)
  12. lvm2 : monte les partitions LVM
  13. filesystems : détecte le module correspondant à votre système de fichier et le passe à kinit
  14. efistub-update : hook pour copier le kernel et l'initramfs de /boot à /boot/efi/EFI

Et on termine en générant l'initramfs :

vim /etc/mkinitcpio.conf
> MODULES=(dm-raid raid1)
> HOOKS=(base udev autodetect keyboard keymap modconf block mdadm_udev netconf tinyssh encryptssh lvm2 filesystems efistub-update)
mkinitcpio -P

Bootloader

Pour le coup, j'ai laché Grub. Trop de problèmes dûs à une génération foireuse du grub.cfg font que je suis passé, sur les conseils de #fediverse sur Geeknode, à Syslinux4. Spoiler : ça marche au top, c'est KISS5, je vais sûrement basculer mes différents PC sur ce bootloader.

On installe les paquets qui vont bien, on copie les fichiers d'init au bon endroit, un poil de config et on termine en ajoutant l'entrée au bootloader. N'oubliez pas de récupérer l'UUID de la partition LUKS qui contient la partition root, ici /dev/nvme0n1p2. Vous pouvez le faire en listant les disques par UUID.

Les paramètres ip des entrées correspondent à la configuration du réseau lors du boot : ip=<client-ip>:<server-ip>:<gateway-ip>:<netmask>:<client-hostname>:<interface>:{dhcp|dhcp6|auto6|on|any|none|off}6.

pacman -S syslinux efibootmgr
mkdir -p /boot/efi/EFI/syslinux
cp -r /usr/lib/syslinux/efi64/* /boot/efi/EFI/syslinux

ll /dev/disk/by-uuid/
[...]
lrwxrwxrwx 1 root root 15 Apr 10 10:24 55289ec0-79bb-4463-8dd5-8519ecbae55d -> ../../nvme0n1p2
[...]

cat << EOF > /boot/efi/EFI/syslinux/syslinux.cfg
PROMPT 1
TIMEOUT 50
DEFAULT arch

LABEL arch
    LINUX ../vmlinuz-linux
    APPEND root=/dev/ssd/root cryptdevice=UUID=55289ec0-79bb-4463-8dd5-8519ecbae55d:cryptssd ip=::::khazad-dum:eth0:dhcp rw
    INITRD ../initramfs-linux.img

LABEL archfallback
    LINUX ../vmlinuz-linux
    APPEND root=/dev/ssd/root cryptdevice=UUID=55289ec0-79bb-4463-8dd5-8519ecbae55d:cryptssd ip=::::khazad-dum:eth0:dhcp rw
    INITRD ../initramfs-linux-fallback.img
EOF

efibootmgr --create --disk /dev/nvme0n1 --part 1 --loader /EFI/syslinux/syslinux.efi --label "Syslinux" --verbose

Réseau

Coté réseau, on sera sur une config assez simple : dhcpcd pour le client DHCP, et systemd-networkd pour le reste. À coté de ça, on modifie le hostname de la machine et on ajoute quelques hosts dans /etc/hosts

pacman -S dhcpcd
systemctl enable dhcpcd
systemctl enable systemd-networkd
echo "khazad-dum" > /etc/hostname

cat << EOF > /etc/hosts
127.0.0.1 localhost khazad-dum
::1 localhost khazad-dum
EOF

SSH

On utilisera le très classique OpenSSH. Pour la config, je détaillerai dans un article dédié auhardening du système. Ici je désactive juste le login du compte root et celui par mot de passe.

pacman -S openssh
vim /etc/ssh/sshd_config
> PermitRootLogin no
> PasswordAuthentication no
systemctl enable sshd

Compte de service

Puisqu'on refuse le login sur root, il faut créer un compte de service qui nous sera utile pour administrer la machine. On installera le classique sudo par commodité, ce qui passe par l'ajout d'un groupe sudo, l'édition de /etc/sudoers pour autoriser les membres du groupe à exécuter des commandes privilégiées, et l'ajout du groupe au nouveau compte. On n'oublie pas de changer le mot de passe et d'ajouter les clés SSH pour ne pas se retrouver dehors au reboot.

pacman -S sudo
vim /etc/sudoers
> %sudo ALL=(ALL) ALL
useradd -m -s /usr/bin/fish eldeberen
groupadd sudo
usermod -aG sudo eldeberen
passwd eldeberen
mkdir /home/eldeberen/.ssh
cp /tmp/usb/authorized_keys /home/eldeberen/.ssh/
chown -R eldeberen:eldeberen /home/eldeberen/.ssh

Reboot

Le système est maintenant configuré, on peut tenter le reboot. Si tout va bien, il est possible lors du boot de déchiffrer le disque soit via le TTY, soit en se connectant au NAS en SSH. N'oubliez pas de lui réserver un bail DHCP pour que son IP soit statique et connue. Dès que la phrase de passe est rentrée, le déchiffrement s'effectue et la machine boot. Il ne reste plus qu'à l'utiliser. ;)

À la prochaine ! o/

Vous pouvez réagir à cet article en m'envoyant un mail, à blog[@]middleearth[.]fr. Je répondrais avec plaisir :)