Merge pull request #79759 from lopsided98/syncoid-no-root
nixos/syncoid: automatically setup privilege delegation
This commit is contained in:
commit
f98312fcb5
|
@ -4,6 +4,15 @@ with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.services.syncoid;
|
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 {
|
in {
|
||||||
|
|
||||||
# Interface
|
# Interface
|
||||||
|
@ -26,14 +35,25 @@ in {
|
||||||
|
|
||||||
user = mkOption {
|
user = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "root";
|
default = "syncoid";
|
||||||
example = "backup";
|
example = "backup";
|
||||||
description = ''
|
description = ''
|
||||||
The user for the service. Sudo or ZFS privilege delegation must be
|
The user for the service. ZFS privilege delegation will be
|
||||||
configured to use a user other than root.
|
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 {
|
sshKey = mkOption {
|
||||||
type = types.nullOr types.path;
|
type = types.nullOr types.path;
|
||||||
# Prevent key from being copied to store
|
# Prevent key from being copied to store
|
||||||
|
@ -150,6 +170,18 @@ in {
|
||||||
# Implementation
|
# Implementation
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
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 = {
|
systemd.services.syncoid = {
|
||||||
description = "Syncoid ZFS synchronization service";
|
description = "Syncoid ZFS synchronization service";
|
||||||
script = concatMapStringsSep "\n" (c: lib.escapeShellArgs
|
script = concatMapStringsSep "\n" (c: lib.escapeShellArgs
|
||||||
|
@ -160,10 +192,22 @@ in {
|
||||||
++ c.extraArgs
|
++ c.extraArgs
|
||||||
++ [ "--sendoptions" c.sendOptions
|
++ [ "--sendoptions" c.sendOptions
|
||||||
"--recvoptions" c.recvOptions
|
"--recvoptions" c.recvOptions
|
||||||
|
"--no-privilege-elevation"
|
||||||
c.source c.target
|
c.source c.target
|
||||||
])) (attrValues cfg.commands);
|
])) (attrValues cfg.commands);
|
||||||
after = [ "zfs.target" ];
|
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;
|
startAt = cfg.interval;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,7 +38,7 @@ in {
|
||||||
|
|
||||||
services.syncoid = {
|
services.syncoid = {
|
||||||
enable = true;
|
enable = true;
|
||||||
sshKey = "/root/.ssh/id_ecdsa";
|
sshKey = "/var/lib/syncoid/id_ecdsa";
|
||||||
commonArgs = [ "--no-sync-snap" ];
|
commonArgs = [ "--no-sync-snap" ];
|
||||||
commands."pool/test".target = "root@target:pool/test";
|
commands."pool/test".target = "root@target:pool/test";
|
||||||
};
|
};
|
||||||
|
@ -69,11 +69,12 @@ in {
|
||||||
"udevadm settle",
|
"udevadm settle",
|
||||||
)
|
)
|
||||||
|
|
||||||
source.succeed("mkdir -m 700 /root/.ssh")
|
|
||||||
source.succeed(
|
source.succeed(
|
||||||
"cat '${snakeOilPrivateKey}' > /root/.ssh/id_ecdsa"
|
"mkdir -m 700 -p /var/lib/syncoid",
|
||||||
|
"cat '${snakeOilPrivateKey}' > /var/lib/syncoid/id_ecdsa",
|
||||||
|
"chmod 600 /var/lib/syncoid/id_ecdsa",
|
||||||
|
"chown -R syncoid:syncoid /var/lib/syncoid/",
|
||||||
)
|
)
|
||||||
source.succeed("chmod 600 /root/.ssh/id_ecdsa")
|
|
||||||
|
|
||||||
source.succeed("touch /tmp/mnt/test.txt")
|
source.succeed("touch /tmp/mnt/test.txt")
|
||||||
source.systemctl("start --wait sanoid.service")
|
source.systemctl("start --wait sanoid.service")
|
||||||
|
|
Loading…
Reference in New Issue