# Borgmatic

[Borgmatic](https://torsion.org/borgmatic/) est un *wrapper* autour de [Borg](/books/administration-syst%C3%A8mes/page/borg) qui en simplifie infiniment l’utilisation.

## Installation

Il nous faut d’abord Borg (utilisez la version des [backports Debian](https://backports.debian.org/Instructions/) si vous êtes encore en *stretch*) :

```bash
apt install borgbackup
```

D’habitude, je préfère utiliser les paquets Debian, mais la version pip de Borgmatic apporte une option en plus que j’apprécie particulièrement.

```bash
apt install python3-pip
pip3 install borgmatic
```

## Configuration

C’est là que Borgmatic est pratique : il permet une configuration très simple de Borg.

Générez un fichier de configuration :
```bash
generate-borgmatic-config
```

Cela créera le fichier `/etc/borgmatic/config.yaml`. Si vous souhaitez que la configuration soit dans un autre fichier :
```bash
generate-borgmatic-config -d /etc/borgmatic/autre_config.yaml
```

La configuration générée ([exemple](https://torsion.org/borgmatic/docs/reference/configuration/)) est très simple à comprendre et auto-documentée, je ne vais l’expliquer, je vais me contenter d’en mettre certains points en valeur

### Le dépôt

On le verra plus bas, j’utilise un serveur distant pour faire les sauvegardes. Donc :
```yaml
location:
    repositories:
        - borg@server:/var/lib/borg/depot/
```

### La *passphrase*

Choisissez quelque chose de costaud et sauvegardez-là [quelque part](/books/administration-syst%C3%A8mes/page/bitwarden_rs) !

```yaml
storage:
    encryption_passphrase: "foo-bar-baz"
```

### Utilisation d’une clé SSH particulière

Je crée plus bas une clé SSH dédiée pour Borg pour faire les sauvegardes sur le serveur distant. Il faut donc que j’indique à Borgmatic que je souhaite utiliser cette clé.

```yaml
storage:
    ssh_command: ssh -i /root/.ssh/id_borgmatic
```

### Les hooks

Situés à la fin du fichier de configuration, il s’agit d’actions qui seront effectuées avant et après la sauvegarde, ou en cas de problème lors de l’exécution.

Personnellement, j’aime bien avoir la liste de mes sauvegardes après qu’une sauvegarde soit effectuée. Je vais donc écrire :
```yaml
hooks:
    after_backup:
        - /usr/local/bin/borgmatic list
```

Comme il est conseillé d’exporter la clé du dépôt borg, je mets aussi ceci dans les `hooks` :
```yaml
    before_backup:
        - borg key export borg@server:/var/lib/borg/depot/ /etc/ssl/private/borg.key
```

### Rétention et vérification du dépôt et des archives

Je fais ça sur le serveur, j’y reviendrai plus loin.

### Cron

On crée un petit cron (avec l’utilisateur `root`) pour sauvegarder régulièrement l’ordinateur :
```cron
35 0 * * * borgmatic create -c /etc/borgmatic/mon_pc.yaml --stats 2>&1
```

Si ce n’est pas un serveur allumé 24h/24, il est préférable de mettre ça dans `/etc/anacrontab` :
```cron
@daily  15      backup borgmatic create -c /etc/borgmatic/mon_pc.yaml --stats 2>&1
```

Cela lancera le backup tous les jours, 15 minutes après le démarrage du pc. Ou plus tard.

Attention, sur Debian, les tâches anacron ne sont lancées que si vous êtes sur secteur ! Pour changer ça, reportez-vous au fichier `/usr/share/doc/anacron/README.Debian`.

## Préparation du serveur du dépôt distant

Je préfère faire mes sauvegardes sur un disque distant : si mon disque lâche, j’aurai toujours mes sauvegardes.

Pour ce faire, je crée une clé dédiée sur l’ordinateur à sauvegarder, sans mot de passe vu que borgmatic va tourner automatiquement :
```bash
ssh-keygen -o -a 100 -t ed25519 -f /root/.ssh/id_borgmatic -N ''
```

**Sur le serveur de sauvegarde**, j’installe Borg et Borgmatic comme précédemment puis je crée un utilisateur `borg` :
```bash
adduser --system --home /var/lib/borg --shell /bin/bash --disabled-password borg
mkdir /var/lib/borg/.ssh
chmod 700 /var/lib/borg/.ssh
touch /var/lib/borg/.ssh/authorized_keys
chmod 600 /var/lib/borg/.ssh/authorized_keys
chown -R borg: /var/lib/borg/.ssh
```

Et je mets la clé publique créée précédemment dans `/var/lib/borg/.ssh/authorized_keys`, avec quelques restrictions :
```bash
command="/usr/bin/borg --umask=077 --info serve --append-only --restrict-to-repository /var/lib/borg/becky2/",restrict ssh-ed25519 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX root@mon_pc
```

On génère une configuration :
```bash
generate-borgmatic-config -d /etc/borgmatic/mon_pc.yaml
```

Et c’est dans cette configuration qu’on va configurer les durées de rétention et les vérifications du dépôt et des archives.

### Rétention

C’est très simple. Pour garder un backup par mois sur les 6 derniers mois, un par semaine sur les 8 dernières semaines et un par jour sur les 14 derniers jours, il suffit de :

```yaml
retention:
    keep_daily: 14
    keep_weekly: 8
    keep_monthly: 6
```

Comme Borg déduplique comme un monstre, cela ne prendra pas énormément de place (sauf si vous sauvegardez des trucs qui changent tout le temps)

### Vérification du dépôt et des archives

Cela permet de s’assurer que votre dépôt et vos archives sont utilisables et non corrompus. Je me contente de décommenter la configuration proposée :
```yaml
consistency:
   checks:
       - repository
       - archives
   check_last: 3
```

J’ai laissé `check_last` à 3 car vérifier toutes les archives peut être fort long. Donc une vérification des 3 dernières devrait faire l’affaire, surtout si on vérifie quotidiennement.

### Dépôt

Attention, comme on est là sur le serveur distant, il faut lui donner un dossier local !

```yaml
location:
    repositories:
        - /var/lib/borg/depot/
```

### Script de suppression d’anciennes sauvegardes / vérification des archives

Il y a des éléments dans ce script qui prendront tout leur sens plus tard.

**NOTA BENE** : ce script est tout à fait adaptable à un usage à Borg sans Borgmatic.

On prépare le terrain :
```bash
apt install libcpanel-json-xs-perl
mkdir -P /opt/borgmatic-stats/tmp/ /opt/borgmatic-stats/json/
cd /opt/borgmatic-stats/
wget https://framagit.org/snippets/3716/raw -O verify-archives.pl
chmod 700 -R /opt/borgmatic-stats/
chown borg: -R /opt/borgmatic-stats/
```

Puis on met ceci dans `/opt/borgmatic_prune_and_check.sh` :
```bash
#!/bin/bash
cat <<EOF
==============================================
== mon_pc
==============================================
EOF

/usr/local/bin/borgmatic list -c /etc/borgmatic/mon_pc.yaml --json > /opt/borgmatic-stats/tmp/mon_pc.json.tmp
CONTINUE=0
if [[ -e /opt/borgmatic-stats/json/mon_pc.json ]]
then
    echo "Checking repository consistency."
    CONTINUE=$(/opt/borgmatic-stats/verify-archives.pl --old /opt/borgmatic-stats/json/mon_pc.json --new /opt/borgmatic-stats/tmp/mon_pc.json.tmp)
    echo "Repository consistency checked."
else
    CONTINUE=1
fi

if [[ $CONTINUE == '1' ]]
then
    ## Check
    /usr/local/bin/borgmatic check -c /etc/borgmatic/mon_pc.yaml 2>&1 && \
    echo "Repository checked." && \
    ## Allow pruning
    borg config /var/lib/borg/depot/ append_only 0 && \
    ## Prune
    /usr/local/bin/borgmatic prune -c /etc/borgmatic/mon_pc.yaml --stats 2>&1 && \
    echo "Repository pruned."
    ## List
    echo "Borg archives of mon_pc:"
    /usr/local/bin/borgmatic list -c /etc/borgmatic/mon_pc.yaml 2>&1

    /usr/local/bin/borgmatic list -c /etc/borgmatic/mon_pc.yaml --json > /opt/borgmatic-stats/json/mon_pc.json

    ## Disallow pruning
    borg config /var/lib/borg/depot/ append_only 1

    echo ''
else
    cat <<EOF

******************************************
* ALERT ON mon_pc! *
******************************************
All of the old archives can’t be retrieved from the repository (/var/lib/borg/depot/)!

Someone may have deleted an archive from mon_pc.

Pruning has been aborted. Please manually review the repository.

$CONTINUE
EOF
fi
```

On n’oublie pas de le rendre exécutable :
```bash
chmod +x /opt/borgmatic_prune_and_check.sh
```

### Cron

Attention ! Il faut éditer la *crontab* de l’utilisateur `borg` :
```bash
crontab -e -u borg
```

Et son contenu :
```cron
15 3 * * * /opt/borgmatic_prune_and_check.sh
```

## Initialisation du dépôt de sauvegarde

**Sur l’ordinateur à sauvegarder** :
```bash
borgmatic init -c /etc/borgmatic/mon_pc.yaml --append-only -e repokey
```

Le dépôt est initialisé en **append-only** (mais de toute façon, on le force dans le `.ssh/authorized_keys` du serveur distant) et avec un chiffrement par mot de passe mais avec la clé dans le dossier du dépôt distant.

## Lancement d’une sauvegarde

**Sur l’ordinateur à sauvegarder** :
```bash
borgmatic create -c /etc/borgmatic/mon_pc.yaml --stats
```

Le `--stats` est l’option que j’affectionne et dont je parlais au début : cela affiche des statistiques sur la sauvegarde qui a été faite : sa taille, sa taille compressée, sa taille dédupliquée, le temps que ça a pris…

## Afficher la liste des sauvegardes

```bash
borgmatic list -c /etc/borgmatic/mon_pc.yaml 
```

## Restauration de sauvegardes

Voir la section kivabien de l’article sur [Borg](/books/administration-syst%C3%A8mes/page/borg#bkmrk-manipulation-des-sau).

## Explication de l’option `--append-only`

Contrairement à ce qu’on pourrait croire, `--append-only` n’empêche pas de supprimer des sauvegardes ([Ce ticket Github](https://github.com/borgbackup/borg/issues/2251) m’en a fait prendre conscience). Ainsi, un attaquant ayant pris le contrôle de l’ordinateur à sauvegarder pourra supprimer des sauvegardes.
Sauf qu’elle ne seront pas vraiment supprimées : l’attaquant aura créé des transactions qui indiquent la suppression des sauvegardes mais ces transactions ne seront rééllement appliquées que lors d’une action comme `prune` depuis un ordinateur qui aura le droit de faire sauter le **append-only**. C’est comme un `BEGIN TRANSACTION;` sans `COMMIT;` en SQL 🙂

C’est le cas du script `/opt/borgmatic_prune_and_check.sh` qui fait effectivement sauter (et le remet après) le verrou avec :
```bash
borg config /var/lib/borg/depot/ append_only 0
```

Comme on automatise la suppression des anciennes sauvegardes avec `cron`, il nous faut un moyen de repérer de tels changements. C’est tout le but de `/opt/borgmatic-stats/verify-archives.pl` qui compare la liste des archives du dépôt avec la liste créée la dernière fois que `/opt/borgmatic_prune_and_check.sh` a supprimé les anciennes archives. Comme le serveur distant est le seul à normalement pouvoir supprimer des archives, il est logique de retrouver toutes les anciennes archives au lancement suivant.

Ainsi, en cas d’incohérence, la suppression des anciennes archives ne s’effectue pas.

**NOTA BENE** : ceci n’empêchera pas un attaquant de changer la configuration de borgmatic pour lui faire sauvegarder des trucs inutiles plutôt que ce qui vous intéresse. Ou de couper les sauvegardes. C’est un inconvénient des sauvegardes en *push* plutôt qu’en *pull*. Je n’ai pas encore trouvé de solution à ça. Peut-être un script qui analyserait la sortie de `borgmatic create --stats --jon` qui me permettrait de repérer des changements importants dans la taille de la sauvegarde, le temps de sauvegarde ou le ratio de déduplication ?

## En cas d’incohérence : restaurer des sauvegardes supprimées par un attaquant

Sur le serveur distant :
```bash
su - borg
cd /var/lib/borg/depot/
```

Regarder le log des transactions pour trouver les n° des transactions suspectes : `cat transactions`

Ce qui nous donne un truc du genre :
```
transaction 23, UTC time 2019-08-01T13:40:34.435019
transaction 25, UTC time 2019-08-01T13:42:05.662188
transaction 27, UTC time 2019-08-01T13:43:18.403771
transaction 29, UTC time 2019-08-01T13:43:53.306636
transaction 31, UTC time 2019-08-01T13:44:51.831937
transaction 33, UTC time 2019-08-01T13:45:17.786886
transaction 35, UTC time 2019-08-01T22:17:12.044179
transaction 37, UTC time 2019-08-02T08:02:55.005430
transaction 43, UTC time 2019-08-02T22:17:10.068843
transaction 45, UTC time 2019-08-03T22:17:09.625745
transaction 47, UTC time 2019-08-04T22:17:09.673447
transaction 49, UTC time 2019-08-05T22:17:13.709208
transaction 51, UTC time 2019-08-06T10:11:26.301496
transaction 53, UTC time 2019-08-06T10:20:46.178014
transaction 55, UTC time 2019-08-06T10:26:47.940003
```

Là, il faut savoir quand a eu lieu le problème. Ici, c'était le 6 août à partir de 10h. Donc les transactions 51 à 55. Mais **attention** !
Il s'agit en fait des transactions **50** à 55 : le numéro indiqué dans le fichier est celui du dernier fichier modifié par la transaction.
Il faut donc partir du n+1 de la dernière transaction correcte.

Après, c'est facile :
```bash
rm hints.* index.* integrity.*
rm data/**/{50..55}
```

On finit par rafraîchir le cache du dépôt :
```bash
borg delete --cache-only /var/lib/borg/depot/
```

Sur l’ordinateur sauvegardé, par contre, je n’arrivais pas à supprimer le cache, j’avais ce message :
```
Cache, or information obtained from the security directory is newer than repository - this is either an attack or unsafe (multiple repos with same ID)
```

Ceci m'a réglé le problème :
```bash
rm -rf ~/.cache/borg/le_dossier_avec_un_nom_monstrueux
rm -rf ~/.config/borg/security/un_autre_dossier_avec_un_nom_monstrueux
```