Cryptage de partitions sous Linux

Avant d’attaquer le cryptage de partitions sous Linux, je vais rappeler quelques règles de base (parce que bon, crypter une partition, ça fait pas tout :))

Sécurisation à minima de sa machine

Je ne rentre pas dans le détail, ce sont justes des principes généraux:

  • protéger l’accès au BIOS par un mot de passe*;
  • protéger le boot manager avec un mot de passe*: on peut soit empêcher le démarrage du kernel en demandant un mot de passe, soit empêcher de passer des options au kernel en demandant un mot de passe (histoire d’empêcher un petit malin de de démarrer avec un init=/bin/sh si pratique quand on a perdu le mot de passe root);
  • empêcher root de se logguer directement sur la machine;
  • ne pas communiquer le mot de passe de root (quand on est plusieurs à se servir d’une machine) ;
  • on ne se loggue pas en root sans avoir une bonne raison ;
  • on ne laisse pas traîner des sessions root ouvertes (un peu de conf dans le serveur SSH, ou des petits outils comme autolog sont très pratiques) ;
  • si on active un serveur SSH sur la machine, c’est une très bonne idée de limiter les utilisateurs qui ont le droit de s’y connecter (cf AllowUsers dans sshd_config(5))
  • configurer correctement NetFilter (cf iptables/ip6tables), ça ne fait jamais de mal, surtout sur une machine nomade que l’on connecte un peu n’importe où.

