Unverified Commit 161a1ca1 authored by Jonas Heinrich's avatar Jonas Heinrich Committed by GitHub
Browse files

Merge pull request #191974 from tu-maurice/btrbk-doas

btrbk: Use sudo or doas based on configuration
parents 5fa4def8 3144b00d
Loading
Loading
Loading
Loading
+42 −15
Original line number Diff line number Diff line
@@ -47,7 +47,12 @@ let
    then [ "${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 {
    name = "btrbk-${name}.conf";
@@ -152,7 +157,8 @@ in
  };
  config = mkIf (sshEnabled || serviceEnabled) {
    environment.systemPackages = [ pkgs.btrbk ] ++ cfg.extraPackages;
    security.sudo.extraRules = [
    security.sudo = mkIf (sudo_doas == "sudo") {
      extraRules = [
        {
            users = [ "btrbk" ];
            commands = [
@@ -166,6 +172,26 @@ in
            ];
        }
      ];
    };
    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 = {
      isSystemUser = true;
      # ssh needs a home directory
@@ -183,8 +209,9 @@ in
              "best-effort" = 2;
              "realtime" = 1;
            }.${cfg.ioSchedulingClass};
            sudo_doas_flag = "--${sudo_doas}";
          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;
    };
+1 −0
Original line number Diff line number Diff line
@@ -108,6 +108,7 @@ in {
  breitbandmessung = handleTest ./breitbandmessung.nix {};
  brscan5 = handleTest ./brscan5.nix {};
  btrbk = handleTest ./btrbk.nix {};
  btrbk-doas = handleTest ./btrbk-doas.nix {};
  btrbk-no-timer = handleTest ./btrbk-no-timer.nix {};
  btrbk-section-order = handleTest ./btrbk-section-order.nix {};
  buildbot = handleTest ./buildbot.nix {};
+114 −0
Original line number Diff line number Diff line
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")
    '';
  })
+1 −1
Original line number Diff line number Diff line
@@ -54,7 +54,7 @@ stdenv.mkDerivation rec {
  '';

  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 {