Role restructured:

- if needed creation of a service user incl. creation of the ssh-key,
  - add the ssh key to authorized_keys,
  - auto init of the repos,
  - creation and start of systemd timer and services and
  - installation of the Docker helperscript.
This commit is contained in:
Frank Dornheim 2023-03-05 13:52:02 +01:00
parent c9ce5d4856
commit 8b67e74440
15 changed files with 564 additions and 0 deletions

32
tasks/01_install.yml Normal file
View File

@ -0,0 +1,32 @@
---
- name: Install borgbackup
when: install_backup is not defined or install_backup
tags:
- install_backup
block:
- name: Ensure legacy hooks aren't used
ansible.builtin.assert:
that:
- borgmatic_failure_command is undefined
- borgmatic_before_backup_command is undefined
- borgmatic_after_backup_command is undefined
msg: Please use the new borgmatic_hooks variable instead of individual before/after/failure hooks.
- name: Include OS-specific variables
include_vars: "{{ item }}"
with_first_found:
- "{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml"
- "{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml"
- "{{ ansible_distribution }}.yml"
- "{{ ansible_os_family }}.yml"
- "{{ ansible_lsb.id }}.yml"
- name: Install general dependencies (openssh)
ansible.builtin.package:
name: "{{ borg_dep_packages }}"
state: present
- name: Install Borg and Borgmatic
ansible.builtin.include_tasks:
file: noauto_install_{{ borg_install_method }}.yml
...

View File

@ -0,0 +1,37 @@
---
- name: Setup backup environment
tags:
- install_backup
when:
- install_backup is not defined or install_backup
- backup_create_local_user is not defined or backup_create_local_user
block:
- name: Add local backup group
ansible.builtin.group:
name: "{{ vault_borg.backup_group }}"
state: present
- name: Add local backup user
ansible.builtin.user:
name: "{{ vault_borg.backup_user }}"
shell: "/bin/bash"
groups: "{{ vault_borg.backup_group }}"
comment: "Backup User Account"
append: true
- name: Add sudo users
community.general.sudoers:
name: "backup"
state: present
user: "{{ vault_borg.backup_user }}"
nopassword: true
commands:
- "/opt/borgmatic/bin/borg"
- "/usr/local/bin/borgmatic -C -p -c /etc/borgmatic/{{ borgmatic_config_name }}"
- "/usr/local/bin/borgmatic -k -c /etc/borgmatic/{{ borgmatic_config_name }}"
- "/usr/local/bin/borgmatic -c /etc/borgmatic/{{ borgmatic_config_name }}"
- name: Install Links to borg and borgmatic
ansible.builtin.include_tasks:
file: noauto_create_links_and_install_helperscripts.yml
...

69
tasks/02_create_key.yml Normal file
View File