*: un bon mot de passe fait au moins 8 caractères de longs, il contient des majuscules et des minuscules, un ou plusieurs chiffres et un ou plusieurs signes de ponctuations (personnellement, j’évite ceux qui peuvent avoir une signification dans un shell comme *,# ou \, j’ai déjà eu des surprises). On évite aussi les mots du dictionnaires (même écrit en l33t), les dates de naissances, sa plaque d’immatriculation ou son code de carte de crédit. Au passage, j’en profite pour refaire un peu de pub pour pwgen (package pwgen chez Debian) qui permet de pallier aux problèmes d’imagination quand on doit générer des mots de passe.

Crypter ses partitions:

À mon avis, il y a au moins deux partitions très critiques à protéger: /home qui contient ses données personnelles et de travail, et le swap (vu qu’il contient une image de la mémoire, surtout quand on sert pour mettre sa machine en veille prolongée). Si on le souhaite, on peut aussi crypter l’intégralité de son système (sauf peut-être la partition où l’on stocke le kernel et l’initrd qui va avec), il y a un paquet de tuto sur internet qui expliquent comment jouer avec cryptsetup/LUKS et LVM, je ne l’aborde pas ici.

Dans les exemples qui suivent, le swap sera sur /dev/sda7, et le /home sur /dev/sda8.

Prérequis:

  • installer le package cryptsetup ;
  • choisir un bon mot de passe (voir le laïus plus haut) ;
  • choisir des petits noms pour les partitions (personnellement je fait cNomPartition, c pour dire crypté, ce qui pour la suite donnera cswap pour le swap et chome pour /home) ;
  • les partitions à crypter ne doivent pas être montées, et il faut les backuper avant de faire quoi que ce soit: les opérations suivantes vont tout effacer.

Cryptage des partitions

cryptsetup luksFormat /dev/sda7
cryptsetup luksFormat /dev/sda8

Initialisation/utilisation des partitions

ouverture

cryptsetup luksOpen /dev/sda7 cswap
cryptsetup luksOpen /dev/sda8 chome

On se retrouve avec deux nouveaux périphériques:

  • /dev/mapper/cswap
  • /dev/mapper/chome

formattage et montage

Là, c’est assez standard, il suffit de manipuler les périphériques que l’on vient de créer:

# mkswap -L swap /dev/mapper/cswap
# swapon LABEL=swap
# mkfs.ext4 -L /home /dev/mapper/chome
# mount LABEL=/home /home

Un peu de conf système

mise à jour de l’initrd

# update-initramfs -u -k $(uname -r)

ou plus radical:

# update-initramfs -d -k $(uname -r)
# update-initramfs -c -k $(uname -r)

modif de /etc/crypttab et /etc/fstab

Histoire de pas tout perdre au reboot, on ajoute ces deux lignes dans le fichier /etc/crypttab:

cswap /dev/sda7 none luks
chome /dev/sda8 none luks

et celles-ci dans le fichier /etc/fstab:

LABEL=swap none swap sw 0 0
LABEL=/home /home ext relatime,nodev,nosuid 0 2

Maintenant, au reboot, le système vous demande un mot de passe pour chaque volume crypté qu’il active puis monte.

Si quelqu’un démonte le disque dur pour le mettre ailleurs, il devrait bien se casser les dents sur vos données 🙂

Outils de gestion de contrôleur RAID 3-ware

Récupération et installation de l’outil (tw_cli):

Ça se passe sur le site de 3-ware (http://www.3ware.com) (support → documents and downloads). On y récupère gros zip (~ 10Mo) 3DM2_CLI-Linux_10.2.1_9.5.4.zip.

On décompresse tout ça dans /opt (ou /usr/local, ou ce que vous voulez), et on se débrouille pour que $instdir/tw_cli.(x86_64|x86) soit dans le PATH ou on fait un bête lien symbolique:

ln -s $instdir/tw_cli.x86_64 /usr/local/sbin/tw_cli

Utilisation / mise en place:

[root@host: ~]# tw_cli
//host> show
 Ctl   Model        (V)Ports  Drives   Units   NotOpt  RRate   VRate  BBU
 ------------------------------------------------------------------------
 c0    9750-8i      7         7        1       0       1       1      -
//host> /c0 show # ajouter «all» pour avoir plus de détails
 Unit  UnitType  Status         %RCmpl  %V/I/M  Stripe  Size(GB)  Cache  AVrfy
 ------------------------------------------------------------------------------
 u0    RAID-0    OK             -       -       256K    2933.59   RbW    ON
 VPort Status         Unit Size      Type  Phy Encl-Slot    Model
 ------------------------------------------------------------------------------
 p0    OK             u0   419.18 GB SAS   0   -            SEAGATE ST3450857SS
 p1    OK             u0   419.18 GB SAS   1   -            SEAGATE ST3450857SS
 p2    OK             u0   419.18 GB SAS   2   -            SEAGATE ST3450857SS
 p3    OK             u0   419.18 GB SAS   3   -            SEAGATE ST3450857SS
 p5    OK             u0   419.18 GB SAS   5   -            SEAGATE ST3450857SS
 p6    OK             u0   419.18 GB SAS   6   -            SEAGATE ST3450857SS
 p7    OK             u0   419.18 GB SAS   7   -            SEAGATE ST3450857SS
//host> /c0 add type=raid0 disk=0:7 stripe=256 autoverify storsave=perform  # ajout d'une grappe raid0
//host> /c0/u0 show # ajouter «all» pour avoir plus de détails
 Unit     UnitType  Status         %RCmpl  %V/I/M  VPort Stripe  Size(GB)
 ------------------------------------------------------------------------
 u0       RAID-0    OK             -       -       -     256K    2933.59
 u0-0     DISK      OK             -       -       p0    -       419.085
 u0-1     DISK      OK             -       -       p1    -       419.085
 u0-2     DISK      OK             -       -       p2    -       419.085
 u0-3     DISK      OK             -       -       p3    -       419.085
 u0-4     DISK      OK             -       -       p5    -       419.085
 u0-5     DISK      OK             -       -       p6    -       419.085
 u0-6     DISK      OK             -       -       p7    -       419.085
 u0/v0    Volume    -              -       -       -     -       2933.59
//host> /c0/u0 set autoverify=on
//host> /c0/u0 set cache=on # cette option et la suivantes requiert d'avoir un pack
//host> /c0/u0 set set wrcache=on # de batterie et une alimentation sécurisée sur onduleur
//host> /c0/u0 set rdcache=basic
//host> /c0/u0 set storsave=perform
//host> /c0/u0 set rapidrecovery=all
//host> quit
[root@host: ~]#
Après ça, si on a juste un disque avec le système (/dev/sda) et un le volume contrôleur raid avec son volume, on voit apparaître un /dev/sdb, sans partition.
Si le volume raid fait plus de 2To, il ne faut pas oublier de créer une table de partition au format GPT si on veut pouvoir tout utiliser. Comme *fdisk ne gère pas ça, on passe par parted:
[root@host: ~]# parted /dev/sdb > mklabel gpt # création de la table de partition au bon format > mkpart primary 0 100% # création d'une seule partition qui prend tout le volume > quit
[root@host: ~]#
La doc de 3ware recommande quelques petites choses à faire au niveau système pour tirer pleinement profit du contrôleur:
  • passer le I/O scheduler en mode deadline:
    • à chaud:
echo deadline > /sys/block/sdb/queue/scheduler
    • on le fait de façon pérenne (pour Debian avec GRUB2): ajouter elevator=deadline à la variable GRUB_CMDLINE_LINUX dans le fichier /etc/default/grub puis exécuter la commande update-grub
  • augmenter la taille du buffer pour le read-ahead:
    • à chaud:
blockdev --setra 16384 /dev/sdb
    • on rend ça pérenne en ajoutant cette même ligne dans le fichier /etc/rc.local.
Personnellement je rajoute aussi au moins ça dans mon /etc/sysctl.conf:
vm.min_free_kbytes = 65536
vm.dirty_background_ratio = 20
vm.dirty_ratio = 60

Ensuite, je formate tout ça en XFS (voir cet article à ce sujet).

Utilisation de XFS…

pour la suite:

  • $volname : nom que l’on veut attribuer au volume, en général, je met le nom du point de montage ;
  • $s : taille du log de journalisation, je met de 64m ou 128m en fonction de la quantité de ram sur la machine (ram ≤ 12Go → 64, ram > 12Go → 128) ;
  • $dev : nom du device à formatter (partition, volume RAID, volume LVS) ;
  • $mount : nom du point de montage ;
  • option entre «[ ]» → option facultative.

formatage du volume:

mkfs.xfs [-L $volname] -d agcount=32 -l size=${s}m -i maxpct=0 $dev

montage du volume:

Suivant l’usage qu’on aura du volume XFS, on peut remplacer noatime,nodiratime par relatime, et on peut ajouter l’option largeio.

Les options nodev,nosuid et noexec sont facultatives (mais très recommandées). A noter qu’il vaut mieux éviter le noexec sur une partition qui servira à stocker le home de vos utilisateurs…

/etc/fstab:

$dev $mount xfs noatime,nodiratime,logbufs=8,logbsize=256k,attr2,inode64[,largeio],auto,nodev,nosuid,noexec 0 0

depuis le shell:

[root@host :~]# mount -t xfs -o nodev,nosuid,noexec,noatime,nodiratime,\
logbufs=8,logbsize=256k,attr2,inode64[,largeio],auto $dev $mount

quelques options utiles niveau sysctl:

au moins:

vm.dirty_writeback_centisecs = 1500
fs.xfs.xfssyncd_centisecs = 360000
fs.xfs.xfsbufd_centisecs = 3000

et aussi:

vm.min_free_kbytes = 65536*
vm.overcommit_ratio = 2
vm.dirty_background_ratio = 20
vm.dirty_ratio = 60

* valeur comprise entre 16Mo (16384ko) et 64Mo (65536ko). à adapter en fonction de la machine