Florent Peterschmitt

Backups avec BURP, LXC, LUKS et un montage réseau

Petite problématique de sauvegarde chiffrée à travers le réseau, dans un conteneur. Au programme :

  • LUKS pour le chiffrement
  • Configuration LXC
  • mknod (obscure)
  • BURP (BackUp and Restore Program)

Contraintes

  • Stockage délégué à l’hébergeur via un stockage réseau SFTP ou CIFS
  • Minimisation de l’espace occupé via de la sauvegarde incrémentale (ça coûte des sous, hein)
  • Installation du système de backup isolée dans un conteneur LXC

Configuration LXC

Dans le fichier config de votre machine LXC, ajouter ces lignes :

# /dev/loop0
lxc.cgroup.devices.allow = b 7:0 rwm
# /dev/mapper/control
lxc.cgroup.devices.allow = c 10:236 rwm
# /dev/mapper/<votre luks>
lxc.cgroup.devices.allow = b 253:* rwm

Redémarrez le conteneur mais pas avec reboot.

Une fois que c’est fait, il vous faudra avoir chargé le module loop sur la machine hôte et créé le node loop0 dans le conteneur :

mknod /dev/loop0 b 7 0

LUKS

Premièrement, montons notre stockage réseau. Pour cela j’ai une entrée fstab avec le point de montage. On oubliera pas de peupler le fichier backup-credentials :

echo '//backup-host/backup /root/srv-backup-cifs cifs iocharset=utf8,rw,credentials=/root/backup-credentials,uid=root,gid=root,file_mode=0600,dir_mode=0700,noauto 0 0' >> /etc/fstab
mkdir /root/srv-backup-cifs
mount /root/srv-backup-cifs

Création d’un fichier sparse de 1Tio. Je n’ai pas cet espace de stockage, mais si un jour il y en a besoin, le fichier est déjà prêt. Bon enfin c’est juste pour faire joujou hein.

cd /root/srv-backup-cifs
dd if=/dev/zero of=luks.backup.raw count=0 seek=1024G
cryptsetup luksFormat luks.backup.raw # passez les options que vous souhaitez pour chiffrer votre conteneur

Une fois que c’est fait, on va pouvoir ouvrir notre LUKS et y créer un système de fichier afin de stocker normalement nos fichiers :

cryptsetup luksOpen luks.backup.raw luks_backup # --key-file vous sera utile pour stocker une passphrase dans un fichier afin de monter le volume sans intervention manuelle. À conserver à l’abrit des regards indiscrets…

mkfs.ext4 /dev/mapper/luks_backup

BURP

Cette solution de sauvegarde et restauration est simple, légère (129KB!) , en mode client/serveur, gère les sauvegardes incrémentales et leur restauration, utilise SSL pour les communications, se configure très facilement… et tout un tas d’autres choses, j’en parlerai une autre fois.

Pour info, j’ai créé deux rôles Ansible pour configurer burp :

ansible-role-backup-burp-client sur github

ansible-role-backup-burp-server sur github

Et voici un exemple de configuration qui va bien :

---
burp_server_clients:
    - { cname: '01-mail', password: 'secret' }

burp_server_timer_args:
    - '1s'

burp_server_script_pre: '/root/mount-backup.sh'

En tout cas, par défaut, BURP sauvegarde dans /var/spool/burp.

Bon bah, il ne nous reste plus qu’à faire notre montage :

mount /dev/mapper/luks_backup /var/spool/burp

Voici la configuration serveur BURP qui nous intéresse :

mode = server
directory = /var/spool/burp
working_dir_recovery_method = delete
user=root
group=root

Tous les fichiers seront stockés en root:root dans le répertoire vu plus haut. Et voici la configuration d’un client :

mode = client
server = host-backup-burp.local
cname = 01-mail
user=root
group=root
include = /var/vmails/
exclude_fs = sysfs
exclude_fs = tmpfs
min_file_size = 0 Mb
max_file_size = 0 Mb

Une fois que nous aurons lancé un backup sur le client et que celui-ci sera terminé (burp -a b), nous aurons un petit nouveau dans /var/spool/burp :

├── 01-mail
│   ├── 0000001 2015-04-15 16:28:36
│   │   └── data
│   │       └── t
│   │           └── var
│   │               └── vmails

... bla bla bla bla bla bla bla bla bla bla bla ...

│   └── current -> 0000001 2015-04-15 16:28:36

Si je recommance un backup un peu plus tard, un nouveau dossier daté sera créé et le pointeur current sera déplacé sur ce nouveau dossier. Et je n’aurai en tout que le différentiel du backup.

Scripter BURP

Pour s’assurer que nos backup seront bien faits sur notre luks, et pas notre machine locale, ajoutons un script qui se lancera à chaque connexion d’un client :

server_script_pre=/root/mount-backup.sh

mount-backup.sh

#!/bin/sh
if [ ! -e /dev/loop0 ]; then
    mknod /dev/loop0 b 7 0 || exit 1
fi

if [ "$(mount|grep "/var/spool/burp"|grep -v grep)" = "" ]; then
    mount /root/srv-backup-cifs || exit 1
    cryptsetup luksOpen /root/srv-backup-cifs/luks.backup.rawdisk luks_backup --key-file /root/luks_backup_keyfile 2>&1 || exit 1
    mount /dev/mapper/luks_backup /var/spool/burp || exit 1
else
    echo "already mounted"
fi

C’est un peu moche et pas franchement résistant à la panne… que se passe-t-il si coupure réseau ? Le mieux serait de démonter notre “disque” à chaque fin de backup si possible (= pas d’autre backup en cours).

Je ne sais pas si une unité systemd serait plus efficace dans ce genre de job, en tout cas ça serait à tester.

Conclusion

Il me semble n’avoir rien oublié, aussi si ça ne fonctionne pas, un petit mail et je corrige.

Comments