diff options
Diffstat (limited to 'README.md')
| -rw-r--r-- | README.md | 229 |
1 files changed, 208 insertions, 21 deletions
@@ -1,5 +1,4 @@ -Ansible Role: BorgBackup -======================== +# Ansible Role: BorgBackup An Ansible role that installs and configures a systemd service for BorgBackup on a client and (delegated) server. @@ -9,8 +8,7 @@ The documentation assumes basic knowledge about BorgBackup. You can get up to speed with Borg by reading their excellent documentation on <https://borgbackup.readthedocs.io>. -How it works ------------- +## How it works ```mermaid sequenceDiagram @@ -27,8 +25,7 @@ borg-client->>Ansible: Store decryption keys borg-client-->borg-server: Do Backup ``` -Installation ------------- +## Installation via ansible-galaxy @@ -54,8 +51,7 @@ ansible-galaxy role install git+https://github.com/kliwniloc/ansible-role-borgba name: kliwniloc.borgbackup ``` -Role Variables --------------- +## Role Variables For more details, see: [`defaults/main.yml`](defaults/main.yml) @@ -76,7 +72,7 @@ will default to `borg_server_host`. ```yaml borg_server_host: "" # Required borg_server_host_ssh_key: "" # Required -borg_server_host_url: {{ borg_server_host }} # Optional +borg_server_host_url: { { borg_server_host } } # Optional ``` The role creates a user for the Borg repositories on the Borg server. You can @@ -121,6 +117,8 @@ your Borg backups, but it is not used by default. > If you want true end-to-end encryption, you should configure a passphrase > Read more: [BorgBackup Security](https://borgbackup.readthedocs.io/en/stable/internals/security.html#offline-key-security) +<!-- TODO: Include keyfile backup mode --> + `borg_included_dirs` and `borg_excluded_dirs` finally picks what directories will be backed up by Borg. @@ -167,18 +165,17 @@ see man-page systemd.timer(5). borg_backup_script_location: /usr/local/bin/run_borg_backup borg_backup_timer_name: borg_backup borg_backup_service_name: borg_backup -borg_backup_argument: '{{ borg_server_host_url }}' -borg_systemd_oncalendar: '*-*-* 02:00:00' +borg_backup_argument: "{{ borg_server_host_url }}" +borg_systemd_oncalendar: "*-*-* 02:00:00" borg_systemd_accuracysec: 60min ``` -Example Playbooks ------------------ +## Example Playbooks -Simple Playbook +### Simple Playbook ```yaml -- name: > +- name: >- Add Borg backup to the borg-client and save the decryption keys alongside the playbook hosts: borg-client @@ -192,10 +189,10 @@ Simple Playbook - /opt/project ``` -Multiple Backup servers +### Multiple Backup Servers ```yaml -- name: > +- name: >- Add Borg backup with multiple borg servers to the borg-client and save the decryption keys alongside the playbook hosts: borg-client @@ -212,12 +209,202 @@ Multiple Backup servers borg_server_host_ssh_key: ssh-rsa BBBBBBBB... ``` -Dependencies ------------- +### Multiple Repositories on Single Server, Single Client (Multi-Instance) + +> [!NOTE] +> **This is considered a beta feature** +> This feature is still being developed and has some quirks around it. +> We plan to release this properly on the next major version with some breaking +> changes to make this less of a footgun. Until then, read this section +> carefully. + +When a single client host needs to back up different data sets to the same Borg +server (e.g., system configs and user data), you can run the role multiple times +with different `borg_repo_name` values. + +**Important:** Each invocation must have a unique `borg_backup_argument` to create +separate systemd timer units. + +<!-- TODO: (next major version): Change default borg_backup_argument to include + borg_repo_name for uniqueness: + "{{ borg_server_host_url }}-{{ borg_repo_name }}". + This will be a breaking change requiring migration of existing systemd + units. --> + +```yaml +- name: Configure multi-instance backup (same host, different repos) + hosts: borg-client + vars: + borg_server_host: borg-server + borg_server_host_ssh_key: ssh-rsa AAAAAAAA... + borg_decryption_keys_yaml_path: "{{ playbook_dir }}/decryption_keys.yml" + + roles: + - role: kliwniloc.borgbackup + vars: + borg_repo_name: configs + borg_backup_argument: configs + borg_compression: zstd + borg_included_dirs: + - /etc + borg_systemd_oncalendar: "*-*-* 02:00:00" + + - role: kliwniloc.borgbackup + vars: + borg_repo_name: home-data + borg_backup_argument: home-data + borg_compression: lz4 + borg_included_dirs: + - /home + borg_excluded_dirs: + - /home/*/.cache + borg_systemd_oncalendar: "*-*-* 04:00:00" +``` + +This creates: + +- Two repositories on the Borg server: `/opt/borg/configs` and `/opt/borg/home-data` +- Two systemd timers: `borg_backup@configs.timer` and `borg_backup@home-data.timer` +- A single SSH keypair shared between both repositories +- A single `authorized_keys` entry with both repositories in `--restrict-to-repository` + +## Important Behaviors and Limitations + +### Consistent `--append-only` Setting Required + +All repositories for a given host must use the same `borg_mode_append_only` +setting. The role will fail with an error if you attempt to configure +repositories with conflicting `--append-only` settings for the same host. + +This is because the SSH `authorized_keys` entry uses a single `--append-only` +flag that applies to all repositories accessible via that key. + +```yaml +# This will FAIL - conflicting append-only settings +roles: + - role: kliwniloc.borgbackup + vars: + borg_repo_name: configs + borg_mode_append_only: false # ERROR: inconsistent + + - role: kliwniloc.borgbackup + vars: + borg_repo_name: home-data + borg_mode_append_only: true # ERROR: inconsistent +``` + +### Single SSH Key per Host\*\* + +The role generates one SSH keypair per client host. All repositories for that +host share the same SSH key for authentication to the Borg server. + +### Decryption Keys Storage Format + +Decryption keys are stored in the `decryption_keys.yml` file using the format: + +```yaml +hostname_repo_name: | + To restore key use borg key import --paper /path/to/repo + BORG PAPER KEY v1 + ... +``` + +For hosts with multiple repos, each repository has its own entry: + +- `borg-client_configs` +- `borg-client_home-data` + +### Deprovisioning Borg Repositories + +This role does not currently handle deprovisioning or removing repositories. +Deprovisioning must be done manually or via separate playbooks. + +### Removing a Repository + +To remove a specific repository (applies to both single and multi-instance setups): + +1. Stop and disable the systemd timer and service: + + ```bash + systemctl stop borg_backup@ARGUMENT.timer + systemctl disable borg_backup@ARGUMENT.timer + systemctl stop borg_backup@ARGUMENT.service + systemctl disable borg_backup@ARGUMENT.service + ``` + + Replace `ARGUMENT` with the `borg_backup_argument` value for that repository. + +2. Remove the backup script: + + ```bash + rm /usr/local/bin/run_borg_backup@ARGUMENT + ``` + +3. _(Multi-instance only)_ Edit the base backup script to remove the repository block: + + ```bash + # Edit /usr/local/bin/run_borg_backup + # Remove the ANSIBLE MANAGED BLOCK for the deleted repository + ``` + +4. _(If other repositories remain)_ Update `authorized_keys` on the Borg server + to remove the repository restriction. Edit `/opt/borg/.ssh/authorized_keys` + and remove the `--restrict-to-repository /opt/borg/REPONAME` from the + appropriate line. + + If this is the last repository for the host, remove the entire line instead. + +5. Delete the repository on the Borg server: + + ```bash + ssh borg@SERVER "borg delete /opt/borg/REPONAME" + # Or simply: ssh borg@SERVER "rm -rf /opt/borg/REPONAME" + ``` + +6. Remove the decryption key entry from your `decryption_keys.yml`. + +## Deprovisioning a Complete Host + +To remove all backup configuration for a host: + +1. Stop and disable all systemd timers and services: + + ```bash + systemctl list-units --type=timer --all | grep borg_backup + # For each relevant timer: + systemctl stop borg_backup@*.timer + systemctl disable borg_backup@*.timer + ``` + +2. Remove all backup scripts: + + ```bash + rm -f /usr/local/bin/run_borg_backup* + ``` + +3. Remove the SSH key from the Borg server's `authorized_keys`: + + ```bash + # On the Borg server, edit /opt/borg/.ssh/authorized_keys + # Remove the line containing root@HOSTNAME + ``` + +4. Delete all repositories for the host on the Borg server: + + ```bash + ssh borg@SERVER "rm -rf /opt/borg/HOSTNAME" + # For multi-instance: + ssh borg@SERVER "rm -rf /opt/borg/HOSTNAME_repo1" + ssh borg@SERVER "rm -rf /opt/borg/HOSTNAME_repo2" + ``` + +5. Remove all decryption key entries for the host from your + `decryption_keys.yml`. + +## Dependencies None. -License -------- +## License MIT |