feat: init backup module

This commit is contained in:
Julien Malka 2024-09-03 22:03:09 +02:00
parent 71693eaa99
commit 23fc74efa6
Signed by: Luj
GPG key ID: 6FC74C847011FD83
7 changed files with 169 additions and 0 deletions

View file

@ -57,6 +57,8 @@
};
};
services.backup.includes = [ "/var/lib/stalwart-mail/db" ];
age.secrets.stalwart-admin-hash = {
file = ../../secrets/stalwart-admin.age;
path = "/var/lib/stalwart-mail/admin-hash";

16
machines/gustave/borg.nix Normal file
View file

@ -0,0 +1,16 @@
{ pkgs, ... }:
{
users.users.borg = {
home = "/home/borg";
group = "borg";
isNormalUser = true;
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAziNbLEO9D69xUGPGEq3eXYauFuOlvhqQTwpLNKjFqs julien@tower"
];
};
users.groups.borg = { };
environment.systemPackages = with pkgs; [ borgbackup ];
}

View file

@ -9,6 +9,7 @@
./hardware.nix
./home-julien.nix
./nsd.nix
./borg.nix
];
machine.meta = {

135
modules/backup/default.nix Normal file
View file

@ -0,0 +1,135 @@
{
lib,
config,
...
}:
let
cfg = config.services.backup;
# We backup on gustave
host = "gustave.luj";
port = "45";
hostPublicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDJrHUzjPX0v2FX5gJALCjEJaUJ4sbfkv8CBWc6zm0Oe";
sshKey = config.age.secrets."borg-ssh-key".path;
secretPath = config.age.secrets."borg-encryption-secret".path;
in
{
options.services.backup =
with lib;
with types;
{
quota = mkOption {
type = nullOr str;
default = null;
example = "90G";
description = ''
Quota for the borg repository. Useful to prevent the target disk from running full and ensuring borg keeps some space to work with.
'';
};
includes = mkOption {
type = listOf path;
default = [ ];
description = ''
Paths to include in the backup.
'';
};
excludes = mkOption {
type = listOf path;
default = [ ];
description = ''
Paths to exclude in the backup.
'';
};
preHook = mkOption {
type = lines;
default = "";
description = ''
Shell commands to run before the backup.
'';
};
postHook = mkOption {
type = lines;
default = "";
description = ''
Shell commands to run after the backup.
'';
};
wantedUnits = mkOption {
type = listOf str;
default = [ ];
description = ''
List of units to require before starting the backup.
'';
};
};
config = lib.mkIf (cfg.includes != [ ]) {
age.secrets."borg-ssh-key" = {
file = ../../secrets/borg-ssh-priv.age;
owner = "root";
mode = "0600";
};
age.secrets."borg-encryption-secret".file = ../../secrets/borg-encryption-secret.age;
programs.ssh.knownHosts."${if port != 22 then "[${host}]:${port}" else host}" = {
publicKey = "${hostPublicKey}";
};
systemd.services.borgbackup-job-state = {
wants = cfg.wantedUnits;
after = cfg.wantedUnits;
};
systemd.timers.borgbackup-job-state.timerConfig = {
# Spread all backups over the day
RandomizedDelaySec = "30m";
FixedRandomDelay = true;
};
services.borgbackup.jobs.state = {
inherit (cfg) preHook postHook;
# Create the repo
doInit = true;
# Create daily backups, but prune to a reasonable amount
startAt = [ "hourly" ];
prune.keep = {
daily = 7;
weekly = 4;
monthly = 3;
};
# What to backup
paths = cfg.includes;
exclude = cfg.excludes;
# Where to backup it to
repo = "borg@gustave.luj:${config.networking.hostName}";
environment.BORG_RSH = "ssh -p ${port} -i ${sshKey}";
# Ensure we don't fill up the destination disk
extraInitArgs = lib.optionalString (cfg.quota != null) "--storage-quota ${cfg.quota}";
# Authenticated & encrypted, key resides in the repository
encryption = {
mode = "repokey-blake2";
passCommand = "cat ${secretPath}";
};
# Reduce the backup size
compression = "auto,zstd";
# Show summary detailing data usage once completed
extraCreateArgs = "--stats";
};
};
}

View file

@ -0,0 +1,7 @@
age-encryption.org/v1
-> ssh-ed25519 81O5Zw WCIdHHk7nehDc0n0u4Df17oVi2OIg+WT2FxM9uUMBTM
ZufMHxTCazJycMSqHYKiGoRQUR+mPwXi/xsZQxIkjUM
-> ssh-ed25519 AqX2tg kYJ4UZixeb7WjkXzdtS6Bgm0JQBLNUdONJbjsTtkaQM
2H4qDAAlSJ3TNOF/UFOBlNnyAy1BclMvTv58fMJctuo
--- s3weoMhZdAdfJ4rTU5E3x56PhlM6N3JfbdJOtQFjACM
FCË"<22>a¤^Cð2bÓ=ÂbgÝ$M éA”¤~Áð·T<05>4`ýöÚ §'žÚý¶.¶röPŸ¿ˆ®eÓÔìþ¡ÍÎCã

BIN
secrets/borg-ssh-priv.age Normal file

Binary file not shown.

View file

@ -81,4 +81,12 @@ in
tower
];
"arkheon-token.age".publicKeys = servers;
"borg-ssh-priv.age".publicKeys = [
akhaten
tower
];
"borg-encryption-secret.age".publicKeys = [
akhaten
tower
];
}