From 4e2f4bf3fe1e96889283c2750fd6401eb8f0d0f1 Mon Sep 17 00:00:00 2001 From: Dieter Verhelst Date: Thu, 11 Jan 2018 23:21:43 +0100 Subject: [PATCH 1/4] 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 From 8cfe198f7ec11178d5a93dfe91a3d2373e396744 Mon Sep 17 00:00:00 2001 From: Dieter Verhelst Date: Thu, 11 Jan 2018 23:24:11 +0100 Subject: [PATCH 2/4] Adding exclude dirs and post-backup tasks --- defaults/main.yml | 4 ++++ templates/borg-backup.sh.j2 | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/defaults/main.yml b/defaults/main.yml index cedf50a..cd13ae7 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -10,6 +10,8 @@ borgbackup_download_url: "https://github.com/borgbackup/borg/releases/download/{ borgbackup_pre_commands: - '[[ ! -f "/usr/sbin/automysqlbackup" ]] || /usr/sbin/automysqlbackup' +borgbackup_post_commands: [] + borgbackup_include: - "/etc" - "/home" @@ -17,6 +19,8 @@ borgbackup_include: - "/var/www" - "/var/log" +borgbackup_exclude: [] + borgbackup_retention: hourly: 12 daily: 7 diff --git a/templates/borg-backup.sh.j2 b/templates/borg-backup.sh.j2 index 96f9348..bf85067 100644 --- a/templates/borg-backup.sh.j2 +++ b/templates/borg-backup.sh.j2 @@ -66,7 +66,7 @@ if [ "$1" = "backup" ] printf "Backing up to {{ b.fqdn }} :\n" 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 %} + /usr/local/bin/borg create -p --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 %} {% for dir in borgbackup_exclude %} --exclude '{{ dir }}'{% endfor %} if [ "$?" -eq "0" ]; then printf "Backup succeeded on $date to {{ b.fqdn }}\n" >> /var/log/borg-backup.log; fi @@ -75,5 +75,11 @@ if [ "$1" = "backup" ] /usr/local/bin/borg prune -v $REPOSITORY {{ b.options }} -H {{ borgbackup_retention.hourly }} -d {{ borgbackup_retention.daily }} -w {{ borgbackup_retention.weekly }} -m {{ borgbackup_retention.monthly }} -y {{ borgbackup_retention.yearly }} {% endif %} {% endfor %} + + # Running some commands post-backup +{% for postcommand in borgbackup_post_commands %} + {{ postcommand }} +{% endfor %} + fi From 0aa85752278a871ead1f0564d692add28fa92c54 Mon Sep 17 00:00:00 2001 From: Dieter Verhelst Date: Thu, 11 Jan 2018 23:26:43 +0100 Subject: [PATCH 3/4] Making it possible to define shell and support other os-ses --- defaults/main.yml | 4 ++++ tasks/borg-client.yml | 4 ++-- tasks/install.yml | 4 ++-- templates/borg-backup.sh.j2 | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/defaults/main.yml b/defaults/main.yml index cd13ae7..cc09f97 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -37,3 +37,7 @@ borgbackup_appendonly: False borgbackup_management_station: '' borgbackup_management_user: '' borgbackup_management_ssh_pubkey: '' + +borgbackup_owner: root +borgbackup_group: root +borgbackup_shell: "/bin/bash" diff --git a/tasks/borg-client.yml b/tasks/borg-client.yml index fbd6ffa..3505876 100644 --- a/tasks/borg-client.yml +++ b/tasks/borg-client.yml @@ -96,8 +96,8 @@ template: src: "borg-backup.sh.j2" dest: "/usr/local/bin/borg-backup" - owner: "root" - group: "root" + owner: "{{ borgbackup_owner }}" + group: "{{ borgbackup_group }}" mode: "0744" - name: client | create backup-directory on backup server diff --git a/tasks/install.yml b/tasks/install.yml index 87ff287..1a59145 100644 --- a/tasks/install.yml +++ b/tasks/install.yml @@ -3,8 +3,8 @@ get_url: dest: "/usr/local/bin/borg" checksum: "{{ borgbackup_checksum }}" - owner: "root" - group: "root" + owner: "{{ borgbackup_owner }}" + group: "{{ borgbackup_group }}" mode: "0755" url: "{{ borgbackup_download_url }}" tags: borginstall diff --git a/templates/borg-backup.sh.j2 b/templates/borg-backup.sh.j2 index bf85067..3f89d6d 100644 --- a/templates/borg-backup.sh.j2 +++ b/templates/borg-backup.sh.j2 @@ -1,4 +1,4 @@ -#!/bin/bash +#!{{ borgbackup_shell }} if [ -z "$1" ] || [ ! -z "$2" ] then From 1afb01aa4a9d2ead5fd0c093c71f14146b442580 Mon Sep 17 00:00:00 2001 From: Dieter Verhelst Date: Sun, 21 Jan 2018 23:12:48 +0100 Subject: [PATCH 4/4] adding key-options for hetzner too, unifying modification of authorized_keys with rsync and hetzner --- tasks/borg-client.yml | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/tasks/borg-client.yml b/tasks/borg-client.yml index 3505876..fce6b6a 100644 --- a/tasks/borg-client.yml +++ b/tasks/borg-client.yml @@ -46,7 +46,7 @@ with_items: "{{ borgbackup_servers }}" changed_when: false -- name: client | modify local rsync.net authorized_keys +- name: client | modify local rsync.net/hetzner authorized_keys authorized_key: user: "{{ ansible_user_id }}" key: "{{ sshkey.stdout }}" @@ -55,19 +55,7 @@ manage_dir: no delegate_to: localhost become: no - when: item.type == 'rsync.net' - with_items: "{{ borgbackup_servers }}" - register: authkeys - -- 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 == 'hetzner' + when: item.type in ['rsync.net','hetzner'] with_items: "{{ borgbackup_servers }}" register: authkeys