====== TX Printemps 2018 : Chiffrement des snapshots et externalisation ======
===== Résumé =====
La configuration actuelle d'Alice et Bob est telle que de nombreuses machines virtuelles (VM) tournent sur chacune des deux machines. Afin de pouvoir récupérer des données en cas de défaillance, il est nécessaire d'effectuer des backups de ces VM afin de pouvoir les réinstaller ultérieurement. Cependant, la nécessité d'effectuer des backups se heurte à deux problématiques : le support de stockage et la quantité de stockage.
Proxmox fournit directement la possibilité d'effectuer des backups quotidiennement. La configuration lance un backup de chaque VM à 03h du matin, période avec peu d'activité sur ces machines. Il permet aussi une rotation des backups des VM. Cependant sans script supplémentaires, ce seul système présente plusieurs problèmes.
Tout d'abord, les backups sont stockés sur le même support sur lequel tourne les VM (les backups des VM d'Alice sont sur Alice, et celles de Bob sont sur Bob). En cas de défaillance physique d'Alice ou de Bob, les VM de la machine seront perdues ainsi que leur backup. Il ne sera donc pas possible de récupérer les VM concernées dans ce cas.
Enfin, les backups devraient pouvoir être accédés par les différents bénévoles de l'association. Cependant, ils ne doivent pas être en mesure de récupérer des informations critiques depuis ces backups. Il est donc nécessaire de chiffrer les VM que peuvent récupérer les bénévoles, et que l'accès aux backups chiffrés ne permette d'effectuer d'autres actions imprévues.
La solution implémentée est un script Python déclenché par Proxmox lors de la construction des backups de chaque VM. Ce script effectue deux opérations : il copie les backups présentes sur Alice et Bob et les copie sur l'autre machine. Ainsi toutes les backups d'Alice sont aussi présentes sur Bob et vice-versa. Cela permet de récupérer les données en cas de défaillance physique d'une des machines.
Afin de permettre aux utilisateurs de récupérer les backups chiffrés sans risque, un chroot a été créé sur Bob, permettant à l'utilisateur "snapshots" de se connecter et être en mesure de copier les backups chiffrés accessibles. Il n'est pas possible pour cet utilisateur d'accéder à une backup non chiffrée ou d'utiliser d'autres commandes quand il est connecté.
Une autre fonctionnalité implémentée est la rotation des backups chiffrés sur Alice et Bob, afin de préserver suffisamment d'espace libre sur chacune des machines. Les paramètres pour la rotation peuvent être modifiés depuis un fichier de configuration.
===== Installation =====
L'ensemble des fichiers nécessaires pour l'installation est situé dans ce [[https://gitlab.utc.fr/picasoft/rotation-vm|répo Git]]. Son contenu peut être récupéré via la commande suivante :
git clone git@gitlab.utc.fr:picasoft/rotation-vm.git
Sur la machine visée pour l'installation, avec Proxmox déjà installé et fonctionnel, installez les paquets suivants :
apt-get install python3
apt-get install python3-pip
Ainsi que les paquets pythons suivants :
pip3 install rotate-backups
pip3 install python-gnupg
Note : attention à bien installer le paquet [[https://pythonhosted.org/python-gnupg/|python-gnupg]] et non le paquet [[https://python-gnupg.readthedocs.io/en/latest/|gnupg]], qui malgré leurs similarités et noms proches fonctionnent différemment.
Ajoutez les fichiers du [[https://gitlab.utc.fr/picasoft/rotation-vm/|répo Git]] suivants sur la machine dans un même dossier :
* hook_script.py
* config.json
Editez le fichier /etc/vzdump.conf et modifiez la ligne suivante :
script: /root/scripts/hook_script.py
Modifiez le fichier de configuration config.json pour correspondre à l'usage nécessaire (champs du fichier de configuration détaillés plus bas dans cette page).
Le hook_script sera lancé automatiquement à chaque backup de Proxmox. Vous pouvez vérifier si ce dernier a bien fonctionné en vérifiant sur Proxmox dans la liste des tâches si le backup s'est déroulé correctement :
{{:txs:infra-p18:capture_d_ecran_2018-06-07_22-12-57.png|}}
===== Configuration =====
==== Proxmox ====
La configuration des backups de Proxmox s'effectue dans le fichier ///etc/vzdump.conf// de l'hyperviseur. On indique une directive //script// suivie du chemin vers le hook script afin qu'il utilise le script spécifié :
# vzdump default settings
script: /root/scripts/hook_script.py
En spéficiant cette ligne, le fichier ///root/scripts/hook_script.py// sera désormais appelé à chaque production de snapshot qu'elle soit déclenchée manuellement ou automatiquement.
==== Rotation des snapshots ====
La rotation des snapshots se réalise à l'aide du module Python [[https://pypi.org/project/rotate-backups/|rotate-backups]].
La configuration de la rotation des snapshots s'effectue dans le fichier //config.json//. Ce fichier inclut les informations relatives aux VM et des informations essentielles pour le fonctionnement du hook_script associé à Proxmox. Voici un exemple :
{
"BACKUP_FOLDER":"/save_folder",
"ENCRYPTED_BACKUP_FOLDER":"/save_folder/chroot_folder/encrypted_backup_folder",
"DESTINATION_IP":"192.168.XXX.YYY",
"DESTINATION_FOLDER":"/save_folder/chroot_folder/encrypted_backup_folder",
"VMs":{
"101":
{
"Name": "pica01",
"Hypervisor": "Alice",
"Backup-Rota":
{
"Day" : 4,
"Week": 0,
"Month": 0
}
},
"102":
{
"Name": "nom_VM",
"Hypervisor": "Bob",
"Backup-Rota":
{
"Day" : 4,
"Week": 0,
"Month": 0
}
}
}
}
Sa structure est très simple :
{
"BACKUP_FOLDER": ,
"ENCRYPTED_BACKUP_FOLDER": ,
"DESTINATION_IP": ,
"DESTINATION_FOLDER": ,
"VMs":{
"":
{
"Name": "",
"Hypervisor": "",
"Backup-Rota":
{
"Day": ,
"Week": ,
"Month":
}
}
}
}
Les champs spécifiées sont utilisés par le hook_script afin de localiser les différents éléments nécessaires à son fonctionnement :
* : chemin du dossier dans lequel sont positionnées les backups enregistrées par Proxmox
* : chemin du dossier dans lequel le hook_script doit enregistrer les backups chiffrées
* : Adresse IP de la machine distante avec laquelle effectuer le rsync
* : chemin du dossier sur la machine distante dans lequel enregistrer les backups chiffrées transmises par le rsync
Pour chaque VM inclue dans VM sont définis les paramètres suivants :
* : doit correspondre à l'id de la VM telle que définie par Proxmox
* : nom de la VM sauvegardée qui sera indiqué dans le nom du fichier chiffré
* : nom de l'hyperviseur qui sera indiqué dans le nom du fichier chiffré
* : nombre de jours sur lesquels on veut garder les snapshots
* : nombre de semaines sur lesquelles on veut garder les snapshots (le plus récent de la semaine sera conservé)
* : nombre de mois sur lesquels on veut conserver les snapshots (le plus récent du mois sera conservé)
==== Externalisation ====
L'accès sécurisé aux snapshots chiffrés s'effectue à l'aide de l'utilisateur **snapshots**. Les clés ssh des personnes autorisées à se connecter avec cet utilisateur doivent être situées dans le fichier ///home/snasphots/.ssh/authorized_keys//.
===== Test du script =====
Le hook script peut être testé en déclenchant une sauvegarde manuelle à partir de l'interface de Proxmox.
{{:txs:infra-p18:capture_d_e_cran_2018-05-20_a_14.52.09.png?400|}}
{{:txs:infra-p18:capture_d_e_cran_2018-05-20_a_14.52.28.png?400|}}
===== Principes de fonctionnement =====
==== Introduction ====
Afin de garantir une exécution rapide du plan de reprise d'activité en cas de sinistre, il a été décidé de conserver les snapshots du jour à la fois en clair et chiffrés. Les snapshots présents en clair sont situés dans le dossier ///SAVE/dump//. Les snapshots chiffrés sont situés dans le dossier ///SAVE/dump/public_snapshots//. **Tout snapshot effectué plus tard que le jour même est donc conservé uniquement sous forme chiffré**. Les snapshots en clair sont des archives compressées au format .vma.gz ou .lzo. Les snapshots chiffrés sont des archives au format tar.
==== Appel du script par Proxmox ====
Un snapshot comporte plusieurs phases :
* job-start
* backup-start
* pre-stop
* pre-restart
* post-restart
* backup-end
* log-end
* job-end
Le nom de la phase est passé en argument par Proxmox lors de l'appel du script. Nous utilisons la phase "backend-end" : à ce moment là, le snapshot a complètement été écrit sur le disque, dans le dossier ///SAVE/dump/// de l'hyperviseur. Chaque phase comporte différentes variables d'environnement que l'on peut récupérer dans le script Python.
Le script se sert uniquement de la variable //TARFILE// qui comporte le nom du fichier du snapshot.
==== Découpage et chiffrement des snapshots ====
Un découpage de l'archive de la snapshot est effectué car il est impossible de faire tenir l'ensemble du fichier en mémoire RAM. Pour ce faire, un générateur Python est utilisé et permet d'obtenir des morceaux de tailles fixes du snapshot, dans notre cas 1 Go.
Le chiffrement des snapshots utilise le module [[https://pythonhosted.org/python-gnupg/|python-gnupg]].
Chaque morceau du snapshot est chiffré, puis écrit dans un dossier temporaire. À ce stade, le dossier temporaire est composé d'une multitude de fichiers ayant pour nom "part.X" où X représente l'indice du morceau (de 1 à n). Ce dossier est ensuite compressé en une archive au format tar. L'archive est alors prête à être synchronisée sur l'autre hyperviseur et externalisée.
==== Synchronisation et mise en place de la solution d'externalisation ====
La synchronisation sur l'autre hyperviseur utilise l'outil rsync via un appel à la commande bash associée. À chaque appel du hook script, l'ensemble du dossier ///SAVE/dump// est synchronisé sur l'autre hyperviseur, donc aussi bien les snapshots en clair que les snapshots chiffrés. La commande rsync est appelé grâce au module Python //sh// qui permet notamment de gérer les erreurs au sein d'exceptions Python. **En cas d'une erreur renvoyée par rsync, celle-ci figurera dans la partie logging de l'interface de Proxmox**.
{{:txs:infra-p18:capture_d_e_cran_2018-05-20_a_14.59.02.png?400|}}
La solution d'externalisation mise en place utilise un chroot du dossier ///SAVE/dump/public_snapshots//. Un chroot permet de définir le dossier //public_snapshots// comme la racine du système de fichiers accessible par l'utilisateur. Le répertoire //public_snapshots// est uniquement accessible avec les droits de lecture et d'exécution par l'utilisateur snapshots (chmod 775 avec root défini comme propriétaire).
L'utilisateur snapshots est créé avec la commande ''adduser''. Un répertoire /home/snapshots est également créé et un mot de passe est défini par sécurité, mais il ne sera pas utilisé car la connexion ssh se fera uniquement par clé.
L'ensemble des clés autorisées à se connecter avec cet utilisateur est défini au sein du dossier /home/snapshots/.ssh dans un fichier ''authorized_keys''.
L'utilisateur snapshots a ensuite été rajouté au sein du groupe chrootjail.
Pour pouvoir ensuite "chrooter" tous les utilisateurs de ce groupe au sein d'un dossier ///SAVE/dump/public_snapshots//, et interdire la connexion par mot de passe, il faut rajouter la configuration suivante au fichier ///etc/ssh/sshd_config// :
Match group chrootjail
chrootDirectory /SAVE/dump/public_snapshots
PasswordAuthentication no
Une fois ces lignes de configuration ajoutées, et après redémarrage du serveur ssh ''%%service ssh restart%%'' l'utilisateur sera donc directement "chrooté" au sein du dossier ///SAVE/dump/public_snapshots// lors d'une connexion ssh réussie. Il verra ce dossier comme la racine du système de fichiers.
À ce stade, néanmoins, l'utilisateur n'a pas accès à un shell. Il pourra se connecter en ssh, mais sera directement déconnecté. Il faut dans un premier temps lui donner accès à /bin/bash, ce qui lui donnera accès aux commandes intégrées à bash telles que //cd// ou //echo//. Il faut également lui donner accès aux commandes //rsync// ou //ls// qui sont nécessaires pour permettre l'externalisation. Pour automatiser la mise à disposition de nouvelles commandes bash, le script suivant est utilisé :
#!/bin/bash
# This script can be used to create simple chroot environment
# Written by LinuxCareer.com
# (c) 2013 LinuxCareer under GNU GPL v3.0+
#!/bin/bash
CHROOT='/SAVE/dump/public_snapshots'
mkdir $CHROOT
for i in $( ldd $* | grep -v dynamic | cut -d " " -f 3 | sed 's/://' | sort | uniq )
do
cp --parents $i $CHROOT
done
# ARCH amd64
if [ -f /lib64/ld-linux-x86-64.so.2 ]; then
cp --parents /lib64/ld-linux-x86-64.so.2 /$CHROOT
fi
# ARCH i386
if [ -f /lib/ld-linux.so.2 ]; then
cp --parents /lib/ld-linux.so.2 /$CHROOT
fi
echo "Chroot jail is ready. To access it execute: chroot $CHROOT"
Source : https://linuxconfig.org/how-to-automatically-chroot-jail-selected-ssh-user-logins
Le script se configure en spécifiant le dossier racine du chroot dans la variable ''%%CHROOT%%''. L'ajout de nouvelles commandes du shell qui seront autorisées à l'utilisateur "chrooté" se fait comme suit :
./chroot.sh /bin/{ls,cat,echo,rm,bash} /usr/bin/vi
Dans l'exemple ci-dessus, les commande //ls//, //cat//, //echo//, //rm//, //bash// et //vi// seront donc ajoutées aux commandes shell autorisées à l'utilisateur.
Le script effectue les actions suivantes :
* Création du dossier qui comporte le chroot, si le dossier existe déjà il n'est pas créé.
* Copie des bibliothèques partagées (obtenues avec la commande //ldd//) dans un dossier //lib// ou //lib64// présents dans le dossier comportant le chroot
* Copie de l'exécutable de la commande dans le dossier //bin// (ou un sous-dossier comme //usr/bin// selon la commande) du chroot
Après l'ajout de commandes, le dossier du chroot contient les dossiers suivants :
bin/
lib/
lib64/
usr/bin
L'externalisation des snapshots est maintenant parfaitement fonctionnelle.