diff --git a/README.md b/README.md index aab4830c69c45c9ebd9514da4931f1c62a5e3901..a3bd107ec8dadb5ea00c1f3dac744ee4ba002fac 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,29 @@ All configuration is to be placed inside the `backups` dict. ``` +# Settings for all backup related timers. +jobs: + retention: + # Can be used to enable/disable the job + enabled: true + # Time this job runs on, random by default + OnCalendar: "hh:mm" + run: + # Can be used to enable/disable the job + enabled: true + # Time this job runs on, random by default + OnCalendar: "hh:mm" + check: + # Can be used to enable/disable the job + enabled: true + # Time this job runs on, random by default + OnCalendar: "hh:mm" + export: + # Can be used to enable/disable the job + enabled: false + # Time this job runs on, random by default + OnCalendar: "hh:mm" + # backend specific settings backends: # restic specific settings @@ -33,6 +56,18 @@ retention: months: 12 years: 3 +# Settings for the export task +export: + # list of all remote destinations the backup should be exported to + destinations: [] + # every element of this list describes an export target +# - user: root +# host: localhost +# remotepath: / +# type: rsync +# port: 22 +# key: "/etc/backup-client/id_ed25519" + # keys are strings with glob patterns of files to be excluded. Value musst be true to enable the exclude, false to disable it # Only supportet in restic based backups exclude_files: {} diff --git a/defaults/main.yml b/defaults/main.yml index 93b4e8a006fb8f1cb3b7a6f6fc92b120b5d13172..3baa1843f7d420077f2510c371da0058ae06e5dd 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -9,6 +9,9 @@ backups: check: enabled: true OnCalendar: "monday 5:{{ 60|random(seed=(inventory_hostname + 'backups_jobs')) }}" + export: + enabled: false + OnCalendar: "{{ [21,22,23]|random(seed=(inventory_hostname + 'backups_export_h')) }}:{{ 60|random(seed=(inventory_hostname + 'backups_export_m')) }}" backends: restic: url: /var/backup-client/restic @@ -21,6 +24,8 @@ backups: weeks: 16 months: 12 years: 3 + export: + destinations: [] exclude_files: '/tmp': true '/var/tmp': true diff --git a/handlers/main.yml b/handlers/main.yml index 0e125d1a6f9769145a712d053a02d32b58c22c4d..d54826bdfc8e907c4be8410d28702544b0dea14d 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -7,6 +7,7 @@ - check - retention - run + - export systemd: name: "backup-{{ item }}.timer" enabled: "{{ backups.jobs[item].enabled }}" diff --git a/tasks/main.yml b/tasks/main.yml index 713d0c8e9091d02a13c2e26bf3e9f40f9d69002c..8c7a8eb95e5aa4233301a8f6f9718fa0dd9c24c3 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -3,9 +3,6 @@ backup_backend: "{% if backups.mode in ['standalone-restic', 'hypervisor-restic'] %}restic{% else %}False{% endif %}" backup_executor: "{% if backups.mode in ['vm-via-hypervisor'] %}False{% else %}True{% endif %}" -- debug: - var: backup_backend - - name: create config folder file: path: /etc/backup-client/ @@ -17,6 +14,10 @@ - name: setup hosts that actualy run backup code (not vms for example) when: backup_executor block: + - name: generate ssh key + community.crypto.openssh_keypair: + path: /etc/backup-client/id_ed25519 + type: ed25519 - name: create retention file copy: dest: /etc/backup-client/retention.env @@ -48,6 +49,7 @@ - backup-full - backup-cronjob - backup-check + - backup-export - status-email-root template: src: "{{ item }}.j2" @@ -63,6 +65,7 @@ - backup-check - backup-retention - backup-run + - backup-export - status-email-root@ template: src: "{{ item }}.service.j2" @@ -79,6 +82,7 @@ - check - retention - run + - export template: src: "timer.j2" dest: "/etc/systemd/system/backup-{{ item }}.timer" @@ -116,9 +120,15 @@ mode: 0600 content: "{{ backups.include_files|filterEnabled|join('\n') }}" - name: create repo key for restic - command: "dd if=/dev/urandom of=/etc/backup-client/restic.key bs=1k count=16" + shell: "umask 177; dd if=/dev/urandom of=/etc/backup-client/restic.key bs=1k count=16" args: creates: "/etc/backup-client/restic.key" + - name: set repo key permissions + file: + path: /etc/backup-client/restic.key + owner: root + group: root + mode: 0600 - name: create restic env file copy: dest: /etc/backup-client/restic.env diff --git a/templates/backup-export. b/templates/backup-export. new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/templates/backup-export.j2 b/templates/backup-export.j2 new file mode 100755 index 0000000000000000000000000000000000000000..f9a27dc669918534f7a20b731a9c76a095eb0b82 --- /dev/null +++ b/templates/backup-export.j2 @@ -0,0 +1,21 @@ +#!/bin/bash +set -euo pipefail + +echo "Starting to export backups..." + +{% if backup_backend == 'restic' %} +# restic backend +source /etc/backup-client/restic.env + +{% for i in backups.export.destinations if i.type == "rsync" %} +echo "exporting to {{ i.host }}" +rsync -h -r -a --append-verify --delete --stats -e "ssh -p {{ i.port|d(22) }} -i {{ i.key|d('/etc/backup-client/id_ed25519') }}" "${RESTIC_REPOSITORY}/" "{{ i.user }}@{{ i.host }}:{{ i.remotepath }}" +{% endfor %} + +{% endif %} + +{% if not backup_backend %} +echo "Noop, backup is handled external" +{% endif %} + +echo "done!" diff --git a/templates/backup-export.service.j2 b/templates/backup-export.service.j2 new file mode 100644 index 0000000000000000000000000000000000000000..4cedaf5a62c34d99550463291c72a06c1559eda4 --- /dev/null +++ b/templates/backup-export.service.j2 @@ -0,0 +1,10 @@ +[Unit] +Description=Export backups to an external host +OnFailure=status-email-root@%n.service + +[Service] +Nice=19 +IOSchedulingClass=idle +Type=simple +ExecStart=/usr/local/bin/backup-export +