L'écriture de ce guide est motivé par les mêmes raisons que celui-ci : Installation d'Alpine Linux chiffré sur un serveur distant.
Une méthode est présentée sur le wiki officiel, mais celle-ci utilise dracut-crypt-ssh, qui dépend de Dropbear et qui ne sait pas gérer ed25519 contrairement à TinySSH.
Je fabriquerais à la fin mon initramfs et j'y intégrerais tinysshd afin de déchiffrer par le réseau ma partition '/' au démarrage.
Je prendrais ici pour exemple le cas d'un serveur dédié Kimsufi mais la manipulation devrait être globalement la même partout à partir du moment où le fournisseur permet de démarrer sur un linux rescue.
Vous pouvez aussi dans un premier temps, tester la manipulation chez vous dans une VM et utiliser SystemRescueCd (choisir rescue64 au boot) afin de tester cette procédure.
- Pré-requis
- Création de la configuration réseau
- Partitionnement
- Chiffrement et formatage
- Installation
- Ajout du module dracut intégrant TinySSH
- Redémarrage
- Conclusion
- Références et remerciements
1. Pré-requis
- Avoir la possibilité de booter sur un linux rescue.
2. Création de la configuration réseau
Connectez-vous en SSH sur votre serveur démarré en mode rescue, puis récupérez les informations utiles :
root@rescue:~# udevadm test-builtin net_id /sys/class/net/eth0 2> /dev/null
[...]
ID_NET_NAME_PATH=enp1s0
root@rescue:~# ip a
[...]
6: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether f6:c5:fb:7e:d9:8f brd ff:ff:ff:ff:ff:ff
inet 5.XXX.XXX.85/24 brd 5.XXX.XXX.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 2001:XXX:X:XX55::1/128 scope global
valid_lft forever preferred_lft forever
inet6 fe80::222:4dff:fea1:a419/64 scope link
valid_lft forever preferred_lft forever
[...]
root@rescue:~# ip r
default via 5.XXX.XXX.254 dev eth0
5.XXX.XXX.0/24 dev eth0 proto kernel scope link src 5.XXX.XXX.85
root@rescue:~# ip -6 r
2001:XXX:X:XX55::1 dev eth0 proto kernel metric 256
2001:XXX:X:XXff:ff:ff:ff:ff dev eth0 metric 1024
fe80::/64 dev eth0 proto kernel metric 256
default via 2001:XXX:X:XXff:ff:ff:ff:ff dev eth0 metric 1
root@rescue:~# cat /etc/resolv.conf
search ovh.net
nameserver 213.186.33.99
De là, on va pouvoir définir les lignes de commandes suivantes qui nous serviront par la suite :
ip link set dev enp1s0 up
ip addr add 5.XXX.XXX.85/24 brd + dev enp1s0
ip route add default via 5.XXX.XXX.254
ip -6 addr add 2001:XXX:X:XX55::1/128 dev enp1s0
ip -6 route add 2001:XXX:X:XXff:ff:ff:ff:ff dev enp1s0
ip -6 route add default via 2001:XXX:X:XXff:ff:ff:ff:ff
Mon serveur étant hébergé chez OVH, le serveur DNS 213.186.33.99 leur appartient et je peux donc l'utiliser.
3. Partitionnement
Notez l'utilisation de GPT et prenez l'habitude à ne plus utiliser MBR. J'utilise parted
, mais vous pouvez utiliser cfdisk
si vous préférez :
[user@local ~]$ ssh-keygen -R ip
[user@local ~]$ ssh root@ip
[root@serveur ~]# sgdisk -Z /dev/sda
[root@serveur ~]# parted /dev/sda
(parted) mklabel gpt
(parted) mkpart primary 2048s 4095s
(parted) mkpart primary ext2 4096s 200MB
(parted) mkpart primary xfs 200MB -500MB
(parted) mkpart primary linux-swap -500MB 100%
(parted) set 1 bios_grub on
Vous pouvez adapter votre partitionnement comme bon vous semble, mais vous devrez adapter la suite.
Voici mon partitionnement :
[root@serveur ~]# parted /dev/sda print
Model: ATA HGST HUS726020AL (scsi)
Disk /dev/sda: 2000GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Flags
1 1049kB 2097kB 1049kB bios_grub
2 2097kB 200MB 198MB ext2
3 200MB 2000GB 2000GB xfs
4 2000GB 2000GB 500MB linux-swap(v1)
Ce qui me donnera approximativement :
/boot : 200MB (ext2)
/ : 2TB (xfs chiffré)
swap : 500MB (swap)
4. Chiffrement et formatage
Il va falloir utiliser une méthode efficace et performante et afin de déterminer ça, nous utiliserons la commande suivante :
[root@serveur ~]# cryptsetup benchmark
# Tests are approximate using memory only (no storage IO).
PBKDF2-sha1 218453 iterations per second for 256-bit key
PBKDF2-sha256 301661 iterations per second for 256-bit key
PBKDF2-sha512 168907 iterations per second for 256-bit key
PBKDF2-ripemd160 208050 iterations per second for 256-bit key
PBKDF2-whirlpool 87148 iterations per second for 256-bit key
argon2i 4 iterations, 170831 memory, 4 parallel threads (CPUs) for 256-bit key (requested 2000 ms time)
argon2id 4 iterations, 171825 memory, 4 parallel threads (CPUs) for 256-bit key (requested 2000 ms time)
# Algorithm | Key | Encryption | Decryption
aes-cbc 128b 40.2 MiB/s 42.6 MiB/s
serpent-cbc 128b 32.3 MiB/s 72.9 MiB/s
twofish-cbc 128b 33.8 MiB/s 35.0 MiB/s
aes-cbc 256b 31.1 MiB/s 32.0 MiB/s
serpent-cbc 256b 32.3 MiB/s 73.0 MiB/s
twofish-cbc 256b 33.8 MiB/s 35.0 MiB/s
aes-xts 256b 41.7 MiB/s 42.2 MiB/s
serpent-xts 256b 68.1 MiB/s 68.5 MiB/s
twofish-xts 256b 34.1 MiB/s 34.8 MiB/s
aes-xts 512b 31.4 MiB/s 31.8 MiB/s
serpent-xts 512b 68.0 MiB/s 68.4 MiB/s
twofish-xts 512b 34.1 MiB/s 34.8 MiB/s
Vous ne rêvez pas, les performances sont désastreuses étant donné que mon microprocesseur est un Atom N2800 et qu'il ne possède pas le jeu d'instruction AES-NI.
Chiffrement de la partition /dev/sda3 :
[root@serveur ~]# cryptsetup -v -c serpent-xts-plain64 -s 256 --hash sha256 luksFormat /dev/sda3
[root@serveur ~]# cryptsetup luksOpen /dev/sda3 root
Si votre microprocesseur possède le jeu d'instruction AES-NI, il faudra généralement utiliser aes-xts et une clé 256 bit afin d'avoir d'excellentes performances :
[root@serveur ~]# cryptsetup -v -c aes-xts-plain64 -s 256 --hash sha256 luksFormat /dev/sda3
[root@serveur ~]# cryptsetup luksOpen /dev/sda3 root
On peut formater :
[root@serveur ~]# mkfs.ext2 -m0 /dev/sda2
[root@serveur ~]# mkfs.xfs -n ftype=1 /dev/mapper/root
[root@serveur ~]# mkswap /dev/sda4
Vous pouvez utiliser LVM, choisir EXT4, faire du thin provisioning, mais vous devrez adapter la suite.
5. Installation
On monte les partitions puis on rentre dans le chroot :
[root@serveur ~]# mkdir /mnt/void
[root@serveur ~]# mount -t xfs /dev/mapper/root /mnt/void
[root@serveur ~]# mkdir /mnt/void/boot
[root@serveur ~]# mount -t ext2 /dev/sda2 /mnt/void/boot
[root@serveur ~]# cd /mnt/void/
[root@serveur void]# curl -O https://alpha.de.repo.voidlinux.org/live/current/void-x86_64-ROOTFS-20181111.tar.xz
[root@serveur void]# tar xpf void-x86_64-ROOTFS-20181111.tar.xz --xattrs-include='*.*' --numeric-owner
[root@serveur void]# rm -f void-x86_64-ROOTFS-20181111.tar.xz
[root@serveur void]# echo 'nameserver 213.186.33.99' > etc/resolv.conf
[root@serveur void]# mount --types proc /proc proc
[root@serveur void]# mount --rbind /sys sys
[root@serveur void]# mount --rbind /dev dev
[root@serveur void]# mount --make-rslave sys
[root@serveur void]# mount --make-rslave dev
[root@serveur void]# cd
[root@serveur ~]# chroot /mnt/void /usr/bin/bash
Vous aurez bien sûr pensé à utiliser la dernière version du rootfs à cet emplacement et utiliser le bon serveur DNS.
Mise à jour du système :
[root@serveur /]# xbps-install -Su
Attention, si la commande précédente est immédiatement Killed (c'est le cas chez FirstHeberg), vous devrez utiliser un autre miroir comme expliqué ici.
Suite à l'installation, vous pourrez supprimer le fichier créé dans /etc/xbps.d/ ou utiliser le miroir de votre choix.
Création d'un utilisateur :
[root@serveur /]# useradd -m -G wheel,floppy,audio,video,cdrom,optical,kvm,xbuilder changeme
[root@serveur /]# passwd changeme
Ajout de l'utilisateur dans le fichier /etc/sudoers avec la commande visudo
, à adapter comme bon vous semble, je décommente cette ligne :
%wheel ALL=(ALL) ALL
Définition du password root :
[root@serveur /]# passwd
Modification du fuseau horaire dans le fichier /etc/rc.conf :
TIMEZONE="Europe/Paris"
Récupération des UUID, vous devrez en toute logique adapter la suite avec les vôtres :
[root@serveur /]# blkid
/dev/sda1: PARTLABEL="primary" PARTUUID="87b05c8e-a339-4bf4-b92e-c626c7d27e34"
/dev/sda2: UUID="881aa33b-f170-4e65-bfd6-32e31d69f2f3" TYPE="ext2" PARTLABEL="primary" PARTUUID="b0bedbc1-f744-4fd0-bec7-fe0bdb705308"
/dev/sda3: UUID="a7768716-3cd2-4a79-ae9e-a0b829b3d0ac" TYPE="crypto_LUKS" PARTLABEL="primary" PARTUUID="73b47d6e-09ec-47ec-bb4e-36d6963ccdf8"
/dev/sda4: UUID="23a6c6d0-f048-49b5-b3e2-b7cedd8cc307" TYPE="swap" PARTLABEL="primary" PARTUUID="249421f4-13e6-4970-8dee-e09c075793dc"
/dev/mapper/root: UUID="86340405-9d6a-4727-8bcf-20da39806231" TYPE="xfs"
Modification de /etc/fstab :
UUID=86340405-9d6a-4727-8bcf-20da39806231 / xfs rw,noatime,nodiratime 0 1
UUID=881aa33b-f170-4e65-bfd6-32e31d69f2f3 /boot ext2 rw,noatime,nodiratime 0 2
UUID=23a6c6d0-f048-49b5-b3e2-b7cedd8cc307 none swap defaults 0 0
tmpfs /tmp tmpfs defaults,nosuid,nodev 0 0
Si vous utilisez un disque SSD, attention à bien ajouter le flag discard ou alors de créer une tâche cron pour la prise en compte du trim.
Définition du hostname :
[root@serveur /]# echo 'changeme' > /etc/hostname
Modification de /etc/locale.conf, vous pouvez utiliser la locale fr_FR.UTF-8 si vous préférez :
LANG=en_US.UTF-8
LC_COLLATE=C
Modification de /etc/default/libc-locales, décommentez la locale de votre choix :
[...]
#en_SG ISO-8859-1
en_US.UTF-8 UTF-8
#en_US ISO-8859-1
[...]
Pour prise en compte si vous avez effectué des modifications :
[root@serveur /]# xbps-reconfigure -f glibc-locales
Installation du kernel, vous pouvez choisir entre linux ou linux-lts :
[root@serveur /]# xbps-install linux
Pour la configuration réseau, vous ajouterez les lignes de commandes que vous avez préparez plus tôt dans le fichier /etc/rc.local :
ip link set dev enp1s0 up
ip addr add 5.XXX.XXX.85/24 brd + dev enp1s0
ip route add default via 5.XXX.XXX.254
ip -6 addr add 2001:XXX:X:XX55::1/128 dev enp1s0
ip -6 route add 2001:XXX:X:XXff:ff:ff:ff:ff dev enp1s0
ip -6 route add default via 2001:XXX:X:XXff:ff:ff:ff:ff
Installation du bootloader, je ne préconise généralement pas grub, mais pour Void Linux c'est bien trop contraignant d'en utiliser un autre :
[root@serveur /]# xbps-install grub
[root@serveur /]# grub-install /dev/sda
Modification du fichier /etc/default/grub, je me répète mais n'oubliez pas d'adapter :
[...]
GRUB_DEFAULT=0
GRUB_HIDDEN_TIMEOUT=0
GRUB_HIDDEN_TIMEOUT_QUIET=true
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR="Void"
GRUB_CMDLINE_LINUX_DEFAULT="loglevel=4 slub_debug=P page_poison=1 ip=5.XXX.XXX.85::5.XXX.XXX.254:255.255.255.0::enp1s0:off rd.luks.uuid=a7768716-3cd2-4a79-ae9e-a0b829b3d0ac"
[...]
Si vous utilisez un disque SSD, n'oubliez pas d'activer le TRIM, dans ce cas la ligne GRUB_CMDLINE_LINUX_DEFAULT ressemblera à ceci :
[...]
GRUB_CMDLINE_LINUX_DEFAULT="loglevel=4 slub_debug=P page_poison=1 ip=5.XXX.XXX.85::5.XXX.XXX.254:255.255.255.0::enp1s0:off rd.luks.uuid=a7768716-3cd2-4a79-ae9e-a0b829b3d0ac rd.luks.allow-discards=a7768716-3cd2-4a79-ae9e-a0b829b3d0ac"
[...]
Installation de cryptsetup, curl, dracut-network et tinyssh :
[root@serveur /]# xbps-install cryptsetup curl dracut-network tinyssh
Lancement automatique d'OpenSSH et suppression des agetty :
[root@serveur /]# cd /etc/runit/runsvdir/current/
[root@serveur current]# ln -s /etc/sv/sshd/
[root@serveur current]# rm -f agetty-tty*
[root@serveur current]# ls
sshd udevd
Attention tout de même, vous n'aurez plus de TTY en accès physique, et c'est ce que je recherche dans un datacenter, par sécurité, vous pouvez laisser agetty-tty1.
A faire que si vous souhaitez conserver un TTY en accès physique :
[root@serveur /]# cd /etc/runit/runsvdir/current/
[root@serveur current]# ln -s /etc/sv/agetty-tty1/
Ajout de votre clé publique de type ED25519 qui servira à déverrouiller votre partition au boot grâce à TinySSH :
[root@serveur /]# echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDG6xoQpsNhFSsn9fIxP0bR3hTKYUYmh72d6fAS10khX doctor@who' > /etc/tinyssh/authorized_keys
[root@serveur /]# chmod 600 /etc/tinyssh/authorized_keys
Le module dracut va utiliser le fichier authorized_keys disponible dans /etc/tinyssh/ en priorité, s'il ne le trouve pas, il ira voir dans /root/.ssh/ et s'il n'en trouve aucune, il ne sera pas intégré dans l'initramfs.
Vous pouvez bien sûr en avoir plusieurs :
[root@serveur /]# cat /etc/tinyssh/authorized_keys
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHXKA9rOvUQmKi1zz339YG8d+wPOL/pq9jmu1krtjujY doctor@who
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH6J/4X1NwxqtLIRZazdRvIvGrUJcIlaL4wPnOik/Q1E saitama@opm
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJl7F5YJ1NUiFW8e1XZXqOpIOAcJ4dEkv45bKVGzaq42 goku@god
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILpN34LuPCMsOUQXgMO5jqZJK+DXpp42a/cy4WGxd8az luffy@gomu
Ajoutez aussi votre clé au niveau de votre utilisateur afin de pouvoir vous connecter sur le système grâce à OpenSSH suite au déverrouillage :
[root@serveur /]# mkdir /home/changeme/.ssh/
[root@serveur /]# chmod 700 /home/changeme/.ssh/
[root@serveur /]# cp /etc/tinyssh/authorized_keys /home/changeme/.ssh/
[root@serveur /]# chown -R changeme: /home/changeme/.ssh/
6. Ajout du module dracut intégrant TinySSH
Récupération du module sur le dépot git :
[root@serveur /]# cd /usr/lib/dracut/modules.d/
[root@serveur modules.d]# curl -O https://gitea.tetsumaki.net/tetsumaki/dracut-crypt-tinyssh/archive/master.tar.gz
[root@serveur modules.d]# tar zxf master.tar.gz
[root@serveur modules.d]# rm -f master.tar.gz
[root@serveur modules.d]# mv dracut-crypt-tinyssh/ 60crypt-tinyssh
Attention, si le téléchargement avec la commande curl est immédiatement Killed (c'est le cas chez FirstHeberg), vous devrez récupérer l'archive sur votre PC puis l'envoyer par scp.
Prise en compte des modifications, remplacez linux4.19 par votre version xbps-query linux
:
[root@serveur /]# xbps-reconfigure -f linux4.19
Nettoyage :
[root@serveur /]# xbps-remove -Oo
7. Redémarrage
Vous avez normalement tout configuré et pour résumer, vous devez contrôler que :
- /etc/rc.local : votre configuration réseau
- /etc/default/grub : vos paramètres réseaux, luks
- /etc/tinyssh/authorized_keys : votre clé publique soit bien présente (pour TinySSH au niveau de l'initramfs)
- /home/changeme/.ssh/authorized_keys : votre clé publique soit bien présente (pour OpenSSH au niveau du système)
Le moment de vérité, sortez du chroot et redémarrez :
[root@serveur ~]# exit
[root@serveur ~]# umount -R /mnt/void/
[root@serveur ~]# reboot
Si tout va bien, vous pouvez vous connecter et déchiffrer votre partition en tapant unlock.sh
:
[user@local ~]$ ssh root@ip
[root@serveur ~]# unlock.sh
Enter passphrase for /dev/sda3:
Vous perdez maintenant la connexion ssh, vous pouvez vous reconnecter et terminer la configuration du système :
[user@local ~]$ ssh user@ip
[user@serveur ~]$ sudo -i
8. Conclusion
Votre système est maintenant installé.
Si votre système ne répond plus ou que vous ne pouvez pas y accéder par SSH c'est que vous avez mal fais quelque chose.
Dans ce cas vous pouvez faire un reboot hardware en rescue et voir ce qui cloche en chrootant.
- Il est fortement conseillé de configurer OpenSSH avec une authentification par clé uniquement
- D'activer iptables et ip6tables :
ln -s /etc/sv/iptables /var/service/
etln -s /etc/sv/ip6tables /var/service/
- D'installer un daemon syslog tel que socklog-void
- D'utiliser tinyssh-convert afin d'utiliser la même clé privée qu'OpenSSH (/etc/ssh/ssh_host_ed25519_key --> /etc/tinyssh/sshkeydir/*)
9. Références et remerciements
- http://man7.org/linux/man-pages/man7/dracut.cmdline.7.html
- https://gitea.tetsumaki.net/tetsumaki/dracut-crypt-tinyssh
- https://wiki.voidlinux.org/Install_LVM_LUKS#Installation_using_void-installer
- https://wiki.voidlinux.org/Installation_via_chroot
- https://wiki.voidlinux.org/Network_Configuration#Static_IP