Installer Ubuntu dans une partition chiffrée sur un serveur Kimsufi

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 :

  1. 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
  2. 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 :

  1. Créer une VM avec VirtualBox et y installer une distribution Ubuntu Server 14.04 LTS 64bits
  2. 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
  3. 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 »)
  4. 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 :

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *