jeudi, décembre 06, 2012

Installation de FreeBSD sur partition chiffrée

Le concept

Cet article présente l'usage de geli pour l'installation d'un FreeBSD (9.1) sur un disque chiffré.
Le module geli permet:
  1. D'utiliser l'assistance matériel si elle est disponible (comme l'aesni des processeurs Intel).
  2. De gérer des clés «maitres» (cas typique d'usage en entreprise: Une clé «maitre» stockée dans le coffre du bureau sécurité, permettant l'accès d'un disque en cas de perte d'une clé «salarié»).
  3. De générer des clés aléatoires: Utile pour avoir une clé différente pour la partition swap à chaque re-démarrage.
L'intégralité des partitions du disque ne sont pas chiffrées:
  1. La partition contenant le boot-loader (utilisant GPT, on réserve une partition pour lui) est en clair
  2. La partition contenant la configuration des boot-loader, le noyau et ses modules est en clair
  3. Tout le reste est chiffré (le /)
Cet exemple présente un usage simple sur un PC portable personnel, c'est à dire avec cette configuration:
  1. Utilisation d'un mot de passe uniquement (pas de clé)
  2. Pas de partition swap
À noter:
Le mot de passe étant demandé pendant le chargement du noyau, le clavier sera obligatoirement en QWERTY (à moins de reconfigurer/recompiler un noyau)… Donc pensez-y lorsque vous rentrez votre mot de passe ;-)

Un dessin vaut mieux qu'un long discours

Voici l'organisation des partitions sur votre disque à la fin de cette installation:


La procédure d'installation détaillée

Démarrage de l'installateur

On commence par lancer l'installateur et sélectionner les options suivantes:
  1. Install
  2. Distribution Select: Vous pouvez décocher le «port tree», le fabuleux pkgng boostrapable depuis la 9.1 rend caduque l'ancienne méthode de compilation des ports (et fini les portmaster/portupgrade)
  3. Partitioning: Attention ! C'est là qu'il faut choisir «Shell»

Partitionnement et chiffrage «en ligne de commande» du disque

Une fois dans le shell, afficher la liste des disques détectés par le système:

# sysctl kern.disks
kern.disks: ada0 cd0
 

Facile ici, il n'y a que ada0 (cd0 étant le lecteur CD), on commence par le ré-initialiser et lui créer une table GPT (la MBR c'est pour les vieux):

# gpart destroy -F ada0
gpart: arg0 'ada0': Invalid argument (si disque vide)
ou

ada0 destroyed (si table MBR/GPT déja présente)
# gpart create -s gpt ada0
ada0 created


Créer la première partition (p1) contenant le boot-loader:

# gpart add -t freebsd-boot -s 64k -a 4k ada0
ada0p1 added
# gpart bootcode -b /boot/pmbr -p /boot/gptboot -i 1 ada0
bootcode written to ada0
 


Puis créer la deuxième (p2) de 1G qui va contenir le noyau:

# gpart add -t freebsd-ufs -s 1G -l bootpart -a 4k ada0
ada0p2 added
# newfs -j gpt/bootpart
gpt/bootpart: 1024.0MB (2097152 sectors) block size 32768, fragment size 4096
        using 4 cylinder groups of 256.03MB, 8193 blks, 32896 inodes.
        with soft updates
