Merge pull request #191974 from tu-maurice/btrbk-doas
btrbk: Use sudo or doas based on configuration
This commit is contained in:
commit
161a1ca129
4 changed files with 158 additions and 16 deletions
|
@ -47,7 +47,12 @@ let
|
||||||
then [ "${name} ${value}" ]
|
then [ "${name} ${value}" ]
|
||||||
else concatLists (mapAttrsToList (genSection name) value);
|
else concatLists (mapAttrsToList (genSection name) value);
|
||||||
|
|
||||||
addDefaults = settings: { backend = "btrfs-progs-sudo"; } // settings;
|
sudo_doas =
|
||||||
|
if config.security.sudo.enable then "sudo"
|
||||||
|
else if config.security.doas.enable then "doas"
|
||||||
|
else throw "The btrbk nixos module needs either sudo or doas enabled in the configuration";
|
||||||
|
|
||||||
|
addDefaults = settings: { backend = "btrfs-progs-${sudo_doas}"; } // settings;
|
||||||
|
|
||||||
mkConfigFile = name: settings: pkgs.writeTextFile {
|
mkConfigFile = name: settings: pkgs.writeTextFile {
|
||||||
name = "btrbk-${name}.conf";
|
name = "btrbk-${name}.conf";
|
||||||
|
@ -152,20 +157,41 @@ in
|
||||||
};
|
};
|
||||||
config = mkIf (sshEnabled || serviceEnabled) {
|
config = mkIf (sshEnabled || serviceEnabled) {
|
||||||
environment.systemPackages = [ pkgs.btrbk ] ++ cfg.extraPackages;
|
environment.systemPackages = [ pkgs.btrbk ] ++ cfg.extraPackages;
|
||||||
security.sudo.extraRules = [
|
security.sudo = mkIf (sudo_doas == "sudo") {
|
||||||
{
|
extraRules = [
|
||||||
users = [ "btrbk" ];
|
{
|
||||||
commands = [
|
users = [ "btrbk" ];
|
||||||
{ command = "${pkgs.btrfs-progs}/bin/btrfs"; options = [ "NOPASSWD" ]; }
|
commands = [
|
||||||
{ command = "${pkgs.coreutils}/bin/mkdir"; options = [ "NOPASSWD" ]; }
|
{ command = "${pkgs.btrfs-progs}/bin/btrfs"; options = [ "NOPASSWD" ]; }
|
||||||
{ command = "${pkgs.coreutils}/bin/readlink"; options = [ "NOPASSWD" ]; }
|
{ command = "${pkgs.coreutils}/bin/mkdir"; options = [ "NOPASSWD" ]; }
|
||||||
# for ssh, they are not the same than the one hard coded in ${pkgs.btrbk}
|
{ command = "${pkgs.coreutils}/bin/readlink"; options = [ "NOPASSWD" ]; }
|
||||||
{ command = "/run/current-system/bin/btrfs"; options = [ "NOPASSWD" ]; }
|
# for ssh, they are not the same than the one hard coded in ${pkgs.btrbk}
|
||||||
{ command = "/run/current-system/sw/bin/mkdir"; options = [ "NOPASSWD" ]; }
|
{ command = "/run/current-system/bin/btrfs"; options = [ "NOPASSWD" ]; }
|
||||||
{ command = "/run/current-system/sw/bin/readlink"; options = [ "NOPASSWD" ]; }
|
{ command = "/run/current-system/sw/bin/mkdir"; options = [ "NOPASSWD" ]; }
|
||||||
|
{ command = "/run/current-system/sw/bin/readlink"; options = [ "NOPASSWD" ]; }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
security.doas = mkIf (sudo_doas == "doas") {
|
||||||
|
extraRules = let
|
||||||
|
doasCmdNoPass = cmd: { users = [ "btrbk" ]; cmd = cmd; noPass = true; };
|
||||||
|
in
|
||||||
|
[
|
||||||
|
(doasCmdNoPass "${pkgs.btrfs-progs}/bin/btrfs")
|
||||||
|
(doasCmdNoPass "${pkgs.coreutils}/bin/mkdir")
|
||||||
|
(doasCmdNoPass "${pkgs.coreutils}/bin/readlink")
|
||||||
|
# for ssh, they are not the same than the one hard coded in ${pkgs.btrbk}
|
||||||
|
(doasCmdNoPass "/run/current-system/bin/btrfs")
|
||||||
|
(doasCmdNoPass "/run/current-system/sw/bin/mkdir")
|
||||||
|
(doasCmdNoPass "/run/current-system/sw/bin/readlink")
|
||||||
|
|
||||||
|
# doas matches command, not binary
|
||||||
|
(doasCmdNoPass "btrfs")
|
||||||
|
(doasCmdNoPass "mkdir")
|
||||||
|
(doasCmdNoPass "readlink")
|
||||||
];
|
];
|
||||||
}
|
};
|
||||||
];
|
|
||||||
users.users.btrbk = {
|
users.users.btrbk = {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
# ssh needs a home directory
|
# ssh needs a home directory
|
||||||
|
@ -183,8 +209,9 @@ in
|
||||||
"best-effort" = 2;
|
"best-effort" = 2;
|
||||||
"realtime" = 1;
|
"realtime" = 1;
|
||||||
}.${cfg.ioSchedulingClass};
|
}.${cfg.ioSchedulingClass};
|
||||||
|
sudo_doas_flag = "--${sudo_doas}";
|
||||||
in
|
in
|
||||||
''command="${pkgs.util-linux}/bin/ionice -t -c ${toString ioniceClass} ${optionalString (cfg.niceness >= 1) "${pkgs.coreutils}/bin/nice -n ${toString cfg.niceness}"} ${pkgs.btrbk}/share/btrbk/scripts/ssh_filter_btrbk.sh --sudo ${options}" ${v.key}''
|
''command="${pkgs.util-linux}/bin/ionice -t -c ${toString ioniceClass} ${optionalString (cfg.niceness >= 1) "${pkgs.coreutils}/bin/nice -n ${toString cfg.niceness}"} ${pkgs.btrbk}/share/btrbk/scripts/ssh_filter_btrbk.sh ${sudo_doas_flag} ${options}" ${v.key}''
|
||||||
)
|
)
|
||||||
cfg.sshAccess;
|
cfg.sshAccess;
|
||||||
};
|
};
|
||||||
|
|
|
@ -108,6 +108,7 @@ in {
|
||||||
breitbandmessung = handleTest ./breitbandmessung.nix {};
|
breitbandmessung = handleTest ./breitbandmessung.nix {};
|
||||||
brscan5 = handleTest ./brscan5.nix {};
|
brscan5 = handleTest ./brscan5.nix {};
|
||||||
btrbk = handleTest ./btrbk.nix {};
|
btrbk = handleTest ./btrbk.nix {};
|
||||||
|
btrbk-doas = handleTest ./btrbk-doas.nix {};
|
||||||
btrbk-no-timer = handleTest ./btrbk-no-timer.nix {};
|
btrbk-no-timer = handleTest ./btrbk-no-timer.nix {};
|
||||||
btrbk-section-order = handleTest ./btrbk-section-order.nix {};
|
btrbk-section-order = handleTest ./btrbk-section-order.nix {};
|
||||||
buildbot = handleTest ./buildbot.nix {};
|
buildbot = handleTest ./buildbot.nix {};
|
||||||
|
|
114
nixos/tests/btrbk-doas.nix
Normal file
114
nixos/tests/btrbk-doas.nix
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
import ./make-test-python.nix ({ pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
privateKey = ''
|
||||||
|
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||||
|
QyNTUxOQAAACBx8UB04Q6Q/fwDFjakHq904PYFzG9pU2TJ9KXpaPMcrwAAAJB+cF5HfnBe
|
||||||
|
RwAAAAtzc2gtZWQyNTUxOQAAACBx8UB04Q6Q/fwDFjakHq904PYFzG9pU2TJ9KXpaPMcrw
|
||||||
|
AAAEBN75NsJZSpt63faCuaD75Unko0JjlSDxMhYHAPJk2/xXHxQHThDpD9/AMWNqQer3Tg
|
||||||
|
9gXMb2lTZMn0pelo8xyvAAAADXJzY2h1ZXR6QGt1cnQ=
|
||||||
|
-----END OPENSSH PRIVATE KEY-----
|
||||||
|
'';
|
||||||
|
publicKey = ''
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHHxQHThDpD9/AMWNqQer3Tg9gXMb2lTZMn0pelo8xyv
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
name = "btrbk-doas";
|
||||||
|
meta = with pkgs.lib; {
|
||||||
|
maintainers = with maintainers; [ symphorien tu-maurice ];
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes = {
|
||||||
|
archive = { ... }: {
|
||||||
|
security.sudo.enable = false;
|
||||||
|
security.doas.enable = true;
|
||||||
|
environment.systemPackages = with pkgs; [ btrfs-progs ];
|
||||||
|
# note: this makes the privateKey world readable.
|
||||||
|
# don't do it with real ssh keys.
|
||||||
|
environment.etc."btrbk_key".text = privateKey;
|
||||||
|
services.btrbk = {
|
||||||
|
extraPackages = [ pkgs.lz4 ];
|
||||||
|
instances = {
|
||||||
|
remote = {
|
||||||
|
onCalendar = "minutely";
|
||||||
|
settings = {
|
||||||
|
ssh_identity = "/etc/btrbk_key";
|
||||||
|
ssh_user = "btrbk";
|
||||||
|
stream_compress = "lz4";
|
||||||
|
volume = {
|
||||||
|
"ssh://main/mnt" = {
|
||||||
|
target = "/mnt";
|
||||||
|
snapshot_dir = "btrbk/remote";
|
||||||
|
subvolume = "to_backup";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
main = { ... }: {
|
||||||
|
security.sudo.enable = false;
|
||||||
|
security.doas.enable = true;
|
||||||
|
environment.systemPackages = with pkgs; [ btrfs-progs ];
|
||||||
|
services.openssh = {
|
||||||
|
enable = true;
|
||||||
|
passwordAuthentication = false;
|
||||||
|
kbdInteractiveAuthentication = false;
|
||||||
|
};
|
||||||
|
services.btrbk = {
|
||||||
|
extraPackages = [ pkgs.lz4 ];
|
||||||
|
sshAccess = [
|
||||||
|
{
|
||||||
|
key = publicKey;
|
||||||
|
roles = [ "source" "send" "info" "delete" ];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
instances = {
|
||||||
|
local = {
|
||||||
|
onCalendar = "minutely";
|
||||||
|
settings = {
|
||||||
|
volume = {
|
||||||
|
"/mnt" = {
|
||||||
|
snapshot_dir = "btrbk/local";
|
||||||
|
subvolume = "to_backup";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
start_all()
|
||||||
|
|
||||||
|
# create btrfs partition at /mnt
|
||||||
|
for machine in (archive, main):
|
||||||
|
machine.succeed("dd if=/dev/zero of=/data_fs bs=120M count=1")
|
||||||
|
machine.succeed("mkfs.btrfs /data_fs")
|
||||||
|
machine.succeed("mkdir /mnt")
|
||||||
|
machine.succeed("mount /data_fs /mnt")
|
||||||
|
|
||||||
|
# what to backup and where
|
||||||
|
main.succeed("btrfs subvolume create /mnt/to_backup")
|
||||||
|
main.succeed("mkdir -p /mnt/btrbk/{local,remote}")
|
||||||
|
|
||||||
|
# check that local snapshots work
|
||||||
|
with subtest("local"):
|
||||||
|
main.succeed("echo foo > /mnt/to_backup/bar")
|
||||||
|
main.wait_until_succeeds("cat /mnt/btrbk/local/*/bar | grep foo")
|
||||||
|
main.succeed("echo bar > /mnt/to_backup/bar")
|
||||||
|
main.succeed("cat /mnt/btrbk/local/*/bar | grep foo")
|
||||||
|
|
||||||
|
# check that btrfs send/receive works and ssh access works
|
||||||
|
with subtest("remote"):
|
||||||
|
archive.wait_until_succeeds("cat /mnt/*/bar | grep bar")
|
||||||
|
main.succeed("echo baz > /mnt/to_backup/bar")
|
||||||
|
archive.succeed("cat /mnt/*/bar | grep bar")
|
||||||
|
'';
|
||||||
|
})
|
|
@ -54,7 +54,7 @@ stdenv.mkDerivation rec {
|
||||||
'';
|
'';
|
||||||
|
|
||||||
passthru.tests = {
|
passthru.tests = {
|
||||||
inherit (nixosTests) btrbk btrbk-no-timer btrbk-section-order;
|
inherit (nixosTests) btrbk btrbk-no-timer btrbk-section-order btrbk-doas;
|
||||||
};
|
};
|
||||||
|
|
||||||
passthru.updateScript = genericUpdater {
|
passthru.updateScript = genericUpdater {
|
||||||
|
|
Loading…
Reference in a new issue