floppy disk and datacenter

On l'entend souvent : Pour protéger vos données vous devez les sauvegarder. En pratique on néglige presque tous ce conseil avisé jusqu'au jour où l'inévitable arrive et où vous perdez en un instant le moral et une partie de votre vie.

Un rm -rf depuis un compte administrateur, un disque dur défaillant ou ayant subi une chute, une clé USB perdue ou détruite, du matériel volé, des CD-ROM devenus illisibles au bout de quelques années, une intrusion sur un système etc.

Puis on s'oriente vers des services de récupération (Seagate, Chronodisk, Ontrack) et on se rend compte des prix exorbitants pratiqués sans garantie de réussite du processus; il faut compter entre 150 et 800€ selon la gravité de la panne. Ce jour-là on se mord les doigts de ne pas avoir pris quelques heures pour sauvegarder ses données.

En informatique, sauvegarder est primordial. L'excuse du "j'ai perdu tous mes fichiers" ne tient pas ! Ce n'est vraiment pas de chance si ça arrive avec un système de sauvegarde, mais sans ce dernier c'est insérer des propos déplacés ici.
De plus, sauvegarder c'est bien, mais chiffrer la sauvegarde et la rendre illisible en cas de vol, c'est mieux ! Sauvegarder sur plusieurs supports, c'est encore mieux !
Évitez le Cloud (commits Dropbox), si vous ne leur rapportez rien, alors vos données n'ont pas de valeur et ils s'en foutent ! Ça parait êxtrême ou aller de soi ? Pensons au nombre de gens et d'entreprises qui faisaient confiance à MegaUpload pour stocker leurs fichiers légaux !

  • Les utilisateurs qui stockaient des fichiers légaux sur MegaUpload n'ont qu'à s'en prendre à eux-mêmes.

    MegaUpload a clairement informé les utilisateurs de cette spécificité à travers la Foire Aux Questions (FAQ) et ses conditions d’utilisation. Les internautes « n’ont aucun droit de propriété sur aucun des fichiers stockés sur les serveurs de MegaUpload, ils assument le risque de perte ou d’indisponibilité de leurs données et que MegaUpload peut mettre un terme aux activités du site sans préavis ».

  • Ex-utilisateurs de MegaUpload en Europe, vos fichiers sont perdus.

    LeaseWeb a effacé tous les serveurs de MegaUpolad. [...] Ces fichiers végétaient sur les serveurs de l’hébergeur depuis au moins le 19 janvier 2012, date de fermeture de la célèbre plateforme. Mais tout cet espace occupé par des pétabytes de fichiers représentait aussi un manque à gagner pour l’hébergeur qui ne l’affectait pas à de nouveaux clients.

Le Cloud gratuit est toxique pour la vie privée et pour les données des utilisateurs. Fuyez-le, décentralisez vos activités.
=> On n'est jamais mieux servi que par soi-même.

Les scripts proposés ici (et sur Github : auto_backups) permettent une sauvegarde automatique décrémentale sur système de fichiers chiffré LUKS (Linux Unified Key Setup), vers un disque dur externe. La durée de la première sauvegarde dépend évidemment de la quantité et du type de fichiers concernés. À titre d'exemple, je dispose de 30Go de photos, documents, codes; le tout est sauvegardé presque tous les jours en moins de 30 secondes.

À lire : La moitié des groupes de presse français viendrait de perdre toute trace de leurs abonnés.

commitstrip backup

Y a-t-il une backup dans l'avion ?

Sommaire

LUKS : Container chiffré et partition cachée

Créer, monter, démonter

Outils:

  • gparted : La boîte à outils de référence (ne gère pas le système de fichiers LUKS).
  • gnome-disk-utility : cf. tuto.
  • partitionmanager : Gère LUKS à partir de la version 2.

La procédure décrite par la suite est manuelle c.-à-d. avec GParted et les outils en ligne de commande.

Il faut tout d'abord créer une partition ext4 de taille suffisante (libérer de l'espace par redimensionnement d'une partition déjà existante par exemple). Peu importe le système de fichiers choisi dans cette phase car il sera écrasé par le système de fichiers LUKS.

GParted utilisation

Création d'une nouvelle partition sur GParted.

Identifier la partition d'accueil. Pour cela il existe des tas d'outils:

$ lsblk -f
NAME   FSTYPE LABEL UUID MOUNTPOINT
sda
├─sda1                   /boot/efi
├─sda2                   /pedoporn
├─sda3                   /nsa_backdoor
├─sda4                   /media/windows_backdoor_for_everyone
├─sda5                   /media/DATA
├─sda6                   /google_backdoor
├─sda7                   [SWAP]
├─sda8                   /home
├─sda9                   /
└─sda10                  /docker_backdoor
sdb
├─sdb1
└─sdb2

# ou:
$ blkid
/dev/sdb2: UUID="d9ad7a7b-24c6-4995-9c53-4afa352a9416" TYPE="ext4" PARTUUID="69a6bda8-e1a0-4dc5-8452-1eaf50d7fd77"

# ou tout simplement:
$ ls -la /dev/disk/by-uuid/
lrwxrwxrwx 1 root root  10 sept.  1 20:41 d9ad7a7b-24c6-4995-9c53-4afa352a9416 -> ../../sdb2

Chez moi la partition est la seconde présente sur le disque externe sdb; soit : /dev/sdb2.

Installer le paquet cryptsetup si ce n'est pas déjà fait :

$ sudo apt-get install cryptsetup

Créer la partition LUKS sur cette partition (Attention, ceci écrasera tout son contenu !):

$ sudo cryptsetup luksFormat -c aes -h sha256 /dev/sdb2

Les options de chiffrement ont une incidence sur les performances de lecture/écriture.

Ici cela importe peu car il s'agit d'un disque externe, mais c'est un point qu'il convient de prendre en compte dans le cas d'un chiffrement généralisé d'un système d'exploitation. Renseignez-vous sur les algos (AES, AES-CBC, AES-XTS, modes d'opération cryptographiques) !

Faites des tests :

$ cryptsetup benchmark
# Tests approximatifs en utilisant uniquement la mémoire (pas de stockage E/S).
PBKDF2-sha1       936228 iterations per second
PBKDF2-sha256     686240 iterations per second
PBKDF2-sha512     464794 iterations per second
PBKDF2-ripemd160  652099 iterations per second
PBKDF2-whirlpool  222911 iterations per second
#  Algorithm | Key |  Encryption |  Decryption
    aes-cbc   128b   577,2 MiB/s  2092,5 MiB/s
serpent-cbc   128b    67,2 MiB/s   273,1 MiB/s
twofish-cbc   128b   175,3 MiB/s   335,3 MiB/s
    aes-cbc   256b   424,3 MiB/s  1565,3 MiB/s
serpent-cbc   256b    83,5 MiB/s   284,7 MiB/s
twofish-cbc   256b   175,9 MiB/s   333,8 MiB/s
    aes-xts   256b  1732,8 MiB/s  1732,0 MiB/s
serpent-xts   256b   292,1 MiB/s   278,9 MiB/s
twofish-xts   256b   326,8 MiB/s   329,8 MiB/s
    aes-xts   512b  1326,8 MiB/s  1334,7 MiB/s
serpent-xts   512b   290,8 MiB/s   279,7 MiB/s
twofish-xts   512b   328,4 MiB/s   330,7 MiB/s

Ouvrir la partition LUKS qui jouera le rôle d'un container (nommé cryptdisk dans la commande suivante), abritant la partition contenant réellement les fichiers :

$ sudo cryptsetup luksOpen /dev/sdb2 cryptdisk

Création du système de fichier ext4 dans la partition chiffrée :

$ sudo mkfs.ext4 /dev/mapper/cryptdisk

C'est quoi ext4 ?

Il s'agit d'un système de fichiers performant et extrêmement résistant aux problèmes de fragmentation rencontrés en particulier avec le FAT/NTFS de Microsoft. Ces particularités sont expliquées entre autres par:

  • Une pré-allocation des fichiers sur le disque avec garantie de la contiguïté de l'espace réservé.
  • Une allocation différée de l'espace, basée sur une mise en cache précédant un vidage de gros blocs de données, permettant de meilleures performances et une réduction de la fragmentation du fichier final.
  • Une allocation multi-blocs évitant des requêtes successives lors de l'agrandissement d'un fichier et garantissant là encore, la contiguïté de l'espace demandé.

TL;DR : NTFS c'est la spatio-merde; il n'y a pas de fragmentation des fichiers sous GNU/Linux.

Création du point de montage :

$ sudo mkdir /media/cryptdisk

Montage :

$ sudo mount /dev/mapper/cryptdisk /media/cryptdisk

Attribution des droits :
Lors de son premier montage, une partition appartient au compte root. Vous devez vous l'approprier en changeant les droits sur la racine. (Cela explique la remarque courante : "gna gna gna Linux c'est dla merde on peut pas mettre de fichiers sur son disque externe".)

$ sudo chown -R cazeneuve:cazeneuve

cazeneuve est votre nom d'utilisateur.

Note de la rédaction

Chiffrer ses fichiers avec un tel nom est assez... contradictoire. Mais si vous êtes ici c'est que vous avez des choses à cacher non ? Ce tuto aidera sans aucun doute certaines personnes à cacher les casseroles qu'ils ont au cul.
Cordialement, bisous <3.

Démontage manuel et fermeture du volume chiffré :

$ sudo umount /media/cryptdisk
$ sudo cryptsetup luksClose cryptdisk

Montage automatique

Après déverrouillage, un nouveau point de montage est disponible sur le système : la partition cachée dans le container LUKS.

$ ls -la /dev/disk/by-uuid/
lrwxrwxrwx 1 root root  10 sept.  1 21:16 c968bc41-a980-4900-9490-00b2a5ed1d4e -> ../../sdb2
lrwxrwxrwx 1 root root  10 sept.  1 21:16 86cee552-66b9-4ab7-92f5-f401ee37de01 -> ../../dm-0

$ blkid
/dev/sdb2: UUID="c968bc41-a980-4900-9490-00b2a5ed1d4e" TYPE="crypto_LUKS" PARTUUID="917abaf8-7ad9-4ca8-b046-36116322c557"
/dev/mapper/luks-c968bc41-a980-4900-9490-00b2a5ed1d4e: UUID="86cee552-66b9-4ab7-92f5-f401ee37de01" TYPE="ext4"

Repérer son UUID (Universal Unique Identifier):
Ici 86cee552-66b9-4ab7-92f5-f401ee37de01 est l'UUID de la partition ext4, cachée dans un container LUKS dont l'UUID est c968bc41-a980-4900-9490-00b2a5ed1d4e.

Définir les options de montage en éditant le fichier /etc/fstab :

# <file system>                            <mount point>     <type>  <options>                           <dump>  <pass>
UUID=86cee552-66b9-4ab7-92f5-f401ee37de01  /media/cryptdisk  ext4    defaults,noatime,nodiratime,noauto  0       2