super-block backups (for fsck_ffs -b #) at:
 192, 524544, 1048896, 1573248
newfs: Can't stat gpt/bootpart: No such file or directory
Using inode 4 in cg 0 for 8388608 byte journal
newfs: soft updates journaling set


Puis créer, initialiser le chiffrement (clé a 256bits, taille de secteur a 4k), attacher et formatter la troisième partition (p3) qui va contenir tout le reste.
En profiter pour charger votre drivers crypto (ici aesni car processeur Intel).

# gpart add -t freebsd-ufs -l rootfs -a 4k ada0
ada0p3 added
# kldload aesni
cryptosoft0: <software crypto> on motherboard

aesni0: <AES-CBC,AES-XTS> on motherboard
# geli init -s 4096 -bl 256 gpt/rootfs
Enter new passphrase: jemmerdeleBEFTI
etOCLTIC
Reenter new passphrase: jemmerdeleBEFTIet
OCLTIC

Metadata backup can be found in /var/backups/gpt_rootfs.eli and
can be restored with the following command:

        # geli restore /var/backups/gpt_rootfs.eli gpt/rootfs
# geli attach gpt/rootfs
Enter passphrase:
jemmerdeleBEFTIetOCLTIC
GEOM_ELI: Device gpt/rootfs.eli created.
GEOM_ELI: Encryption: AES-XTS 256
GEOM_ELI:     Crypto: hardware
# newfs -j gpt/rootfs.eli
gpt/rootfs.eli: 9215.9MB (18874168 sectors) block size 32768, fragment size 4096
        using 15 cylinder groups of 626.09MB, 20035 blks, 80256 inodes.
        with soft updates
super-block backups (for fsck_ffs -b #) at:
 192, 1282432, 2564672, 3846912, 5129152, 6411392, 7693632, 8975872, 10258112,
 11540352, 12822592, 14104832, 15387072, 16669312, 17951552
newfs: Can't stat gpt/rootfs.eli: No such file or directory
Using inode 4 in cg 0 for 33554432 byte journal
newfs: soft updates journaling set


Reste le montage de ces partitions au bon endroit avant de retourner à l'installateur:

# mount /dev/gpt/rootfs.eli /mnt/
# mkdir /mnt/bootpart
# cd /mnt
# ln -s bootpart/boot boot
# mount /dev/gpt/bootpart /mnt/bootpart

# mkdir bootpart/boot

Et quitter le shell pour revenir à l'installateur:
# exit

Retour à l'installateur 

Terminer l'installation et la configuration réseau, timezone, services à activer, puis:
  1. Dumpdev Configuration: No, car il n'existe pas de partiton swap pour la récupérer
  2. Final Configuration: Exit
  3. Manual Configuration: Yes, pour lancer une dernière fois le shell avant de redémarrer la machine

Finalisation de la configuration par le shell

On commence par vérifier que l'installation s'est correctement déroulée puis à configurer correctement le fichier boot/loader.conf:

# test -L boot && echo "ok" || echo "NOK !"
ok

# test -f bootpart/boot/loader && echo "ok" || echo "NOK !"
ok

# cat > boot/loader.conf <<EOF
> geom_eli_load="YES"
> aesni_load="YES"
> vfs.root.mountfrom="ufs:/dev/ada0p3.eli"
> EOF


Note: Ne pas essayer d'utiliser les label gpt pour le vfs.root.mountfrom car ça ne fonctionne pas.

Puis la génération du etc/fstab:

# cat > etc/fstab <<EOF
> /dev/gpt/bootpart /bootpart ufs rw,noatime 1 1
> /dev/gpt/rootfs.eli / ufs rw,noatime 1 1
> EOF 


On en profite aussi pour générer le mtree qui récupére l'emprunte sha256 de l'ensemble des fichiers de la partition /bootpart que vous stockerez sur votre partition chiffrée.

# cd /bootpart
# mtree -x -ic -k sha256digest > /root/boot.mtree


Et enfin quitter le shell et rebooter:

# quit 

Le démarrage

Désormais, au démarrage, pendant le chargement du noyau, s'affichera le message suivant puis il attendra votre mot de passe:
Enter passphrase for ada0p3: 

Note: Il arrive que cette phrase soit mélangée dans le dmesg et pas très visible. Il suffit alors de taper votre mot de passe quand le démarrage semble en pause.

Pour les paranos

Lors de l'étape de finalisation, juste avant le reboot, nous avons créé un fichier mtree.
Cette étape sert à vous protéger d'un vecteur d'attaque assez vicieux:
 Pour obtenir votre mot de passe il est possible d'aller remplacer le noyau (car stocké sur partition en clair) par un noyau modifié (qui enregistrer votre mot de passe à votre insu).
Le fait d'avoir stocké l'emprunte sha256 des fichiers en clair sur la partition chiffrée, et de vérifier leur cohérence après chaque démarrage (un petit script fait très bien l'affaire) permet de limiter cette attaque.
Pour vérifier la cohérence des fichiers avec le mtree, c'est cette commande:
mtree -f /root/boot.mtree -p /bootpart
S'il n'affiche rien: C'est bon signe :-)

Sources

Je me suis appuyé sur les deux articles suivants: