summary refs log tree commit diff
path: root/nixos/modules/services/backup
diff options
context:
space:
mode:
authorBen Wolsieffer <benwolsieffer@gmail.com>2020-02-09 19:40:52 -0500
committerBen Wolsieffer <benwolsieffer@gmail.com>2020-03-09 16:04:31 -0400
commit733acfa140d5b73bc69c53c4ebd90ccc5f281f0e (patch)
tree12f5c5d20c969b3a6811665e6559d653e42e02b8 /nixos/modules/services/backup
parentfcc8660d359d2c582b0b148739a72cec476cfef5 (diff)
downloadnixpkgs-733acfa140d5b73bc69c53c4ebd90ccc5f281f0e.tar
nixpkgs-733acfa140d5b73bc69c53c4ebd90ccc5f281f0e.tar.gz
nixpkgs-733acfa140d5b73bc69c53c4ebd90ccc5f281f0e.tar.bz2
nixpkgs-733acfa140d5b73bc69c53c4ebd90ccc5f281f0e.tar.lz
nixpkgs-733acfa140d5b73bc69c53c4ebd90ccc5f281f0e.tar.xz
nixpkgs-733acfa140d5b73bc69c53c4ebd90ccc5f281f0e.tar.zst
nixpkgs-733acfa140d5b73bc69c53c4ebd90ccc5f281f0e.zip
nixos/syncoid: automatically setup privilege delegation
Diffstat (limited to 'nixos/modules/services/backup')
-rw-r--r--nixos/modules/services/backup/syncoid.nix52
1 files changed, 48 insertions, 4 deletions
diff --git a/nixos/modules/services/backup/syncoid.nix b/nixos/modules/services/backup/syncoid.nix
index 53787a0182a..41e7a9ef6fe 100644
--- a/nixos/modules/services/backup/syncoid.nix
+++ b/nixos/modules/services/backup/syncoid.nix
@@ -4,6 +4,15 @@ with lib;
 
 let
   cfg = config.services.syncoid;
+
+  # Extract pool names of local datasets (ones that don't contain "@") that
+  # have the specified type (either "source" or "target")
+  getPools = type: unique (map (d: head (builtins.match "([^/]+).*" d)) (
+    # Filter local datasets
+    filter (d: !hasInfix "@" d)
+    # Get datasets of the specified type
+    (catAttrs type (attrValues cfg.commands))
+  ));
 in {
 
     # Interface
@@ -26,14 +35,25 @@ in {
 
       user = mkOption {
         type = types.str;
-        default = "root";
+        default = "syncoid";
         example = "backup";
         description = ''
-          The user for the service. Sudo or ZFS privilege delegation must be
-          configured to use a user other than root.
+          The user for the service. ZFS privilege delegation will be
+          automatically configured for any local pools used by syncoid if this
+          option is set to a user other than root. The user will be given the
+          "hold" and "send" privileges on any pool that has datasets being sent
+          and the "create", "mount", "receive", and "rollback" privileges on
+          any pool that has datasets being received.
         '';
       };
 
+      group = mkOption {
+        type = types.str;
+        default = "syncoid";
+        example = "backup";
+        description = "The group for the service.";
+      };
+
       sshKey = mkOption {
         type = types.nullOr types.path;
         # Prevent key from being copied to store
@@ -146,6 +166,18 @@ in {
     # Implementation
 
     config = mkIf cfg.enable {
+      users =  {
+        users = mkIf (cfg.user == "syncoid") {
+          syncoid = {
+            group = cfg.group;
+            isSystemUser = true;
+          };
+        };
+        groups = mkIf (cfg.group == "syncoid") {
+          syncoid = {};
+        };
+      };
+
       systemd.services.syncoid = {
         description = "Syncoid ZFS synchronization service";
         script = concatMapStringsSep "\n" (c: lib.escapeShellArgs
@@ -156,10 +188,22 @@ in {
             ++ c.extraArgs
             ++ [ "--sendoptions" c.sendOptions
                  "--recvoptions" c.recvOptions
+                 "--no-privilege-elevation"
                  c.source c.target
                ])) (attrValues cfg.commands);
         after = [ "zfs.target" ];
-        serviceConfig.User = cfg.user;
+        serviceConfig = {
+          ExecStartPre = (map (pool: lib.escapeShellArgs [
+            "+/run/booted-system/sw/bin/zfs" "allow"
+            cfg.user "hold,send" pool
+          ]) (getPools "source")) ++
+          (map (pool: lib.escapeShellArgs [
+            "+/run/booted-system/sw/bin/zfs" "allow"
+            cfg.user "create,mount,receive,rollback" pool
+          ]) (getPools "target"));
+          User = cfg.user;
+          Group = cfg.group;
+        };
         startAt = cfg.interval;
       };
     };