Pour pouvoir faire de l’autohébergement pour pas trop cher, j’ai un serveur Kimsufi chez OVH. Seulement, qui dit autohébergement dit données personnelles et donc nécessité de les protéger. Or le serveur, dont je ne suis que locataire, est situé dans un datacenter que je ne verrai probablement jamais, et je ne maîtrise pas qui a un accès physique à la machine.
D’où l’idée de vouloir faire un chiffrement complet du disque dur, pour que même si quelqu’un avait l’idée d’aller fouiller dedans, il ne puisse pas y lire quoi que ce soit.
L’OS que je veux utiliser est une distribution Ubuntu Server 14.04 LTS avec le chiffrement proposé à base de dm-crypt/cryptsetup/LUKS. Tout le root file system (y compris le /home) et la partition swap sont chiffrés. Seule la partition de boot qui contient l’initramfs et le kernel n’est pas chiffrée, pour permettre de démarrer le système et attendre que l’utilisateur entre la clé de déverrouillage.
Deux problèmes se posent :
- l’interface de gestion Kimsufi permet seulement d’installer un nombre limité de distributions Linux, avec une configuration prédéfinie et pas de chiffrement de partitions
- le système repose sur le fait d’entrer la clé au démarrage pour déverrouiller la partition, ce qui n’est pas possible sur un serveur « headless », sans clavier et écran et à l’autre bout du monde
Pour le premier point, il va donc falloir faire une installation custom du serveur, à distance et sans clavier+écran.
Pour le second point, l’astuce consiste à installer dans l’initramfs un serveur SSH sur lequel on va pouvoir se connecter à distance pour entrer la clé de déverrouillage et débloquer la suite du démarrage.
Préparation :
La technique que j’ai choisie va consister à faire une installation dans une machine virtuelle sur un PC de bureau avec le chiffrement, puis de copier par le réseau le root file system généré et le contenu de la partition de boot vers le serveur Kimsufi démarré en mode rescue.
Les étapes :
- Créer une VM avec VirtualBox et y installer une distribution Ubuntu Server 14.04 LTS 64bits
- Configurer l’initramfs pour permettre le remote unlock par SSH ; vérifier le bon fonctionnement en testant le déverrouillage par SSH depuis l’hôte de la VM par exemple
- Redémarrer la VM sur un LiveCD Ubuntu Desktop par exemple et monter un emplacement réseau qui peut recevoir une copie du système dans un fichier (montage NFS dans « /mnt/nfs »)
- Depuis le LiveCD, déverrouiller la partition chiffrée :
# cryptsetup luksOpen /dev/sda5 sda5_crypt # vgscan --mknodes # vgchange -ay
Réaliser une copie compressée du root file system :
# dd if=/dev/mapper/ubuntu--vg-root conv=sync,noerror bs=64K | gzip -c > /mnt/nfs/rootfs.img.gz
Copier le contenu de la partiton de boot :
# mkdir /mnt/boot # mount /dev/sda1 /mnt/boot/ # cp -ar /mnt/boot /mnt/nfs/
Note : la destination de la copie doit être accessible depuis le serveur Kimsufi (IP publique).
Tout est maintenant prêt pour passer sur le Kimsufi.
Sur le serveur Kimsufi :
Je pars d’un Kimsufi tout neuf avec dessus une distribution Ubuntu Server 14.04 LTS 64bits fraîchement installée par OVH/Kimsufi. Mais peut importe le choix de la distribution via le manager Kimsufi, puisqu’on va tout écraser.
Tout d’abord :
- désactiver le monitoring dans le manager Kimsufi (pour éviter les mails d’alerte)
- sélectionner le démarrage en rescue-pro
- redémarrer le serveur
- se connecter en SSH avec le mot de passe reçu par mail
La commande parted devrait donner quelque chose dans ce genre :
# parted -l Model: ATA HGST HUS724020AL (scsi) Disk /dev/sda: 2000GB Sector size (logical/physical): 512B/512B Partition Table: gpt Disk Flags: Number Start End Size File system Name Flags 1 20.5kB 1049kB 1029kB primary bios_grub 2 2097kB 1996GB 1996GB ext4 primary 3 1996GB 2000GB 4294MB linux-swap(v1) primary
On va modifier les partitions avec cgdisk (warning : toutes les données seront perdues).
# cgdisk
- laisser la « BIOS boot partition » telle quelle
- supprimer les partitions « Linux filesystem » et « Linux swap »
- créer une partition « Linux filesystem » de 250 Mo
- créer une partition « Linux filesystem » sur le reste de l’espace libre
On redémarre la machine (toujours en rescue) pour que les changement soient bien pris en compte :
# reboot
La commande parted doit maintenant donner ceci :
# parted -l Error: Can't have overlapping partitions. Model: ATA HGST HUS724020AL (scsi) Disk /dev/sda: 2000GB Sector size (logical/physical): 512B/512B Partition Table: gpt Disk Flags: Number Start End Size File system Name Flags 1 20.5kB 1049kB 1029kB primary bios_grub 2 1053kB 263MB 262MB 3 263MB 2000GB 2000GB
Note : je n’ai pas compris l’erreur « can’t have overlapping partitions », mais ça ne semble pas avoir d’incidence sur la suite.
Créer un système de fichiers EXT2 pour la partition de boot :
# mkfs.ext2 /dev/sda2
Créer le conteneur chiffré avec cryptsetup :
# cryptsetup -y -s 512 -c serpent-xts-plain64 luksFormat /dev/sda3 # cryptsetup luksOpen /dev/sda3 sda3_crypt
Note : le choix de l’algo de chiffrement peut se faire en fonction des perfs de la machine. Le CPU Atom N2800 du KS-2 ne disposant pas des instructions AES-NI, AES ne sera pas forcément le choix le plus performant. Un bench peut être réalisé sur la machine (y compris depuis le rescue) avec la commande « cryptsetup benchmark ».
Créer les volumes pour le root FS et la swap avec LVM dans la partition chiffrée :
# pvcreate /dev/mapper/sda3_crypt # vgcreate ubuntu-vg /dev/mapper/sda3_crypt # lvcreate -L 4G -n swap_1 ubuntu-vg # lvcreate -l 100%FREE -n root ubuntu-vg
Créer la partition swap :
# mkswap /dev/mapper/ubuntu--vg-swap_1
Monter l’emplacement NFS où l’on a mis la copie du système installé dans la machine virtuelle. Décompresser l’image de la partition root dans son volume logique :
# mkdir /mnt/nfs
# mount -t nfs [...] /mnt/nfs
# gunzip -c /mnt/nfs/rootfs.img.gz | dd of=/dev/mapper/ubuntu--vg-root
Redimensionner le file system pour occuper tout le volume logique :
# resize2fs /dev/mapper/ubuntu--vg-root
Monter maintenant le nouveau root FS ainsi que la partition de boot (pour l’instant toujours vide) :
# mkdir /mnt/ubuntu # mount /dev/mapper/ubuntu--vg-root /mnt/ubuntu/ # mkdir /mnt/boot # mount /dev/sda2 /mnt/boot/
Copier les fichiers de la partition de boot depuis le montage NFS :
# cp -ar /mnt/nfs/boot/* /mnt/boot/ # umount /mnt/boot
Noter la configuration réseau de l’interface eth0 (le rescue est probablement en DHCP, mais pour la prod on préférera une config en IP fixe) :
# ifconfig eth0 # route -n # cat /etc/resolv.conf
L’étape suivante est de chrooter dans le root FS Ubuntu pour compléter la configuration :
# swapon /dev/mapper/scoresby2--vg-swap_1 # mount -o bind /dev /mnt/ubuntu/dev # mount -t proc proc /mnt/ubuntu/proc # mount -t sysfs sys /mnt/ubuntu/sys # XTERM=xterm-color LANG=C.UTF-8 chroot /mnt/ubuntu /bin/bash # mount /dev/sda2 /boot/
A l’aide de la commande blkid, on trouve les UUID des différentes partitions et volumes logiques :
# blkid
Editer le fichier /etc/crypttab avec l’UUID de la partition /dev/sda3 :
# vi /etc/crypttab
sda3_crypt UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx none luks,discard
Editer le fichier /etc/fstab avec l’UUID de la partition /dev/sda2 :
# vi /etc/fstab
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /boot ext2 defaults 0 2
Créer un lien symbolique pour /etc/mtab :
# ln -sf /proc/mounts /etc/mtab
Côté réseau, il faut configurer l’interface eth0 avec l’IP fixe que l’on a notée dans un coin, ainsi que le serveur DNS.
# vi /etc/network/interfaces
auto lo iface lo inet loopback auto eth0 iface eth0 inet static address [...] netmask [...] network [...] broadcast [...] gateway [...] pre-up /sbin/ip addr flush dev eth0 || true [+ config IPv6]
Note : la commande de pre-up sert à se débarrasser de la config réseau utilisée pendant l’initramfs (pour déverrouiller le volume chiffré en remote).
# vi /etc/resolv.conf
nameserver 127.0.0.1
nameserver [...]
search ovh.net
Il faut maintenant configurer GRUB2 pour le démarrage du serveur. On doit s’assurer que le système démarrera bien automatiquement sur Ubuntu, et définir la configuration réseau pour le kernel.
# vi /etc/default/grub
GRUB_DEFAULT=0 GRUB_HIDDEN_TIMEOUT=2 GRUB_HIDDEN_TIMEOUT_QUIET=true GRUB_TIMEOUT=0 GRUB_RECORDFAIL_TIMEOUT=$GRUB_HIDDEN_TIMEOUT GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian` GRUB_CMDLINE_LINUX_DEFAULT="" GRUB_CMDLINE_LINUX="ip=[ip-address]::[default-gateway]:[netmask]::eth0:none net.ifnames=0 biosdevname=0" GRUB_TERMINAL=console GRUB_DISABLE_RECOVERY="true"
Notes :
- l’option « GRUB_RECORDFAIL_TIMEOUT » permet de ne pas bloquer dans le menu de GRUB après un échec au démarrage et de s’assurer qu’on démarrera sur l’option par défaut
- les paramètres « net.ifnames=0 » et « biosdevname=0 » permettent d’éviter que l’interface réseau eth0 ne soit renommée en autre chose (force le nommage legacy)
Pour le principe, je dégage l’option memory test du menu de GRUB :
# chmod -x /etc/grub.d/20_memtest86+
On installe GRUB sur le disque /dev/sda :
# grub-install /dev/sda # update-grub
On met à jour l’initramfs :
# update-initramfs -u
On peut vérifier le contenu de l’initramfs :
# zcat /boot/initrd.img-* | cpio -t conf/conf.d/cryptroot etc/lvm/lvm.conf etc/dropbear/\* root/.ssh/authorized_keys sbin/dropbear
Vérifier que la sortie contient bien :
root/.ssh/authorized_keys sbin/dropbear conf/conf.d/cryptroot etc/lvm/lvm.conf etc/dropbear/dropbear_dss_host_key etc/dropbear/dropbear_rsa_host_key
# zcat /boot/initrd.img-* | cpio -i --to-stdout conf/conf.d/cryptroot
Vérifier que la sortie est de la forme :
target=sda3_crypt,source=UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx,key=none,rootdev,lvm=ubuntu--vg-root
La configuration est terminée. On sort maintenant du chroot, on démonte les partitions et on ferme le volume chiffré :
# umount /boot # exit # umount /mnt/ubuntu/{dev,proc,sys} # umount /mnt/ubuntu # swapoff -a # lvchange -an /dev/mapper/ubuntu--vg-* # cryptsetup luksClose sda3_crypt
Retourner dans le manager Kimsufi et sélectionner le démarrage sur le disque dur. On serre les fesses et
# reboot
Si tout va bien, la machine démarre et attend dans l’initramfs que le volume chiffrée soit déverrouillé. On se connecte en SSH (sur Dropbear) et la commande « unlock » perment d’entrer la passphrase. On peut ensuite se déconnecter et se reconnecter une fois que le serveur a fini de démarrer (sur OpenSSH cette fois-ci).
Si ça ne marche pas, on peut redémarrer en rescue et vérifier la configuration. On peut aussi démarrer sur le disque dur via QEMU dans le rescue pour débuguer la séquence de boot avec une connexion VNC.
Sources :