@ -0,0 +1,69 @@
---
- name: Create ssh-key for {{ borgbackup_user }} if neeeded
when:
- install_backup is not defined or install_backup
- backup_id_rsa is not defined or backup_id_rsa | length == 0
tags:
- install_backup
block:
- name: Ensire /home/{{ borgbackup_user }}/.ssh directory exist
ansible.builtin.file:
path: "/home/{{ borgbackup_user }}/.ssh/"
state: directory
mode: "0700"
owner: "{{ borgbackup_user }}"
group: "{{ borgbackup_group }}"
- name: Generate an OpenSSH keypair with the default values (4096 bits, rsa)
community.crypto.openssh_keypair:
path: "/home/{{ borgbackup_user }}/.ssh/id_rsa"
mode: "0600"
owner: "{{ borgbackup_user }}"
group: "{{ borgbackup_group }}"
- name: Set key (/home/{{ borgbackup_user }}/.ssh) permission
ansible.builtin.file:
path: "/home/{{ borgbackup_user }}/.ssh/id_rsa.pub"
mode: "0644"
owner: "{{ borgbackup_user }}"
group: "{{ borgbackup_group }}"
- name: Read ssh key
ansible.builtin.slurp:
src: "/home/{{ borgbackup_user }}/.ssh/id_rsa.pub"
register: backup_local_ssh_key
- name: Set authorized key taken from file
ansible.posix.authorized_key:
user: "{{ backup_repository | regex_search('(.*)@', '\\1') | first }}"
state: present
key: "{{ backup_local_ssh_key['content'] | b64decode }}"
# This is a bit tricky, the string backup_repository consists of three parts:
# "username"@"FQDN":"path/to/store/backup".
# With the regex we use the FQDN part to store the ssh-key on the target system.
delegate_to: "{{ backup_repository | regex_search('@(.*):', '\\1') | first }}"
- name: Install ssh cert and key
when:
- install_backup is not defined or install_backup
- backup_id_rsa is defined and backup_id_rsa | length > 0
- backup_id_rsa_pub is defined and backup_id_rsa_pub | length > 0
tags:
- install_backup
block:
- name: Copy existing id_rsa, not genereting one
ansible.builtin.copy:
content: "{{ backup_id_rsa }}"
dest: "/home/{{ borgbackup_user }}/.ssh/id_rsa"
mode: "0600"
owner: "{{ borgbackup_user }}"
group: "{{ borgbackup_group }}"
- name: Copy existing id_rsa.pub, not genereting one
ansible.builtin.copy:
content: "{{ backup_id_rsa_pub }}"
dest: "/home/{{ borgbackup_user }}/.ssh/id_rsa.pub"
mode: "0644"
owner: "{{ borgbackup_user }}"
group: "{{ borgbackup_group }}"
...

23
tasks/03_configure.yml Executable file
View File

@ -0,0 +1,23 @@
---
- name: Configure borgbackup
when:
- install_backup is not defined or install_backup
tags:
- install_backup
block:
- name: Ensure /etc/borgmatic exists
ansible.builtin.file:
path: /etc/borgmatic
state: directory
mode: "0700"
owner: "{{ borgbackup_user }}"
group: "{{ borgbackup_group }}"
- name: Add Borgmatic configuration
ansible.builtin.template:
src: config.yaml.j2
dest: "/etc/borgmatic/{{ borgmatic_config_name }}"
mode: "0600"
owner: "{{ borgbackup_user }}"
group: "{{ borgbackup_group }}"
...

View File

@ -0,0 +1,9 @@
---
- name: Init repository
when:
- install_backup is not defined or install_backup
tags:
- install_backup
ansible.builtin.command:
cmd: "su - {{ borgbackup_user }} -c '/usr/local/bin/borgmatic rcreate --encryption keyfile --append-only'"
...

89
tasks/05_create_timer.yml Normal file
View File

@ -0,0 +1,89 @@
---
- name: Create borgbackup timer
when:
- install_backup is not defined or install_backup
tags:
- install_backup
block:
- name: Add systemd.timer for borgmatic (large repo, create and check separate)
when: borgmatic_large_repo
block:
- name: Copy systemd files
ansible.builtin.template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: root
backup: true
mode: "{{ item.mode }}"
with_items:
- { src: "backup_large_repo_check.timer.j2", dest: "/usr/lib/systemd/system/backup_large_repo_check.timer", mode: "0644" }
- { src: "backup_large_repo_check.service.j2", dest: "/usr/lib/systemd/system/backup_large_repo_check.service", mode: "0644" }
- { src: "backup_large_repo.timer.j2", dest: "/usr/lib/systemd/system/backup_large_repo.timer", mode: "0644" }
- { src: "backup_large_repo.service.j2", dest: "/usr/lib/systemd/system/backup_large_repo.service", mode: "0644" }
- name: Populate service facts (large repo, create and check separate)
ansible.builtin.service_facts:
- name: Restart borgmatic services (large repo, create and check separate)
ansible.builtin.systemd:
name: "{{ item }}"
state: restarted
enabled: true
masked: false
daemon_reload: true
when: "item in services"
with_items:
- "backup_large_repo_check.service"
- "backup_large_repo.service"
# bug: Need own section without masked else the timer are skipped
- name: Restart borgmatic timers (large repo, create and check separate)
ansible.builtin.systemd:
name: "{{ item }}"
state: started
enabled: true
daemon_reload: true
with_items:
- "backup_large_repo_check.timer"
- "backup_large_repo.timer"
- name: Add systemd.timer for borgmatic (normal-sized repo)
when: not borgmatic_large_repo
block:
- name: Copy systemd files (normal-sized repo)
ansible.builtin.template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: root
backup: true
mode: "{{ item.mode }}"
with_items:
- { src: "backup_normal_repo.timer.j2", dest: "/usr/lib/systemd/system/backup_normal_repo.timer", mode: "0644" }
- { src: "backup_normal_repo.service.j2", dest: "/usr/lib/systemd/system/backup_normal_repo.service", mode: "0644" }
- name: Populate service facts
ansible.builtin.service_facts:
- name: Restart borgmatic services (normal-sized repo)
ansible.builtin.systemd:
name: "{{ item }}"
state: started
enabled: true
masked: false
daemon_reload: true
when: "item in services"
with_items:
- backup_normal_repo.service
# bug: Need own section without masked else the timer ar skipped
- name: Restart borgmatic timers (normal-sized repo)
ansible.builtin.systemd:
name: "{{ item }}"
state: started
enabled: true
daemon_reload: true
with_items:
- "backup_normal_repo.timer"
...

