From 4e78d87bde570efebc6fe23af026a5c16062dc28 Mon Sep 17 00:00:00 2001 From: Simon Bruder Date: Thu, 25 Aug 2022 17:18:43 +0200 Subject: [PATCH] restic: Use storage box and restic-rest-server While this setup complicates things, it also should protect me against (malicious) deletion of old backups. --- machines/fuuko/secrets.yaml | 5 ++- machines/vueko/configuration.nix | 1 + machines/vueko/secrets.yaml | 6 ++- machines/vueko/services/restic.nix | 61 ++++++++++++++++++++++++++++++ modules/restic/system.nix | 19 +++++++--- secrets.yaml | 6 +-- 6 files changed, 85 insertions(+), 13 deletions(-) create mode 100644 machines/vueko/services/restic.nix diff --git a/machines/fuuko/secrets.yaml b/machines/fuuko/secrets.yaml index 2663b00..8ac2d2f 100644 --- a/machines/fuuko/secrets.yaml +++ b/machines/fuuko/secrets.yaml @@ -1,3 +1,4 @@ +restic-ssh-key: ENC[AES256_GCM,data:wA7JCg6Y900s6+1JoevMzbr6fKRN6jbfUuX166VS+TUFhFbn0npz5gKkAQpC8h1io1WaSCPJkJMzr+viOLlnVwqe8zFGm3ZJlKSEqKKK+CatZ95+zKACOZuBAC/2E6rep6JnL/C3/gKMKibVmAL+9TkTX6nA83xwhM65JPLN/+bP29bq0Cr2FopgZgNPQjb6ANB4POy+MUktet63DZ4dJwKvndiCRg4EMLIOqFopbQei6Pxc1F/lC3yBu71YgB4TSGQp/6tXjfFOuXQpI0nFrZCmLYcW03ZqOBQbKg3w4rwlqtnl25/23jpT0kqWp99wHUGMCib5+iywPUMSNDwAsz0fq04JGpTEM9cuxkLWZVfCpguNlgaiwCObyJkA2CHXlIn6KYsDOa6U/Uy9mNRPae52j/E+JdLQycOwT5+n78j0vqtvS69blUC/E7j2IWe17SI8JVCiYFbZXPqVm43jdEiQ9jU4gXMsu6NKppnBhFSrMVUHScS3gR/xnTfrabrr2FWJwIOjdGdJb4pr+nfZ,iv:ow+hzt5YGGD0FDvN+XkZtW74k4mwW+6HqWZMtOwAWDg=,tag:HXogIkcSTq6Ep4M2MXEMew==,type:str] wg-home-private-key: ENC[AES256_GCM,data:6l3CgB4qCsPuyYOWuwU2vNiEeC0D1wl6yZvXGGYVsZfYvdPjRz8j5yV7ekQ=,iv:slB/qr+cxi8r7cnTuZAd8CuzWVnvp24Li6A/AnZaFzo=,tag:ynh1Z2+IELAJcgBbHwFC0A==,type:str] wg-qbittorrent-private-key: ENC[AES256_GCM,data:9sjqTCMXqN0oWS95RQOmfLK0/2dH6V4Rs2LX8ydnYl+7zR55PG5pW3kROH8=,iv:m+4xKthKNCQBOEP9ExOHY5Dg3i+yTgREwrAci4zhqUk=,tag:L0vnwyiGOAoarr7FZFE91A==,type:str] sops: @@ -6,8 +7,8 @@ sops: azure_kv: [] hc_vault: [] age: [] - lastmodified: "2022-06-09T21:32:26Z" - mac: ENC[AES256_GCM,data:96T1CeXtmu98I0pHrg3tZ7LNOk2O9NkIzGXm0HfbPa2D0JJa5oNpkaW3pxY9mF+CNz3zBb8RaDLoeFPhcJ7i5eGtGwL/yqAKJsoZZ2VmBUbgjKhYQMP2A4vxk2NCKjgeicAUjXzkbyhPQP411hGNuZWjjcQtUZRa8ErSXZ4LHEw=,iv:SJLSvQCnIMiPJh4ysUOQLv1O0cySFcT2Z+vfrq2E3C4=,tag:wT4t23H7UG2qZR//j3biOQ==,type:str] + lastmodified: "2022-08-25T14:39:59Z" + mac: ENC[AES256_GCM,data:3Z1f1DobOU1RHT25TM0FI9fUUtZxrFhKeGTmXaxC+vDE2j9url28XVDesiMmj2Vairapk5krf31hV47K62Q+YvVyYrNw0a3hn+v7/2kBrbdU1SqZNajVwb7/3F5YKYNcsF/tHLClJrwYOIrSWBWsky7gim2ohItm6eKuG9ED+wg=,iv:zqMw8Q4c3EOI9AEUjx148/X2VTF1UMTdacgjxyYuiyk=,tag:H72VN77/SzHMBqys8ZONGw==,type:str] pgp: - created_at: "2021-04-06T11:27:21Z" enc: | diff --git a/machines/vueko/configuration.nix b/machines/vueko/configuration.nix index d0f7fec..01dc226 100644 --- a/machines/vueko/configuration.nix +++ b/machines/vueko/configuration.nix @@ -6,6 +6,7 @@ ../../modules ./services/media.nix + ./services/restic.nix ]; sbruder = { diff --git a/machines/vueko/secrets.yaml b/machines/vueko/secrets.yaml index 2c28037..071dce5 100644 --- a/machines/vueko/secrets.yaml +++ b/machines/vueko/secrets.yaml @@ -1,13 +1,15 @@ wg-home-private-key: ENC[AES256_GCM,data:/RHNF6Zw6CTWa9ahUhGWRfkR8KIj+HdqUIojA1w6HQBFbZ/+Vo+CcYTYO5I=,iv:2sDH1P3VRjmLw6Ilkq0rw/hossHrNWP5uRvX9yr5fLE=,tag:KIT5GCfXuhg6RjA8+Nmtnw==,type:str] media-sb-proxy-auth: ENC[AES256_GCM,data:hYKmrpIMotRaf47bt8LSyXT2FEUHu26SLtKCt2zh/ziFtH2empD2NTlpf+l5Q6VHW1r1RUyE0KdmNM4nZRumJ/NuP3Aa9ErGTI3qozjQk9Kl,iv:pLYZv8X76XQGBd36PjQPkiUNPR08PkIKuTqJ+mmaMcw=,tag:3PMAO3lOfT+y+1s8yJLvhA==,type:str] +restic-rclone-ssh-key: ENC[AES256_GCM,data:IOVEsH7DcrX4Lcb5Vv8Qxshyoc5jOudRbLnc+iZ2aL05wGo2aUbtDusPrZ9QeIhw/09UAdJUXW6HudtVWPnmL9UJVr1Sm+JYMUS50QCE4DcX0kVV9u5DXiESwfJ+WHAQimShQEvjJ6SCgNBoZNTHcsr95H9G6Tn0XyAM3VYcm69+rzzBN3E0ohb06SOV6JOvtgLLN1BVB+dt6p1UlBuWt5XNc6YPd2T4Erf4FkiPHVneg66hcFFFMX453Qzv/z14aKM0NlEMhMKqLTGt0fsIlwoX4Wdq1KDWGtsf6oVZygCbGiOi57Sy5PjUDys8FmCdkV5PjnRQc4c0E1ynHk79stwbQzqJr/RVe2Tmo3KFgoOOrWYENXztQ+rewYnhsJKF2eVVMtBKf9CAbcrw7UTuVnyxzb9K/NpebAugo00w+4M95lv2Y/MxKf85xdCqGAtfgCJ9eOH3ZW2MUx4m9e5TrBzcS/ewyeXvzd69SBknyvdQ7GXqht5Nf6Ed2a1zj3LUYiLy3H/0/GLZVmoAlJ86,iv:rwqEopfSJJ66yPKgrbVD8Id/CWCfIQi6FLByJZJbJUI=,tag:71J3OFgGNeJUyIZCNrFbqw==,type:str] +restic-htpasswd: ENC[AES256_GCM,data:hqZxZ1KXDUqaJ4rsz58l6Jqmhmatm65aZx7aEBlDyBUm3NQFNjyjZlK570lfOdOfJhj0ZZPFRiCENBHTpMt8sdjvsQ4M+g==,iv:Sw/7MBrOy0nIHjF+v8qP7cF1vwfwWiCicl4yl0tOBJc=,tag:3RFktMbo/oETuqVzvjzGwA==,type:str] sops: kms: [] gcp_kms: [] azure_kv: [] hc_vault: [] age: [] - lastmodified: "2022-08-21T15:55:45Z" - mac: ENC[AES256_GCM,data:qtMmv0BfPmgoLrlIxfED7vXoIU+lU6SOXGsh1EPLQUjSnDEaWJpj3gDTEWVskgwHoBdt+jFaCw1j+nI36+6F+KQDwD58sV1/Oiw/J7J5QwePGeU1iyXmq/JwPNU4wYfe3O15tNRXkpFfv4tV/rdeFqbbh0++V4nQ5ZnDE0MlUJA=,iv:NOOSGauhsWhMrMXL81syzSpcvgGk4LVKwQ840/78MWg=,tag:GbMzBSlcSvMRJojGy6/0BA==,type:str] + lastmodified: "2022-08-25T14:16:49Z" + mac: ENC[AES256_GCM,data:e/9RK7hHX0Jft/27J5ImLxeYS9w7gdLM06/yoHOsgIdeKAzTqCUxVxyAK2JCmTA65iHybY0k8UkrjO73eC4fLUNjNOUIfWJPnEbgs4Ms0BSzRKHoEQ+OZesnaTpzg3BC8z+Y7Uq3PJ/btEFyap1sY4DR84q0oRU4og4/C+1lL7c=,iv:T8EM0HzzxIqdrl8rgfnc0edkr7QpZJWevZxHzo7HwVc=,tag:eS3bX6D0VL7HVFcXFLdk6Q==,type:str] pgp: - created_at: "2021-04-06T11:13:54Z" enc: | diff --git a/machines/vueko/services/restic.nix b/machines/vueko/services/restic.nix new file mode 100644 index 0000000..2c58ec4 --- /dev/null +++ b/machines/vueko/services/restic.nix @@ -0,0 +1,61 @@ +{ config, pkgs, ... }: + +{ + sops.secrets = { + restic-rclone-ssh-key = { + sopsFile = ../secrets.yaml; + owner = "restic-rclone"; + }; + restic-htpasswd = { + sopsFile = ../secrets.yaml; + owner = "restic-rclone"; + }; + }; + + users.users.restic-rclone = { + isSystemUser = true; + group = "restic-rclone"; + }; + users.groups.restic-rclone = { }; + + systemd.services."rclone-restic-server" = { + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + User = "restic-rclone"; + SupplementaryGroups = [ "keys" ]; + ExecStart = "${pkgs.rclone}/bin/rclone serve restic :sftp,user=u313368-sub4,host=u313368-sub4.your-storagebox.de,port=23,key_file=${config.sops.secrets.restic-rclone-ssh-key.path}: --private-repos --htpasswd ${config.sops.secrets.restic-htpasswd.path} --append-only"; + Restart = "on-failure"; + + CapabilityBoundingSet = null; + LockPersonality = true; + MemoryDenyWriteExecute = true; + PrivateDevices = true; + PrivateUsers = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + SystemCallFilter = "@system-service"; + }; + }; + + services.nginx.virtualHosts."restic.sbruder.de" = { + enableACME = true; + forceSSL = true; + + locations."/".proxyPass = "http://127.0.0.1:8080/"; + + extraConfig = '' + client_max_body_size 20M; + ''; + }; +} diff --git a/modules/restic/system.nix b/modules/restic/system.nix index d3fd470..697f8b6 100644 --- a/modules/restic/system.nix +++ b/modules/restic/system.nix @@ -2,7 +2,9 @@ let cfg = config.sbruder.restic.system; - repository = "s3:https://s3.eu-central-1.wasabisys.com/sbruder-restic"; + sftpTarget = "u313368-sub4@u313368-sub4.your-storagebox.de"; + sftpPort = 23; + repository = "sftp://${sftpTarget}:${toString sftpPort}/personal"; excludes = [ # Caches "/home/*/Downloads/" @@ -31,7 +33,6 @@ let # script to use restic as user without dealing with authentication authScript = pkgs.writeShellScriptBin "restic-auth" '' - . <(pass data/wasabi/restic-nixos | sed 's/^/export /') ${pkgs.restic}/bin/restic \ --password-command="pass data/backup/restic-nixos" \ --repo "${repository}" \ @@ -67,14 +68,17 @@ in config = lib.mkIf cfg.enable { sops.secrets = { restic-password = { }; - restic-s3 = { }; + restic-repository = { }; + } // lib.optionalAttrs cfg.prune { + restic-ssh-key = { + sopsFile = ../../machines/${config.networking.hostName}/secrets.yaml; + }; }; services.restic.backups.system = { - inherit repository; inherit (cfg) timerConfig; + repositoryFile = config.sops.secrets.restic-repository.path; passwordFile = config.sops.secrets.restic-password.path; - environmentFile = config.sops.secrets.restic-s3.path; paths = [ "/etc" "/home" @@ -99,12 +103,15 @@ in services.restic.backups.system-prune = lib.mkIf cfg.prune { inherit repository; passwordFile = config.sops.secrets.restic-password.path; - environmentFile = config.sops.secrets.restic-s3.path; timerConfig = { OnCalendar = "*-1/2-07 03:00:00"; RandomizedDelaySec = "4h"; }; paths = [ ]; + extraOptions = [ + "-o" + "sftp.command='ssh -i ${config.sops.secrets.restic-ssh-key.path} -p ${toString sftpPort} ${sftpTarget} -s sftp'" + ]; pruneOpts = [ "--keep-daily 7" "--keep-monthly 12" diff --git a/secrets.yaml b/secrets.yaml index 5973503..527dcfd 100644 --- a/secrets.yaml +++ b/secrets.yaml @@ -2,7 +2,7 @@ media-htpasswd: ENC[AES256_GCM,data:8o+MBYaH+OoPrK2FtDzxCLXCz8oGDezIALl2KkoVlj/Z media-proxy-auth: ENC[AES256_GCM,data:OcmYZq/tyzMB61NfyYZ8gAlEE+8w2IhlPlZ+dfedtfqVlPHk3iJsd9mvsXHf5ODTtuy00ll0MF4KYNePZkz7TeuaIdBgGlshFyE4gwsJdPXZNYnhcg==,iv:qo6SOaHrWsXfvRwgSKDTSnreOcO9xy3RKrfE2k+VLEg=,tag:14DT86PQdEuK9zyZzcAohA==,type:str] media-ssh-key: ENC[AES256_GCM,data:cT5Jp5asgF2GZL4nn0rS4+tmli5adZjDa/G6WD/QXbOLtAjquytX63LKrLYUoTjOa7rNAjxDBIYEi90uvubKxOI0QbXACj0MSt6WbkxmosYResnFl9/WefpROctpGcDvn60fzer0K75IRBAtpAogVU7VynOkOuPa0xhTyAU8ZPOmij456UjpbtIgSg4yKVDn14jj/OZ1Oz+qd3bHC8FSQvp0jSKD9xfIizc2kb6ca3LRdR7VtJtTnJOOADRKaLC+rBywVyTOlCQBLiZ6LE9i6SmgFOdI+l6z9jE1Vi3vZ3BAe8Q/wWQ6Kjts+3+RkjPbgdjdWzxyHly/dr8lU1HcwtMHgKBV84asJBghCm6B1o48AEqd4oF9W039rCRQkR/VMb/ser0ifEjwnpDnDskrFYxWzidMKsfHGOtZxm7rzvOxSRA+Rcx9vxwa90gRsU4mBdx7QG0y3f/AbxRvVCuLLZW/y0JpCtE2B/mcObRvjsZP3RXQIS4vGAeTerd18RwsrsWO,iv:+ASa0hhWXmQ2hgJ9UuRFjnf/fA65kxWXiC+rDI6Lnx8=,tag:LDYSsN0DXAFiW0w+YBcopA==,type:str] torrent-proxy-auth: ENC[AES256_GCM,data:4oi4uZCgslTvmso1SCedu3gKsOTCtYIAf3g1mBS6/ta3d/hd6GJ0Ns+/9w51WrhcyJQRLSR7jLlzxRzKFp6JvKXlNAeflXDqOKNfk0LXY1GKTZynOA==,iv:26d+hQ9yn5CzDGNZvi9A5bvzgo87IrJHz67xTac4UA4=,tag:e8fO5Xpu7wpDiSC4CBsaaQ==,type:str] -restic-s3: ENC[AES256_GCM,data:RXRvwIwR7EqZSKxoqSYhGIWGH3GEBagPYCdwkRh0CDSTTRHQYN280gpgQA7ef2NkWnkrwQK4FCwCu2CBaPSMO0X6OcSVNJsmBySDQqZAb8SCs6pOSn2J+kHP2n8K9Fgy9/7OeX2i,iv:yrp2QZLXJypWh5XjsAHcpiXEPUcYF8A+mQZ+W2w7zpU=,tag:XhktIlDqXeq/tLMPZpQuLA==,type:str] +restic-repository: ENC[AES256_GCM,data:5LDzTrzcNDLHvNNMGaW4C2P6fTvnushyGX/ghLP47GGktnqLUff4r+dxR0o+xebhOu/g3Rku/F0vUDPy6ajAJ8+jCfzh9Kj16SzZXESvuqlX,iv:0y7S1Y8TR/XIh57etoVl7NEW+IO1kiu0M7dnFrAP+Lw=,tag:EKZcyTJz1lYGrFUXt4AAGA==,type:str] restic-password: ENC[AES256_GCM,data:nzbUoZgK+XP99/hPlIBm83hIDqRWlmNNNHwq0TXE9cQGTJyEmLfB6qlUdEtateG3,iv:8/WPCuGfLkd0LkLTEr7pjpT8kb/P64VICppDeEcKDIE=,tag:eytBikegC2fzCtUFh84qIw==,type:str] sops: kms: [] @@ -10,8 +10,8 @@ sops: azure_kv: [] hc_vault: [] age: [] - lastmodified: "2022-08-22T14:22:50Z" - mac: ENC[AES256_GCM,data:jeon/GqCA40VJogcR0jBtkZyLvRvEf3dhMfGl0NdLKEQhbH1a7xWSCe+riyszv4/UU6qkm/mIbrqLY4Tjaqg++f1AO9ZbSVleahik397cdVgfxaFBYrD2Ia7rvRqNSncHbK7Kc93GV/XzB6yIJTKcEKddNLxMvSnJtlaVaETECE=,iv:irJR+d+mxp6L9bZyTRjnTl42rEZS5u5awic2uR2DLLU=,tag:H0aWDkz0hTKkR/QXb7cvzQ==,type:str] + lastmodified: "2022-08-25T14:27:39Z" + mac: ENC[AES256_GCM,data:75hpB3gQ5WhqdSG4q1w08dQ1g9QGK2PA3hqXHnRz7cosjAERyldIG9TmOATrUGLULUy+E8fnOaACCatY5aMXVL/wmn77GkI4EA658D9j3Fhm1+k/Tv+rE8+4icb+9YNVZijLpHzSlMKZVOdYyg+CZlAC/xDz6ggdZOO6Ks29N+Q=,iv:0NKHdZxKmcUNiraoBW4WldO2hHkaTDVH0sUk/lh1Xg8=,tag:mRfDetmVh0Nv/4nHjCs/5g==,type:str] pgp: - created_at: "2022-06-09T21:22:41Z" enc: |