# SPDX-FileCopyrightText: 2020-2024 Simon Bruder # # SPDX-License-Identifier: AGPL-3.0-or-later { config, lib, pkgs, ... }: let cfg = config.sbruder.restic; sftpTarget = "u313368-sub4@u313368-sub4.your-storagebox.de"; sftpPort = 23; repository = "sftp://${sftpTarget}:${toString sftpPort}/personal"; mkPruneConfig = { tag, timerConfig, opts }: { inherit repository timerConfig; passwordFile = config.sops.secrets.restic-password.path; paths = [ ]; extraOptions = [ "-o" "sftp.command='ssh -i ${config.sops.secrets.restic-ssh-key.path} -p ${toString sftpPort} ${sftpTarget} -s sftp'" ]; pruneOpts = [ "--compression auto" "--tag ${tag}" "--verbose" ] ++ opts; }; in { imports = [ ./system.nix ./vm-image.nix ]; options.sbruder.restic = { enable = lib.mkEnableOption "restic"; authScript.enable = (lib.mkEnableOption "script to use restic as user without dealing with authentication") // { default = cfg.enable && config.sbruder.gui.enable; }; prune.enable = lib.mkEnableOption "pruning"; mirror.backblaze.enable = lib.mkEnableOption "mirroring to Backblaze B2"; }; config = lib.mkIf cfg.enable (lib.mkMerge [ { sops.secrets = { restic-password = { }; restic-repository = { }; }; } (lib.mkIf cfg.authScript.enable { environment.systemPackages = [ (pkgs.writeShellScriptBin "restic-auth" '' ${pkgs.restic}/bin/restic \ --password-command="pass data/backup/restic-nixos" \ --repo "${repository}" \ $@ '') ]; }) (lib.mkIf cfg.prune.enable { sops.secrets.restic-ssh-key = { sopsFile = ../../machines/${config.networking.hostName}/secrets.yaml; }; services.restic.backups = { system-prune = mkPruneConfig { tag = "system"; timerConfig = { OnCalendar = "*-1/2-07 03:00:00"; RandomizedDelaySec = "4h"; }; opts = [ "--keep-daily 7" "--keep-monthly 12" "--keep-weekly 5" "--keep-yearly 10" ]; }; vm-image-prune = mkPruneConfig { tag = "vm-image"; timerConfig = { OnCalendar = "06:00"; RandomizedDelaySec = "1h"; }; opts = [ "--keep-last 1" ]; }; }; }) (lib.mkIf cfg.mirror.backblaze.enable { sops.secrets = { restic-ssh-key.sopsFile = ../../machines/${config.networking.hostName}/secrets.yaml; restic-mirror-backblaze-env.sopsFile = ../../machines/${config.networking.hostName}/secrets.yaml; }; systemd.services.restic-mirror-backblaze = { wants = [ "network-online.target" ]; after = [ "network-online.target" ]; serviceConfig = { ExecStart = "${pkgs.rclone}/bin/rclone --config /dev/null sync :sftp,user=u313368-sub4,host=u313368-sub4.your-storagebox.de,port=23,key_file=$CREDENTIALS_DIRECTORY/ssh-key: :b2:sbruder-restic"; EnvironmentFile = config.sops.secrets.restic-mirror-backblaze-env.path; LoadCredential = "ssh-key:${config.sops.secrets.restic-ssh-key.path}"; DynamicUser = true; CapabilityBoundingSet = null; LockPersonality = true; MemoryDenyWriteExecute = true; PrivateDevices = true; PrivateUsers = true; ProtectClock = true; ProtectControlGroups = true; ProtectHome = true; ProtectHostname = true; ProtectKernelLogs = true; ProtectKernelModules = true; ProtectKernelTunables = true; ProtectProc = "noaccess"; RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; RestrictNamespaces = true; RestrictRealtime = true; SystemCallArchitectures = "native"; SystemCallFilter = "@system-service"; }; }; systemd.timers.restic-mirror-backblaze = { wantedBy = [ "timers.target" ]; timerConfig = { OnCalendar = "hourly"; RandomizedDelaySec = "15min"; }; }; }) ]); }