]> git.immae.eu Git - perso/Immae/Config/Nix.git/commitdiff
Use zrepl to make zfs backups
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Tue, 1 Sep 2020 22:23:50 +0000 (00:23 +0200)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Tue, 1 Sep 2020 22:23:50 +0000 (00:23 +0200)
modules/default.nix
modules/private/environment.nix
modules/private/system/dilion.nix
modules/private/system/eldiron.nix
modules/zrepl.nix [new file with mode: 0644]
nixops/secrets
pkgs/default.nix
pkgs/zrepl/default.nix [new file with mode: 0644]

index a503f9228de50ffee05470bf67e8b55f44959b3a..03b9adc9c92a162956dc003ae32eff3b1b82491c 100644 (file)
@@ -19,5 +19,6 @@
   naemon = ./naemon;
 
   php-application = ./websites/php-application.nix;
+  zrepl = ./zrepl.nix;
   websites = ./websites;
 } // (if builtins.pathExists ./private then import ./private else {})
index 6a2cea0b87c40e4c6fb6e584be7a69df609a2c87..0f6f3e2d50854f3f260c36afaca52a8b19d16db8 100644 (file)
@@ -462,6 +462,22 @@ in
         };
       };
     };
+    zrepl_backup = mkOption {
+      type = submodule {
+        options = {
+          ssh_key = mkOption {
+            description = "SSH key information";
+            type = submodule {
+              options = {
+                public = mkOption { type = str; description = "Public part of the key"; };
+                private = mkOption { type = lines; description = "Private part of the key"; };
+              };
+            };
+          };
+          mysql = mkMysqlOptions "Zrepl" {};
+        };
+      };
+    };
     rsync_backup = mkOption {
       description  =''
         Rsync backup configuration from controlled host
index 14155efc50ee22119f9e736c72869263057c7a38..cc4297e0f4e7ce2f74dcc4abbb2dc5f23c30d89c 100644 (file)
   programs.zsh.enable = true;
 
   users.users.backup = {
-    home = "/var/lib/backup";
-    createHome = true;
     hashedPassword = "!";
     isSystemUser = true;
+    extraGroups = [ "keys" ];
     shell = pkgs.bashInteractive;
     openssh.authorizedKeys.keys = let
+      zreplConfig = config.secrets.fullPaths."zrepl/zrepl.yml";
     in
-      ["command=\"${pkgs.rrsync_sudo}/bin/rrsync /var/lib/backup/eldiron/\"  ${config.myEnv.rsync_backup.ssh_key.public}"];
+      ["command=\"${pkgs.zrepl}/bin/zrepl stdinserver --config ${zreplConfig} eldiron\",restrict ${config.myEnv.zrepl_backup.ssh_key.public}"];
   };
   security.sudo.extraRules = pkgs.lib.mkAfter [
-    {
-      commands = [
-        { command = "${pkgs.rsync}/bin/rsync"; options = [ "NOPASSWD" ]; }
-      ];
-      users = [ "backup" ];
-      runAs = "root";
-    }
     {
       commands = [
         { command = "/home/immae/.nix-profile/root_scripts/*"; options = [ "NOPASSWD" ]; }
   ];
 
   boot.kernel.sysctl."vm.nr_hugepages" = 256; # for xmr-stak
-  system.activationScripts.backup_home = ''
-    chown root:root /var/lib/backup
-    install -m 0750 -o backup -g root -d /var/lib/backup/eldiron
-  '';
-
   system.activationScripts.libvirtd_exports = ''
     install -m 0755 -o root -g root -d /var/lib/caldance
   '';
     };
   };
 
+  systemd.services.zrepl.serviceConfig.RuntimeDirectory = lib.mkForce "zrepl zrepl/stdinserver";
+  systemd.services.zrepl.serviceConfig.User = "backup";
+  # zfs allow backup create,mount,receive,destroy,rename,snapshot,hold,bookmark,release zpool/backup
+  services.zrepl = {
+    enable = true;
+    config = ''
+      global:
+        control:
+          sockpath: /run/zrepl/control
+        serve:
+          stdinserver:
+            sockdir: /run/zrepl/stdinserver
+      jobs:
+        - type: sink
+          # must not change
+          name: "backup-from-eldiron"
+          root_fs: "zpool/backup"
+          serve:
+            type: stdinserver
+            client_identities:
+              - eldiron
+    '';
+  };
   # This value determines the NixOS release with which your system is
   # to be compatible, in order to avoid breaking some software such as
   # database servers. You should change this only after NixOS release
index 8a5d11cd53da40215e66b80714205177d29482e0..83e52b8989636d50328060d97412329c2bfc0f66 100644 (file)
@@ -19,9 +19,6 @@
   };
 
   services.zfs = {
-    autoSnapshot = {
-      enable = true;
-    };
     autoScrub = {
       enable = true;
     };
 
   secrets.keys = [
     {
-      dest = "rsync_backup/identity";
+      dest = "zrepl_backup/identity";
       user = "root";
       group = "root";
       permissions = "0400";
-      text = config.myEnv.rsync_backup.ssh_key.private;
+      text = config.myEnv.zrepl_backup.ssh_key.private;
     }
   ];
   programs.ssh.knownHosts.dilion = {
     mailto = "cron@immae.eu";
     systemCronJobs = [
       ''
-        # The star after /var/lib/* avoids deleting all folders in case of problem
-        0 3,9,15,21 * * * root rsync -e "ssh -i /var/secrets/rsync_backup/identity" --new-compress -aAXv --delete --numeric-ids --super --rsync-path="sudo rsync" /var/lib/* backup@dilion.immae.eu: > /dev/null
         0 0 * * * root journalctl -q --since="25 hours ago" -u postfix -t postfix/smtpd -g "immae.eu.*Recipient address rejected"
         # Need a way to blacklist properly
         # 0 0 * * * root journalctl -q --since="25 hours ago" -u postfix -t postfix/smtpd -g "NOQUEUE:"
   };
   environment.systemPackages = [ pkgs.bindfs ];
 
+  services.zrepl = {
+    enable = true;
+    config = let
+      redis_dump = pkgs.writeScript "redis-dump" ''
+        #! ${pkgs.stdenv.shell}
+        ${pkgs.redis}/bin/redis-cli bgsave
+      '';
+    in ''
+      jobs:
+        - type: push
+          # must not change
+          name: "backup-to-dilion"
+          filesystems:
+            "zpool/root": true
+            "zpool/root/etc": true
+            "zpool/root/var<": true
+          connect:
+            type: ssh+stdinserver
+            host: dilion.immae.eu
+            user: backup
+            port: 22
+            identity_file: ${config.secrets.fullPaths."zrepl_backup/identity"}
+          snapshotting:
+            type: periodic
+            prefix: zrepl_
+            interval: 15m
+            hooks:
+              - type: mysql-lock-tables
+                dsn: "${config.myEnv.zrepl_backup.mysql.user}:${config.myEnv.zrepl_backup.mysql.password}@tcp(localhost)/"
+                filesystems:
+                  "zpool/root/var": true
+              - type: command
+                path: ${redis_dump}
+                err_is_fatal: false
+                filesystems:
+                  "zpool/root/var": true
+          send:
+            encrypted: true
+          pruning:
+            keep_sender:
+              - type: not_replicated
+              - type: regex
+                regex: "^manual_.*"
+              - type: grid
+                grid: 1x1h(keep=all) | 24x1h | 7x1d | 4x7d | 6x30d
+                regex: "^zrepl_.*"
+            keep_receiver:
+              - type: regex
+                regex: "^manual_.*"
+              - type: grid
+                grid: 1x1h(keep=all) | 24x1h | 7x1d | 4x7d | 6x30d
+                regex: "^zrepl_.*"
+    '';
+  };
   # This value determines the NixOS release with which your system is
   # to be compatible, in order to avoid breaking some software such as
   # database servers. You should change this only after NixOS release
diff --git a/modules/zrepl.nix b/modules/zrepl.nix
new file mode 100644 (file)
index 0000000..cb74082
--- /dev/null
@@ -0,0 +1,46 @@
+{ config, lib, pkgs, ... }:
+let
+  cfg = config.services.zrepl;
+in
+{
+  options = {
+    services.zrepl = {
+      enable = lib.mkEnableOption "Enable the zrepl daemon";
+
+      config = lib.mkOption {
+        type = lib.types.lines;
+        default = "";
+        description = "Configuration";
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    secrets.keys = [
+      {
+        dest = "zrepl/zrepl.yml";
+        permissions = "0400";
+        text = cfg.config;
+        user = config.systemd.services.zrepl.serviceConfig.User or "root";
+        group = config.systemd.services.zrepl.serviceConfig.Group or "root";
+      }
+    ];
+    services.filesWatcher.zrepl = {
+      restart = true;
+      paths = [ config.secrets.fullPaths."zrepl/zrepl.yml" ];
+    };
+    systemd.services.zrepl = {
+      description = "zrepl daemon";
+      wantedBy = [ "multi-user.target" ];
+      path = [ pkgs.zfs pkgs.openssh ];
+      serviceConfig = {
+        ExecStart =
+          let configFile = config.secrets.fullPaths."zrepl/zrepl.yml";
+          in "${pkgs.zrepl}/bin/zrepl daemon --config ${configFile}";
+        Type = "simple";
+        RuntimeDirectory= "zrepl";
+        RuntimeDirectoryMode= "0700";
+      };
+    };
+  };
+}
index d34d5490226809ff9863ce4e66bd59a68ead861c..79b991028b09aa59f719059de8dc1fba7d6b04fd 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d34d5490226809ff9863ce4e66bd59a68ead861c
+Subproject commit 79b991028b09aa59f719059de8dc1fba7d6b04fd
index 702f4cfc55a9e12b72b354a97889ae9960cd9361..4b3d4b306c747983fa4f28d1a21e9092045e99aa 100644 (file)
@@ -70,4 +70,5 @@ rec {
   };
 
   fiche = callPackage ./fiche { inherit mylibs; };
+  zrepl = callPackage ./zrepl {};
 }
diff --git a/pkgs/zrepl/default.nix b/pkgs/zrepl/default.nix
new file mode 100644 (file)
index 0000000..1e89098
--- /dev/null
@@ -0,0 +1,14 @@
+{ buildGoModule, fetchFromGitHub }:
+buildGoModule rec {
+  name = "zrepl-${version}";
+  version = "0.3.0";
+  src = fetchFromGitHub {
+    owner  = "zrepl";
+    repo   = "zrepl";
+    rev    = "v${version}";
+    sha256 = "11wfdvi3f4yw7kdapf0l38illnnn7jgi5cp4whrg5zsqyc0wqrym";
+  };
+  modSha256 = "0gh0x8321dhk1nhg1as0bl1bxlblrrcxxl1rb1d8825ly8bhcdkb";
+  vendorSha256 = "0gh0x8321dhk1nhg1as0bl1bxlblrrcxxl1rb1d8825ly8bhcdkb";
+  subPackages = [ "." ];
+}