View File

@ -0,0 +1,33 @@
---
- name: Create borgmatic command in /usr/local/bin
ansible.builtin.copy:
content: |
#!/bin/bash
. "{{ borg_venv_path }}"/bin/activate
borgmatic "$@"
dest: /usr/local/bin/borgmatic
mode: "0755"
owner: "{{ borgbackup_user }}"
group: "{{ borgbackup_group }}"
- name: Create borg command in /usr/local/bin
ansible.builtin.copy:
content: |
#!/bin/bash
. "{{ borg_venv_path }}"/bin/activate
borg "$@"
dest: /usr/local/bin/borg
mode: "0755"
owner: "{{ borgbackup_user }}"
group: "{{ borgbackup_group }}"
- name: Install helper scripts
ansible.builtin.copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: "{{ item.owner }}"
group: "{{ item.group }}"
mode: "{{ item.mode }}"
with_items:
- { src: "docker.sh", dest: "/usr/local/bin/docker.sh", owner: "{{ backup_owner }}", group: "{{ backup_group }}", mode: "0770" }
...

View File

@ -0,0 +1,23 @@
---
- name: Install borgbackup by distro
tags:
- install_backup
block:
- name: Check if EPEL repo is enabled, if installation from distro is requested
when: ansible_os_family == 'RedHat'
block:
- name: Get list of installed packages
ansible.builtin.package_facts:
manager: auto
- name: Ensure EPEL is enabled
ansible.builtin.assert:
that:
- "'epel-release' in ansible_facts.packages"
fail_msg: Need EPEL repo to install via distro package.
- name: Install borgmatic and borg via distribution package manager
ansible.builtin.package:
name: "{{ item }}"
state: present
loop: "{{ borg_distro_packages }}"
...

View File

@ -0,0 +1,33 @@
---
- name: Install borgbackup by pip
tags:
- install_backup
block:
- name: Install build dependencies
ansible.builtin.package:
name: "{{ borg_pip_packages }}"
state: present
- name: Create virtualenv for borg # noqa package-latest
ansible.builtin.pip:
name:
- pip
- setuptools
state: latest
virtualenv: "{{ borg_venv_path }}"
virtualenv_command: "{{ python_bin }} -m venv"
- name: Install dependent Python Packages
ansible.builtin.pip:
name: "{{ borg_dependent_python_packages }}"
virtualenv: "{{ borg_venv_path }}"
when: borg_dependent_python_packages is defined
- name: Install main Python Packages
ansible.builtin.pip:
name: "{{ item.name }}"
version: "{{ item.version | default(omit, true) }}"
virtualenv: "{{ borg_venv_path }}"
when: borg_python_packages is defined
loop: "{{ borg_python_packages }}"
...

View File

