From 4e2f4bf3fe1e96889283c2750fd6401eb8f0d0f1 Mon Sep 17 00:00:00 2001 From: Dieter Verhelst Date: Thu, 11 Jan 2018 23:21:43 +0100 Subject: [PATCH] Hetzner support --- README.md | 9 ++++++++- tasks/borg-client.yml | 30 +++++++++++++++++++++--------- templates/borg-backup.sh.j2 | 14 +++++++------- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 5033482..ec9f9d1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Borg backup role This role installs Borg backup on borgbackup\_servers and clients. The role contains a wrapper-script 'borg-backup' to ease the usage on the client. Supported options include borg-backup info | init | list | backup | mount. Automysqlbackup will run as pre-backup command if it's installed. -The role supports both self hosted and rsync.net as Borg server. +The role supports both self hosted and offsite backup-storage such as rsync.net and hetzner storage box as Borg server. It's possible to configure append-only repositories to secure the backups against deletion from the client. @@ -29,6 +29,13 @@ borgbackup_servers: home: "" pool: repos options: "--remote-path=borg1" + - fqdn: username.your-storagebox.de + user: username + type: hetzner + home: "" + pool: repos + options: "" + borgbackup_retention: hourly: 12 diff --git a/tasks/borg-client.yml b/tasks/borg-client.yml index 919a026..fbd6ffa 100644 --- a/tasks/borg-client.yml +++ b/tasks/borg-client.yml @@ -37,12 +37,12 @@ when: item.type == 'normal' with_items: "{{ borgbackup_servers }}" -# rsync.net has no python, so we can only use raw to manage ssh keys - workaround with local tmp file -- name: client | get rsync.net authorized_keys file - raw: scp {{ item.user }}@{{ item.fqdn }}:.ssh/authorized_keys /tmp/rsync.net-{{ item.fqdn }}-authkeys +# rsync.net and hetzner have no python, so we can only use raw to manage ssh keys - workaround with local tmp file +- name: client | get authorized_keys file + raw: scp {{ item.user }}@{{ item.fqdn }}:.ssh/authorized_keys /tmp/authkeys-{{ item.type }}-{{ item.fqdn }}-authkeys delegate_to: localhost become: no - when: item.type == 'rsync.net' + when: item.type in ['rsync.net','hetzner'] with_items: "{{ borgbackup_servers }}" changed_when: false @@ -51,7 +51,7 @@ user: "{{ ansible_user_id }}" key: "{{ sshkey.stdout }}" key_options: 'command="cd {{ item.pool }}/{{ inventory_hostname }};/usr/local/bin/borg1 serve {% if borgbackup_appendonly %}--append-only {% endif %} --restrict-to-path {{ item.pool }}/{{ inventory_hostname }}",no-port-forwarding,no-X11-forwarding,no-pty,no-agent-forwarding,no-user-rc' - path: "/tmp/rsync.net-{{ item.fqdn }}-authkeys" + path: "/tmp/authkeys-{{ item.type }}-{{ item.fqdn }}-authkeys" manage_dir: no delegate_to: localhost become: no @@ -59,16 +59,28 @@ with_items: "{{ borgbackup_servers }}" register: authkeys -- name: client | upload local authorized_keys to rsync.net - raw: scp /tmp/rsync.net-{{ item.fqdn }}-authkeys {{ item.user }}@{{ item.fqdn }}:.ssh/authorized_keys +- name: client | modify local hetzner authorized_keys + authorized_key: + user: "{{ ansible_user_id }}" + key: "{{ sshkey.stdout }}" + path: "/tmp/authkeys-{{ item.type }}-{{ item.fqdn }}-authkeys" + manage_dir: no delegate_to: localhost become: no - when: item.type == 'rsync.net' and authkeys.changed + when: item.type == 'hetzner' + with_items: "{{ borgbackup_servers }}" + register: authkeys + +- name: client | upload local authorized_keys to rsync.net / hetzner + raw: scp /tmp/authkeys-{{ item.type }}-{{ item.fqdn }}-authkeys {{ item.user }}@{{ item.fqdn }}:.ssh/authorized_keys + delegate_to: localhost + become: no + when: item.type in ['rsync.net','hetzner'] and authkeys.changed with_items: "{{ borgbackup_servers }}" - name: client | remove tmp authorized_keys files file: - path: /tmp/rsync.net-{{ item.fqdn }}-authkeys + path: /tmp/authkeys-{{ item.type }}-{{ item.fqdn }}-authkeys state: absent delegate_to: localhost become: no diff --git a/templates/borg-backup.sh.j2 b/templates/borg-backup.sh.j2 index 0e7bd60..96f9348 100644 --- a/templates/borg-backup.sh.j2 +++ b/templates/borg-backup.sh.j2 @@ -15,7 +15,7 @@ if [ "$1" = "info" ] then if [ -z "$2" ]; then printf "run $0 with list and use the backup-tag to request information\n"; exit 1; fi {% for b in borgbackup_servers %} - REPOSITORY={{ b.user }}@{{ b.fqdn }}:{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} + REPOSITORY={% if b.type == 'hetzner' %}ssh://{% endif %}{{ b.user }}@{{ b.fqdn }}:{% if b.type == 'hetzner' %}23/./{% endif %}{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} /usr/local/bin/borg info $REPOSITORY::$2 {{ b.options }} {% endfor %} exit 0 @@ -27,7 +27,7 @@ if [ "$1" = "mount" ] if [ -z "$3" ]; then printf "Select the backup to mount\n"; exit 1; fi if [ -z "$4" ]; then printf "Select the path to mount the backup on\n"; exit 1; fi {% for b in borgbackup_servers %} - REPOSITORY={{ b.user }}@{{ b.fqdn }}:{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} + REPOSITORY={% if b.type == 'hetzner' %}ssh://{% endif %}{{ b.user }}@{{ b.fqdn }}:{% if b.type == 'hetzner' %}23/./{% endif %}{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} /usr/local/bin/borg mount $REPOSITORY::$3 $4 {{ b.options }} if [ "$?" = "0" ]; then printf "Backup mounted on $4, do not forget to unmount!\n"; fi exit 0 @@ -37,7 +37,7 @@ fi if [ "$1" = "list" ] then {% for b in borgbackup_servers %} - REPOSITORY={{ b.user }}@{{ b.fqdn }}:{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} + REPOSITORY={% if b.type == 'hetzner' %}ssh://{% endif %}{{ b.user }}@{{ b.fqdn }}:{% if b.type == 'hetzner' %}23/./{% endif %}{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} printf "Archives on {{ b.fqdn }} :\n" /usr/local/bin/borg list -v $REPOSITORY {{ b.options }} {% endfor %} @@ -47,8 +47,8 @@ fi if [ "$1" = "init" ] then {% for b in borgbackup_servers %} - REPOSITORY={{ b.user }}@{{ b.fqdn }}:{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} - borg init $REPOSITORY {{ b.options }} + REPOSITORY={% if b.type == 'hetzner' %}ssh://{% endif %}{{ b.user }}@{{ b.fqdn }}:{% if b.type == 'hetzner' %}23/./{% endif %}{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} + /usr/local/bin/borg init $REPOSITORY {{ b.options }} {% endfor %} exit 0 fi @@ -64,11 +64,11 @@ if [ "$1" = "backup" ] {% for b in borgbackup_servers %} printf "Backing up to {{ b.fqdn }} :\n" - REPOSITORY={{ b.user }}@{{ b.fqdn }}:{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} + REPOSITORY={% if b.type == 'hetzner' %}ssh://{% endif %}{{ b.user }}@{{ b.fqdn }}:{% if b.type == 'hetzner' %}23/./{% endif %}{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} /usr/local/bin/borg create --compression zlib,6 --stats $REPOSITORY::$date {{ b.options }} {% for dir in borgbackup_include %}{{ dir }} {% endfor %}{% if automysql.stat.isdir is defined and automysql.stat.isdir == True %}/var/lib/automysqlbackup{% endif %} - if [ "$?" -eq "0" ]; then printf "Backup succeeded on $date\n" >> /var/log/borg-backup.log; fi + if [ "$?" -eq "0" ]; then printf "Backup succeeded on $date to {{ b.fqdn }}\n" >> /var/log/borg-backup.log; fi {% if not borgbackup_appendonly %} # prune old backups