From 207a682045074af8cd0ff4af24c47d7963540e48 Mon Sep 17 00:00:00 2001 From: Gabriel Arazas Date: Sat, 19 Feb 2022 16:58:08 +0800 Subject: [PATCH] backup-archive: switch to NixOS borg module While Borgmatic is great, the NixOS module does have easier configuration for various use cases such as backups in removable devices. To make this possible in Borgmatic, you have to go through some loops. Borgmatic does have easier way of indicating paths. However, in recent versions of Borg, they have the experimental feature of indicate both include and exclude through patterns which is close enough. Also, because of this, we'll be deprecating the custom borgmatic service at this point. It'll be removed once all of my NixOS-related backup setups are not using it. --- .../nixos/hardware-setup/backup-archive.nix | 43 ------- .../hardware-setup/backup-archive/README.adoc | 5 + .../backup-archive/borg-ssh-key.pub | 1 + .../hardware-setup/backup-archive/default.nix | 114 ++++++++++++++++++ secrets/archive/borg-patterns | Bin 0 -> 1831 bytes secrets/archive/borg-patterns-local | Bin 0 -> 2166 bytes secrets/archive/borgmatic.json | Bin 1773 -> 0 bytes secrets/archive/key | Bin 0 -> 1680 bytes secrets/archive/password | Bin 518 -> 835 bytes secrets/secrets.nix | 10 +- 10 files changed, 128 insertions(+), 45 deletions(-) delete mode 100644 modules/nixos/hardware-setup/backup-archive.nix create mode 100644 modules/nixos/hardware-setup/backup-archive/README.adoc create mode 100644 modules/nixos/hardware-setup/backup-archive/borg-ssh-key.pub create mode 100644 modules/nixos/hardware-setup/backup-archive/default.nix create mode 100644 secrets/archive/borg-patterns create mode 100644 secrets/archive/borg-patterns-local delete mode 100644 secrets/archive/borgmatic.json create mode 100644 secrets/archive/key diff --git a/modules/nixos/hardware-setup/backup-archive.nix b/modules/nixos/hardware-setup/backup-archive.nix deleted file mode 100644 index 6374d621..00000000 --- a/modules/nixos/hardware-setup/backup-archive.nix +++ /dev/null @@ -1,43 +0,0 @@ -# This is my external hard drive. -{ config, options, lib, pkgs, ... }: - -# TODO: Make this a generic service. -# There are multiple external storage drives now. -let cfg = config.hardware-setup.backup-archive; -in { - options.hardware-setup.backup-archive.enable = lib.mkEnableOption - "external hard drive and automated backup service with BorgBackup"; - - config = lib.mkIf cfg.enable { - assertions = [{ - assertion = config.profiles.agenix.enable; - message = "Agenix module is not enabled."; - }]; - - age.secrets.external-backup-borgmatic-settings.file = - lib.getSecret "archive/borgmatic.json"; - - fileSystems."/mnt/external-storage" = { - device = "/dev/disk/by-uuid/665A391C5A38EB07"; - fsType = "ntfs"; - noCheck = true; - options = [ - "nofail" - "noauto" - "user" - - # See systemd.mount.5 and systemd.automount.5 manual page for more - # details. - "x-systemd.automount" - "x-systemd.device-timeout=2" - "x-systemd.idle-timeout=2" - ]; - }; - - # This uses the custom borgmatic NixOS service. - services.borgmatic-fds.jobs.external-storage = { - startAt = "04/6:00:00"; - configPath = config.age.secrets.external-backup-borgmatic-settings.path; - }; - }; -} diff --git a/modules/nixos/hardware-setup/backup-archive/README.adoc b/modules/nixos/hardware-setup/backup-archive/README.adoc new file mode 100644 index 00000000..0003808b --- /dev/null +++ b/modules/nixos/hardware-setup/backup-archive/README.adoc @@ -0,0 +1,5 @@ += BorgBackup setup for the archive + +It's a NixOS configuration that configures my basic BorgBackup backup battlestation for my local archive. +Not all of the required files are here (i.e., the SSH key used for Borg). +In other words, if it's not yours, don't attempt to activate this setup. diff --git a/modules/nixos/hardware-setup/backup-archive/borg-ssh-key.pub b/modules/nixos/hardware-setup/backup-archive/borg-ssh-key.pub new file mode 100644 index 00000000..10c413ac --- /dev/null +++ b/modules/nixos/hardware-setup/backup-archive/borg-ssh-key.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ1IdisweU/qW+Np36K1WoR+RsPSyG6JcLNp96m1rDWx foo-dogsquared@ni diff --git a/modules/nixos/hardware-setup/backup-archive/default.nix b/modules/nixos/hardware-setup/backup-archive/default.nix new file mode 100644 index 00000000..67209506 --- /dev/null +++ b/modules/nixos/hardware-setup/backup-archive/default.nix @@ -0,0 +1,114 @@ +# This is my external hard drive with the backup setup with borg. +{ config, options, lib, pkgs, ... }: + +let + cfg = config.hardware-setup.backup-archive; + + borgJobCommonSetting = { patterns ? [ ] }: { + compression = "zstd,9"; + dateFormat = "+%F-%H-%M-%S-%z"; + doInit = true; + encryption = { + mode = "repokey-blake2"; + passCommand = "cat ${config.age.secrets.borg-password.path}"; + }; + extraCreateArgs = lib.concatStringsSep " " + (builtins.map (patternFile: "--patterns-from ${patternFile}") patterns); + extraInitArgs = "--make-parent-dirs"; + + # We're emptying them since we're specifying them all through the patterns file. + paths = [ ]; + + persistentTimer = true; + preHook = '' + extraCreateArgs="$extraCreateArgs --exclude-if-present .nobackup" + extraCreateArgs="$extraCreateArgs --stats" + ''; + prune = { + keep = { + within = "1d"; + hourly = 8; + daily = 30; + weekly = 4; + monthly = 6; + yearly = 3; + }; + }; + }; + +in { + options.hardware-setup.backup-archive.enable = + lib.mkEnableOption "backup setup with BorgBackup"; + + config = lib.mkIf cfg.enable { + assertions = [{ + assertion = config.profiles.agenix.enable; + message = '' + Agenix module is not enabled. This is for the borgmatic configuration + we're using. + ''; + }]; + + age.secrets.borg-password.file = lib.getSecret "archive/password"; + age.secrets.borg-patterns.file = lib.getSecret "archive/borg-patterns"; + age.secrets.borg-patterns-local.file = + lib.getSecret "archive/borg-patterns-local"; + age.secrets.borg-ssh-key.file = lib.getSecret "archive/borg-ssh-key"; + + fileSystems."/mnt/external-storage" = { + device = "/dev/disk/by-uuid/665A391C5A38EB07"; + fsType = "ntfs"; + noCheck = true; + options = [ + "nofail" + "noauto" + "user" + + # See systemd.mount.5 and systemd.automount.5 manual page for more + # details. + "x-systemd.automount" + "x-systemd.device-timeout=2" + "x-systemd.idle-timeout=2" + ]; + }; + + services.borgbackup.jobs = { + local = borgJobCommonSetting { + patterns = [ + config.age.secrets.borg-patterns-local.path + config.age.secrets.borg-patterns.path + ]; + } // { + doInit = true; + repo = "/archives/"; + startAt = "04/5:00:00"; + }; + + local-archive = borgJobCommonSetting { + patterns = [ + config.age.secrets.borg-patterns-local.path + config.age.secrets.borg-patterns.path + ]; + } // { + doInit = false; + removableDevice = true; + repo = "/mnt/external-storage/backups"; + startAt = "daily"; + }; + + remote-borgbase = borgJobCommonSetting { + patterns = [ config.age.secrets.borg-patterns.path ]; + } // { + doInit = false; + repo = "m9s7d92s@m9s7d92s.repo.borgbase.com:repo"; + startAt = "daily"; + environment.BORG_RSH = "ssh -i ${config.age.secrets.borg-ssh-key.path}"; + }; + }; + + programs.ssh.extraConfig = '' + Host *.repo.borgbase.com + IdentityFile ${config.age.secrets.borg-ssh-key.path} + ''; + }; +} diff --git a/secrets/archive/borg-patterns b/secrets/archive/borg-patterns new file mode 100644 index 0000000000000000000000000000000000000000..ea77c67aabb88234de333db915b07cf2ae0112ee GIT binary patch literal 1831 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 Noy-=e)Z6Cq>0cV{6runC delta 472 zcmWmAxr)?a007_>7lmNGS`G_hF@#*^0uhsJ=GfdbIc9<=lVc{Ee>RE9SZr)W z5G=&f#$wSY5Jj=DSP;Y)&_b{g1noRfpWuV<&6zu!_b=YC3}qDw9kDg&e$r0s%=5|! z6f>K0rjk`;PQy@RG28Q~LJ3K!O*CY(Lz^6LXLwJQ*oxTc`irSY>j$x+71G+IVVXdL z(q+OF9^5>2{%DoVmNQ6a+Bobc%UyCm=whHPhQP@w64qd9Srb#=HF{))1Z@b?+HmvP znpblXuk^8{a_fmuHF+6jBa6=Qxhd2b2N3jXr>YV(j!2p&_>M0rb-d^}b_jW9;2Yrr zu-$=uaO4J_?ldkZ4oVCsSTXRtLQ#k;kr6Grl}EB65Bg;};_J)oToAeCGG+E{2})WB z8QHADw$Rtke~whIxpKLUF3NaT#mLAYLY(us2^QzMT3db6^=$=XNHF%y1%jez2e@I@ zXk}VxystZhJvanIyw6S7QjaSFI#vzf*#Eld6||6#8$t7BJFPZ8UwL@%0`&+xewLp8 zbqSvP!<@a1ynMp{MEvg`?mqp!`Ss-W=*P)iye_}$etLhrbqJq-YuUH&Mvq_o1x-Vw A?*IS* diff --git a/secrets/secrets.nix b/secrets/secrets.nix index af0d9416..7449beb9 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -1,6 +1,9 @@ let system1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG42LafAFOeh3oYz/cm6FXes0ss59/EOCXpGsYvhpI21"; + system2 = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHjRjAddjbyoM32tQhCjj8OrnqNBsXj+5D379iryupK+"; + systems = [ system1 system2 ]; user1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMclb6WPpYRoMVqCCzQcG2XQHczB6vaIEDIHqjVsyQJi"; @@ -10,7 +13,10 @@ let "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIytwsseYS6kV8ldiUV767C2Gy7okxckdDRW4aA3q/Ku"; user4 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGtn+t2D7clY1U1rzKcSCBJjNbuJzbRArEiM3soyFcnv"; + users = [ user1 user2 user3 user4 ]; in { - "archive/password".publicKeys = [ system1 user3 user4 ]; - "archive/borgmatic.json".publicKeys = [ system1 user3 user4 ]; + "archive/borg-patterns".publicKeys = users ++ systems; + "archive/borg-patterns-local".publicKeys = users ++ systems; + "archive/password".publicKeys = users ++ systems; + "archive/key".publicKeys = users ++ systems; }