@ -0,0 +1,59 @@
# Managed by Ansible, please don't edit manually
[Unit]
Description=borgmatic backup only - because large repo
Wants=backup_normal_repo.timer
Wants=network-online.target
After=network-online.target
# Prevent borgmatic from running unless the machine is plugged into power. Remove this line if you
# want to allow borgmatic to run anytime.
ConditionACPower=true
[Service]
Type=oneshot
ExecStart=su - {{ borgbackup_user }} -c '/usr/local/bin/borgmatic -C -p -c /etc/borgmatic/{{ borgmatic_config_name }}'
# Source: https://projects.torsion.org/borgmatic-collective/borgmatic/raw/branch/master/sample/systemd/borgmatic.service
# Security settings for systemd running as root, optional but recommended to improve security. You
# can disable individual settings if they cause problems for your use case. For more details, see
# the systemd manual: https://www.freedesktop.org/software/systemd/man/systemd.exec.html
LockPersonality=true
# Certain borgmatic features like Healthchecks integration need MemoryDenyWriteExecute to be off.
# But you can try setting it to "yes" for improved security if you don't use those features.
MemoryDenyWriteExecute=no
NoNewPrivileges=yes
PrivateDevices=yes
PrivateTmp=yes
ProtectClock=yes
ProtectControlGroups=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
# To restrict write access further, change "ProtectSystem" to "strict" and uncomment
# "ReadWritePaths", "ReadOnlyPaths", "ProtectHome", and "BindPaths". Then add any local repository
# paths to the list of "ReadWritePaths" and local backup source paths to "ReadOnlyPaths". This
# leaves most of the filesystem read-only to borgmatic.
ProtectSystem=full
# ReadWritePaths=-/mnt/my_backup_drive
# ReadOnlyPaths=-/var/lib/my_backup_source
# This will mount a tmpfs on top of /root and pass through needed paths
# ProtectHome=tmpfs
# BindPaths=-/root/.cache/borg -/root/.config/borg -/root/.borgmatic
# May interfere with running external programs within borgmatic hooks.
# CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW
# Lower CPU and I/O priority.
Nice=19
CPUSchedulingPolicy=batch
IOSchedulingClass=best-effort
IOSchedulingPriority=7
IOWeight=100

View File

@ -0,0 +1,13 @@
# Managed by Ansible, please don't edit manually
[Unit]
Description=Start creating of Backups - see: https://www.freedesktop.org/software/systemd/man/systemd.time.html#
[Timer]
# Day-of-the-Week Year-Month-Day Hour:Minutes:Seconds
# Persistent -> resume backup after shutdown
OnCalendar= *-*-* {{ borgmatic_timer_hour }}:{{ borgmatic_timer_minute }}:00
Persistent=true
[Install]
WantedBy=timers.target

View File

@ -0,0 +1,59 @@
# Managed by Ansible, please don't edit manually
[Unit]
Description=borgmatic check consistently only - because large repo
Wants=backup_normal_repo.timer
Wants=network-online.target
After=network-online.target
# Prevent borgmatic from running unless the machine is plugged into power. Remove this line if you
# want to allow borgmatic to run anytime.
ConditionACPower=true
[Service]
Type=oneshot
ExecStart=su - {{ borgbackup_user }} -c '/usr/local/bin/borgmatic -k -c /etc/borgmatic/{{ borgmatic_config_name }}'
# Source: https://projects.torsion.org/borgmatic-collective/borgmatic/raw/branch/master/sample/systemd/borgmatic.service
# Security settings for systemd running as root, optional but recommended to improve security. You
# can disable individual settings if they cause problems for your use case. For more details, see
# the systemd manual: https://www.freedesktop.org/software/systemd/man/systemd.exec.html
LockPersonality=true
# Certain borgmatic features like Healthchecks integration need MemoryDenyWriteExecute to be off.
# But you can try setting it to "yes" for improved security if you don't use those features.
MemoryDenyWriteExecute=no
NoNewPrivileges=yes
PrivateDevices=yes
PrivateTmp=yes
ProtectClock=yes
ProtectControlGroups=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
# To restrict write access further, change "ProtectSystem" to "strict" and uncomment
# "ReadWritePaths", "ReadOnlyPaths", "ProtectHome", and "BindPaths". Then add any local repository
# paths to the list of "ReadWritePaths" and local backup source paths to "ReadOnlyPaths". This
# leaves most of the filesystem read-only to borgmatic.
ProtectSystem=full
# ReadWritePaths=-/mnt/my_backup_drive
# ReadOnlyPaths=-/var/lib/my_backup_source
# This will mount a tmpfs on top of /root and pass through needed paths
# ProtectHome=tmpfs
# BindPaths=-/root/.cache/borg -/root/.config/borg -/root/.borgmatic
# May interfere with running external programs within borgmatic hooks.
# CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW
# Lower CPU and I/O priority.
Nice=19
CPUSchedulingPolicy=batch
IOSchedulingClass=best-effort
IOSchedulingPriority=7
IOWeight=100

