backups: Switch to hetzner storage box

This commit is contained in:
Tristan Daniël Maat 2024-03-18 05:05:54 +01:00
parent f43f8742d9
commit c161eeb056
Signed by: tlater
GPG key ID: 49670FD774E43268
3 changed files with 63 additions and 29 deletions

View file

@ -24,6 +24,24 @@
inherit name text; inherit name text;
runtimeInputs = packages; runtimeInputs = packages;
}); });
# *NOT* a TOML file, for some reason quotes are interpreted
# *literally
rcloneConfig = pkgs.writeText "rclone.conf" ''
[storagebox]
type = sftp
user = u395933
host = u395933.your-storagebox.de
port = 23
key_file = ${config.sops.secrets."restic/storagebox-ssh-key".path}
shell_type = unix
'';
resticEnv = {
RESTIC_PASSWORD_FILE = config.sops.secrets."restic/storagebox-backups".path;
RESTIC_REPOSITORY = "rclone:storagebox:backups";
RCLONE_CONFIG = rcloneConfig;
};
in { in {
options = { options = {
services.backups = lib.mkOption { services.backups = lib.mkOption {
@ -120,13 +138,11 @@ in {
# Doesn't hurt to finish the ongoing prune # Doesn't hurt to finish the ongoing prune
restartIfChanged = false; restartIfChanged = false;
environment = { environment = resticEnv;
RESTIC_PASSWORD_FILE = config.sops.secrets."restic/local-backups".path;
RESTIC_REPOSITORY = "/var/lib/backups/";
RESTIC_CACHE_DIR = "%C/restic-prune";
};
path = with pkgs; [ path = with pkgs; [
openssh
rclone
restic restic
]; ];
@ -145,11 +161,6 @@ in {
CacheDirectory = "restic-prune"; CacheDirectory = "restic-prune";
CacheDirectoryMode = "0700"; CacheDirectoryMode = "0700";
ReadWritePaths = "/var/lib/backups/";
# Ensure we don't leave behind any files with the
# temporary UID of this service.
ExecStopPost = "+${pkgs.coreutils}/bin/chown -R root:backup /var/lib/backups/";
}; };
}; };
} }
@ -158,17 +169,24 @@ in {
# Don't want to restart mid-backup # Don't want to restart mid-backup
restartIfChanged = false; restartIfChanged = false;
environment = { environment =
resticEnv
// {
RESTIC_CACHE_DIR = "%C/backup-${name}"; RESTIC_CACHE_DIR = "%C/backup-${name}";
RESTIC_PASSWORD_FILE = config.sops.secrets."restic/local-backups".path; };
path = with pkgs; [
coreutils
openssh
rclone
restic
];
# TODO(tlater): If I ever add more than one repo, service # TODO(tlater): If I ever add more than one repo, service
# shutdown/restarting will potentially break if multiple # shutdown/restarting will potentially break if multiple
# backups for the same service overlap. A more clever # backups for the same service overlap. A more clever
# sentinel file with reference counts would probably solve # sentinel file with reference counts would probably solve
# this. # this.
RESTIC_REPOSITORY = "/var/lib/backups/";
};
serviceConfig = { serviceConfig = {
User = backup.user; User = backup.user;
Group = "backup"; Group = "backup";
@ -183,8 +201,8 @@ in {
ExecStartPre = ExecStartPre =
map (service: "+${mkShutdownScript service}") backup.pauseServices map (service: "+${mkShutdownScript service}") backup.pauseServices
++ singleton (writeScript "backup-${name}-repo-init" [pkgs.restic pkgs.coreutils] '' ++ singleton (writeScript "backup-${name}-repo-init" [] ''
restic snapshots || (restic init && chmod -R g+rwx "$RESTIC_REPOSITORY"/*) restic snapshots || restic init
'') '')
++ optional (backup.preparation.text != null) ++ optional (backup.preparation.text != null)
(writeScript "backup-${name}-prepare" backup.preparation.packages backup.preparation.text); (writeScript "backup-${name}-prepare" backup.preparation.packages backup.preparation.text);
@ -220,10 +238,14 @@ in {
}) })
config.services.backups; config.services.backups;
users.groups.backup = {}; users = {
# This user is only used to own the ssh key, because apparently
systemd.tmpfiles.rules = [ # the ssh client checks file permissions and is stuck in 1980.
"d /var/lib/backups/ 0770 root backup" users.backup = {
]; group = "backup";
isSystemUser = true;
};
groups.backup = {};
};
}; };
} }

View file

@ -36,6 +36,16 @@
group = "backup"; group = "backup";
mode = "0440"; mode = "0440";
}; };
"restic/storagebox-backups" = {
owner = "root";
group = "backup";
mode = "0440";
};
"restic/storagebox-ssh-key" = {
owner = "backup";
group = "backup";
mode = "0040";
};
# Steam # Steam
"steam/tlater" = {}; "steam/tlater" = {};

View file

@ -14,6 +14,8 @@ wireguard:
server-key: ENC[AES256_GCM,data:mXb7ZznJHf5CgV8rI4uzPBATMRbmd7LimgtCkQM9kAjbIaGwUBqJZBN3fXs=,iv:3Po1Orinzov9rnEm9cLzgJY1PeD+5Jl9115MriABHh8=,tag:E/2CjDO1JCvJzxCnqKcNyw==,type:str] server-key: ENC[AES256_GCM,data:mXb7ZznJHf5CgV8rI4uzPBATMRbmd7LimgtCkQM9kAjbIaGwUBqJZBN3fXs=,iv:3Po1Orinzov9rnEm9cLzgJY1PeD+5Jl9115MriABHh8=,tag:E/2CjDO1JCvJzxCnqKcNyw==,type:str]
restic: restic:
local-backups: ENC[AES256_GCM,data:NLNVlR9G9bLSZOkMoPvkbBbAZlKkmiUbdWHOFDnaefuy9wNLH53ctOIyS0rSsQLaJCSBTpgPSWIIXUSuzoK/eA==,iv:DzuujmyJJP4GiE5z7KOOGUEzUgOwmtf/7UYhwkyLe9g=,tag:cElFhpVC7S6HYlB6UyN7PQ==,type:str] local-backups: ENC[AES256_GCM,data:NLNVlR9G9bLSZOkMoPvkbBbAZlKkmiUbdWHOFDnaefuy9wNLH53ctOIyS0rSsQLaJCSBTpgPSWIIXUSuzoK/eA==,iv:DzuujmyJJP4GiE5z7KOOGUEzUgOwmtf/7UYhwkyLe9g=,tag:cElFhpVC7S6HYlB6UyN7PQ==,type:str]
storagebox-backups: ENC[AES256_GCM,data:UyT8jCkKlfYJXjWLI9MbYfeVhY5d89N3aj1Olj54/aBOP3gwcrx6gU56Pwa1xKZ3lR13AVs/b4wF9sbvP7Kqqg==,iv:0HM+DgH4iCiWpjRvAYCFQGEy4xIBQwAM+PkkzOsizw0=,tag:jbrqo1In2O4jVM5e7fjOzg==,type:str]
storagebox-ssh-key: ENC[AES256_GCM,data:7aYlKX7I8Bsur3nm4nV9eSW3lmIxBCeCUMbPX3qgcotPbyPYaUqD3MOCnFRepajYkFXAgMX4jknqLfoO9xYc4bavDFjOY8Ww/KmLay7ces6tDnkK6tTRxcNRPUBqEzaFiPNsZc2UwHnmHOF0rKvQusvhCOplYao3xxz5McTHC7IEriUApSNudWCg3qGbyAmxkGEw7tRfh6IiUXEOFeaXDZd78dWZlWIIeospmA1hcVhkLGrjMmoikt/YANHUpWPbd+B9E6x+s2eIzFdvztRjarBluWPZuX981b+hcOm1/+HY/tJ/jzgyVbX1rjmdgZ9jZqdKO/vkOkijHWXlwpQ0QJ2s8p5MURPGRsC7W5jfmGbVKrubxfQC2mSJRJgBaj1wX3yI4GbfCXNdbpseAMy7t8OmN/iMN57lGnD3uX8CWWD327PIWp3SgwMDIZtJRlMBu3vMUrBdNnrrlYoLgf821tX7JWW6L5g1EK/bcBZqZZ/6rE+Q9fLiJHTsj2lyTzQZRLKsn0YePlcIMOWHO2CG/aWrfycdSKKjaKGG,iv:OVnEIMFB4h/EQ8zV3XOpVXLDrV5t4roNYDFQz99m4sQ=,tag:mKWF12uD1TLla/MoJs2zNg==,type:str]
turn: turn:
env: ENC[AES256_GCM,data:kt5nhVo9pb/ZbPUEcqSYXxN9YMgQKnFb5VRfFFS/qoIaJ73uD2fuJKqcxAyVRrdLqnSAWSQBgTgunBzdP7xqLAK2qt8DYAQWHkIe9uxFbSXZpdmw,iv:9lq6SFwTFN4GGm6gPiJpUMasMdnHVF6XLGYrsyG3kjU=,tag:428Qf9DOiiHt/Wjb188b8g==,type:str] env: ENC[AES256_GCM,data:kt5nhVo9pb/ZbPUEcqSYXxN9YMgQKnFb5VRfFFS/qoIaJ73uD2fuJKqcxAyVRrdLqnSAWSQBgTgunBzdP7xqLAK2qt8DYAQWHkIe9uxFbSXZpdmw,iv:9lq6SFwTFN4GGm6gPiJpUMasMdnHVF6XLGYrsyG3kjU=,tag:428Qf9DOiiHt/Wjb188b8g==,type:str]
secret: ENC[AES256_GCM,data:si7ee6Xfhdgdyzbp6aQpF7pz3TmTBb7iQ82lRPVXNDg9JfHI+lbmgAsSnRLX5qMCA6P9R045sSMosqidL8QwRg==,iv:SrhpZKK8D45yxCEfDb9P3TwtA14+qEI+wcRqcN/a6pw=,tag:PiwV+mOL9xHJgJft6sc61g==,type:str] secret: ENC[AES256_GCM,data:si7ee6Xfhdgdyzbp6aQpF7pz3TmTBb7iQ82lRPVXNDg9JfHI+lbmgAsSnRLX5qMCA6P9R045sSMosqidL8QwRg==,iv:SrhpZKK8D45yxCEfDb9P3TwtA14+qEI+wcRqcN/a6pw=,tag:PiwV+mOL9xHJgJft6sc61g==,type:str]
@ -26,8 +28,8 @@ sops:
azure_kv: [] azure_kv: []
hc_vault: [] hc_vault: []
age: [] age: []
lastmodified: "2024-03-18T04:04:56Z" lastmodified: "2024-03-18T04:05:08Z"
mac: ENC[AES256_GCM,data:qIbgeaaFQXYacURO9EVfvtvvlUP0j7FMJuh9CIRbzQCyoSedibt1yhGIMQk2ERUliPb8OEuG4QPZ8rled/DmP1BHrUNTYFnRcagtPOnIE+0b9TuAVrj+vTWVl4MvQKMt9i/DQJsWAZVuaP8isDuZ77mVnlj1V8F+1MvXtL0+ZVM=,iv:0mKgiXjWrmNmuXLEsPYBMWSZvD9qrHDHEkSPAm9GCY4=,tag:ZM32r6kbsi4ERGFERzTRpA==,type:str] mac: ENC[AES256_GCM,data:/v/XRBizRUn8UR1HOIaKrY11/5I8RmsctmxXg0wcCXO983YgcGYTEqfXOSRJzkh/MOjB0c8jpdfE7tyqYgB2iYjm+HmRFVsGNB484e+3ukAMsxz4CTz26RWC/LEemQeBOa5RB3rrPXXo1LrJCBN9Y+T/PVgO2xshUSxyhRFQmMA=,iv:km1m8k/vrCVT8ugvqAZNORLu0NSW66B58btH5k4e//Y=,tag:RZXviobM03IQXN1FwDUlVA==,type:str]
pgp: pgp:
- created_at: "2024-03-18T04:02:00Z" - created_at: "2024-03-18T04:02:00Z"
enc: |- enc: |-