Le paramètre noauto est là pour empêcher une tentative de montage qui ralentirait le démarrage (c'est un disque externe !).


Au cas où il s'agirait d'un disque fixe, et qu'il faudrait le monter au démarrage, il faut savoir que la configuration des paramètres du volume chiffré se fait dans le fichier /etc/crypttab. Dans ce fichier, la colonne <key file> permet de spécifier un fichier capable de déverrouiller le volume chiffré sans saisie du mot de passe.

Cas d'utilisation : Le système se déverrouille uniquement si un périphérique contenant la clé est branché. Autrement la NSA va se faire voir...

Exemple :

# <target name>  <source device>                            <key file>  <options>
cryptdisk        UUID=c968bc41-a980-4900-9490-00b2a5ed1d4e  none        luks,timeout=10

À la fin de cette partie vous devriez avoir un système capable de monter la partition cachée de façon autonome. Il est bon de connaître l'existence des commandes de gestion vues jusque-là, mais en général les environnements de bureau s'en chargent à votre place.

KDE automount LUKS partition

Exemple sur KDE (existe-t-il d'autres bureaux qui valent le coup ? :o)

Rsync : Sauvegarde

Pour faire des sauvegardes, vous pouvez utiliser un système propriétaire, payant, cher, très cher, buggé, inefficace, ou alors vous utilisez rsync. rsync permet de faire entre autres, de la sauvegarde décrémentale. rsync sert notamment à réaliser des sauvegardes à distance en se reposant sur une excellente optimisation des transferts.

Une sauvegarde incrémentielle consiste à réaliser une sauvegarde complète le jour J. Le jour J+1, la sauvegarde incrémentielle est réalisée par référence au jour J. Le jour J+2, la sauvegarde incrémentielle est réalisée par référence au jour J+1. Et ainsi de suite.
Une sauvegarde décrémentale consiste à obtenir une sauvegarde complète comme sauvegarde la plus récente et des sauvegardes différentielles pour les plus anciennes.

Merci Wikipédia.

Avec la sauvegarde décrémentale, les jours précédents sont des diffs du jour courant. La restauration du jour courant est aisée, et on peut supprimer les vieilles sauvegardes sans devoir faire un point de restauration complet comme avec la sauvegarde incrémentielle (faire un nouveau jour J).

Vous l'avez compris, il est inutile de sauvegarder la totalité des fichiers chaque jour; étant donné qu'une grande partie des fichiers ne change que très rarement, on ne conserve que les données modifiées.

Architecture

À la racine du répertoire de sauvegarde on trouve :

  • Le dossier de la dernière sauvegarde,
  • Les dossiers des jours précédents,
  • Les logs conservant les modifications.

backup flowchart

Logigramme décrivant les actions réalisées lors du processus de sauvegarde décrémentale. Oui, c'est fait avec Inkscape et ça m'a pris 20 minutes; et non, pour une fois le logiciel n'a pas planté !

Rsync

Voici la commande utilisée :

rsync --stats -av --force --ignore-errors --delete --delete-excluded \
    --exclude-from=exclude_file \
    --include-from=include_file \
    --backup --backup-dir="$(date +%Y-%m-%d)/" \
    "source/dir/" "current/" \
    &> log_file.log

Description des paramètres :

-a, --archive               archive mode; equals -rlptgoD (no -H,-A,-X)
-r, --recursive             recurse into directories
-l, --links                 copy symlinks as symlinks
-p, --perms                 preserve permissions
-t, --times                 preserve modification times
-g, --group                 preserve group
    --devices               preserve device files (super-user only)
    --specials              preserve special files
-D                          same as --devices --specials
-o, --owner                 preserve owner (super-user only)

-v, --verbose               increase verbosity
--stats                     give some file-transfer stats

--delete
    supprime les fichiers qui sont dans le répertoire de destination et pas dans le répertoire source
--ignore-errors
    delete even if there are I/O errors
--force
    force la suppression de répertoires même non-vides

--backup
    crée des sauvegardes des fichiers avant de les écraser en les écrivant sur eux-mêmes
--backup-dir=`date +%Y-%m-%d`
    crée un répertoire de backup daté pour ces sauvegardes

--exclude-from=FILE
    This option is related to the --exclude option, but it specifies a FILE that contains exclude patterns (one per line).
    Blank lines in the file and lines starting with ';' or '#' are ignored.
--include-from=FILE
    This option is related to the --include option, but it specifies a FILE that contains include patterns (one per line).
    Blank lines in the file and lines starting with ';' or '#' are ignored.

    Note also that excluding a directory prevents it not only from being copied but also from being traversed, so this effectively excludes everything below it. See this rsync filter primer for more information.
    If you exclude a directory, this excludes everything below it.
    If you include a directory, this doesn't automatically include its contents. In recent versions, --include='directory/***' will do that.
    * : any substring of a single directory component (i.e. never matches /);
    ** : matches any path substring.


    Exemple de syntaxe:

        + Users
        + Users/Cazeneuve
        + Users/Cazeneuve/Desktop
        + Users/Cazeneuve/Desktop/**
        - *

        # ou plus rapide:
        + Users
        + Users/Cazeneuve
        + Users/Cazeneuve/Desktop/***
        - *

Script final :

#!/bin/bash
########################################
# Script for incremental rsync backups #
# Return 1 on errors, 0 otherwise      #
########################################

# Names of saved directories
BACKUP_NAME_WINDOWS="windows"
BACKUP_NAME_DATA="DATA"
BACKUP_NAME_DEBIAN="home"

# Paths of directories to save
SRC_WINDOWS="/media/windows/"
SRC_DEBIAN="/home/Lex/"
SRC_DATA="/media/DATA/"

# PS : Include patterns have to be specified
# as argument of backup_process function.

# Mount point of the partition/volume where the backup will be made
MOUNT_POINT="/media/cryptdisk"
# Root directory of backup stuff
BACKUP_ROOT="backups"

########################################
# From here on out, you probably don't #
#   want to change anything unless you #
#   know what you're doing.            #
########################################

CURRENT_DATE=$(date +%Y-%m-%d)
# Directory where the script and include/exclude files are stored
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
EXIT_VALUE=0

check_directories()
{
    # Check the existence of the directory where the last backup will be put
    # Param: Directory name

    #echo "Checking ${MOUNT_POINT}/${BACKUP_ROOT}/$1_current/ ..."

    if [ ! -d  "${MOUNT_POINT}/${BACKUP_ROOT}/$1_current/" ]; then
        echo -n "Init backup dir..."
        mkdir -p "${MOUNT_POINT}/${BACKUP_ROOT}/$1_current/"

        # get the exit code from the last command executed
        if [ $? -ne 0 ]; then
            echo -e " [${RED}FAIL${NC}]"
            # Stop the script
            exit 1
        else
            # 0 on success
            echo -e " [ ${GREEN}OK${NC} ]"
            return 0
        fi
    fi
}

backup_process()
{
    # Check directory & do the backup process
    # Param 1: Path of directory to save
    # Param 2: Name used for the destination
    # Param 3 (optional): File with patterns that will filter the source files

    #check_directories $BACKUP_NAME_WINDOWS
    check_directories $2

    echo -n "Backup $2 in progress..."

    LOG_FILE="${MOUNT_POINT}/${BACKUP_ROOT}/log_$2_$(date +%Y-%m-%d_%Hh-%Mm-%Ss).log"

    rsync --stats -av --force --ignore-errors --delete --delete-excluded \
        --exclude-from="${SCRIPT_DIR}/exclude_all" \
        --include-from=$3 \
        --backup --backup-dir="${MOUNT_POINT}/${BACKUP_ROOT}/$2_${CURRENT_DATE}/" \
        $1 "${MOUNT_POINT}/${BACKUP_ROOT}/$2_current/" \
        &> ${LOG_FILE}

    # get the exit code from the last command executed
    if [ $? -ne 0 ]; then
        echo -e " cf log [${RED}FAIL${NC}]"
        # Update exit value
        EXIT_VALUE=1
        return 1
    else
        # 0 on success
        echo -e " [ ${GREEN}OK${NC} ]"
        return 0
    fi
}

#########################################

if df | grep -q $MOUNT_POINT; then

    # Check include files here as third parameter !
    backup_process $SRC_WINDOWS $BACKUP_NAME_WINDOWS "${SCRIPT_DIR}/include_windows"
    backup_process $SRC_DEBIAN $BACKUP_NAME_DEBIAN
    backup_process $SRC_DATA $BACKUP_NAME_DATA "${SCRIPT_DIR}/include_DATA"
else
    echo -e "ERROR: Can't find mount point ! [${RED}FAIL${NC}]"
    EXIT_VALUE=1
fi

# Uncomment these lines if the script is not run through systemd (in user env)
#if [ $EXIT_VALUE -ne 0 ]; then
#    kdialog --passivepopup "Some errors occured !"
#else
#    kdialog --passivepopup "Backup is done."
#fi
exit $EXIT_VALUE

Pour adapter le script il suffit de renseigner les paramètres BACKUP_NAME_* qui correspondent aux noms des dossiers sauvegardés dans le dossier principal de sauvegarde BACKUP_ROOT.

Un paramètre SRC_* fait référence à chaque BACKUP_NAME_*. Il s'agit du répertoire contenant les fichiers à sauvegarder.

Les différents dossiers sont traités vers la fin du script par autant d'appels à la fonction backup_process.

Exemple:

backup_process $SRC_DATA $BACKUP_NAME_DATA "${SCRIPT_DIR}/include_DATA"

Le 3ième paramètre, optionel, fait référence à un fichier listant les dossiers qui doivent être pris en compte dans le dossier SRC_*. La syntaxe de ce fichier est expliquée au début du chapitre avec les paramètres de rsync.

Systemd : Automatisation

Concrètement on veut que le système lance le script de sauvegarde après qu'on ait déverrouillé le container.

Pour lancer un script au montage d'une partition (et non au branchement d'un périphérique) il faut utiliser systemd en créant un service dédié (cf. tuto précédent) ! N'allez pas vous perdre avec udev qui reconnait et monte les périphériques mais qui est incapable de lancer des actions en fonction de la présence/absence d'une partition spécifique.

Avec udev, le script essaiera de se lancer au branchement du périphérique; soit avant qu'on ait pu avoir le temps de déverrouiller le container.

Copier le code de ce service systemd dans un fichier auto-backup-cryptdisk.service placé dans /etc/systemd/system:

# List mount targets: systemctl list-units -t mount
[Unit]
# Contains information about the service.
Description=Auto backup of the system to a LUKS encrypted partition.
Requires=media-cryptdisk.mount
# Launch after mounting the partition
After=media-cryptdisk.mount

[Service]
# Action of the service itself
ExecStart=/home/MY_USERNAME/backups/script.sh

[Install]
WantedBy=media-cryptdisk.mount

Activer le service :

$ systemctl enable auto-backup-cryptdisk.service
Created symlink from /etc/systemd/system/media-cryptdisk.mount.wants/auto-backup-cryptdisk.service to /etc/systemd/system/auto-backup-cryptdisk.service.

Recharger le démon systemd :

$ systemctl --system daemon-reload

Le script se lance dès le déverrouillage du container. On peut visualiser la sortie de ce dernier via la commande suivante :

$ systemctl status auto-backup-cryptdisk.service
● auto-backup-cryptdisk.service - Auto backup of the system to a LUKS encrypted partition.
    Loaded: loaded (/etc/systemd/system/auto-backup-cryptdisk.service; enabled)
    Active: inactive (dead) since jeu. 2016-09-01 15:38:51 CEST; 2s ago
    Process: 7140 ExecStart=/home/Lex/Desktop/backups/script.sh (code=exited, status=0/SUCCESS)
    Main PID: 7140 (code=exited, status=0/SUCCESS)

sept. 01 15:38:17 kali script.sh[7140]: Backup windows in progress... [ OK ]
sept. 01 15:38:25 kali script.sh[7140]: Backup home in progress... [ OK ]
sept. 01 15:38:38 kali script.sh[7140]: Backup DATA in progress... [ OK ]

Sources