View File

@ -0,0 +1,13 @@
# Managed by Ansible, please don't edit manually
[Unit]
Description=Start creating of Backups - see: https://www.freedesktop.org/software/systemd/man/systemd.time.html#
[Timer]
# Day-of-the-Week Year-Month-Day Hour:Minutes:Seconds
# Persistent -> resume backup after shutdown
OnCalendar= {% if borgmatic_timer_day_of_the_week is defined and borgmatic_timer_day_of_the_week | lenght > 0 %} {{ borgmatic_timer_day_of_the_week }} {% endif %} *-*-{{ borgmatic_timer_checks_day }} {{ borgmatic_timer_checks_hour }}:{{ borgmatic_timer_checks_minute }}:00
Persistent=true
[Install]
WantedBy=timers.target

View File

@ -0,0 +1,59 @@
# Managed by Ansible, please don't edit manually
[Unit]
Description=borgmatic backup
Wants=backup_normal_repo.timer
Wants=network-online.target
After=network-online.target
# Prevent borgmatic from running unless the machine is plugged into power. Remove this line if you
# want to allow borgmatic to run anytime.
ConditionACPower=true
[Service]
Type=oneshot
ExecStart=su - {{ borgbackup_user }} -c '/usr/local/bin/borgmatic -c /etc/borgmatic/{{ borgmatic_config_name }}'
# Source: https://projects.torsion.org/borgmatic-collective/borgmatic/raw/branch/master/sample/systemd/borgmatic.service
# Security settings for systemd running as root, optional but recommended to improve security. You
# can disable individual settings if they cause problems for your use case. For more details, see
# the systemd manual: https://www.freedesktop.org/software/systemd/man/systemd.exec.html
LockPersonality=true
# Certain borgmatic features like Healthchecks integration need MemoryDenyWriteExecute to be off.
# But you can try setting it to "yes" for improved security if you don't use those features.
MemoryDenyWriteExecute=no
NoNewPrivileges=yes
PrivateDevices=yes
PrivateTmp=yes
ProtectClock=yes
ProtectControlGroups=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
# To restrict write access further, change "ProtectSystem" to "strict" and uncomment
# "ReadWritePaths", "ReadOnlyPaths", "ProtectHome", and "BindPaths". Then add any local repository
# paths to the list of "ReadWritePaths" and local backup source paths to "ReadOnlyPaths". This
# leaves most of the filesystem read-only to borgmatic.
ProtectSystem=full
# ReadWritePaths=-/mnt/my_backup_drive
# ReadOnlyPaths=-/var/lib/my_backup_source
# This will mount a tmpfs on top of /root and pass through needed paths
# ProtectHome=tmpfs
# BindPaths=-/root/.cache/borg -/root/.config/borg -/root/.borgmatic
# May interfere with running external programs within borgmatic hooks.
# CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW
# Lower CPU and I/O priority.
Nice=19
CPUSchedulingPolicy=batch
IOSchedulingClass=best-effort
IOSchedulingPriority=7
IOWeight=100

View File

@ -0,0 +1,13 @@
# Managed by Ansible, please don't edit manually
[Unit]
Description=Start creating of Backups - see: https://www.freedesktop.org/software/systemd/man/systemd.time.html#
[Timer]
# Day-of-the-Week Year-Month-Day Hour:Minutes:Seconds
# Persistent -> resume backup after shutdown
OnCalendar= *-*-* {{ borgmatic_timer_hour }}:{{ borgmatic_timer_minute }}:00
Persistent=true
[Install]
WantedBy=timers.target