From c063dbd2170f088fcf0fe30cdb0d1cceaae8a3db Mon Sep 17 00:00:00 2001 From: Christoph Urlacher Date: Tue, 10 Jun 2025 23:43:25 +0200 Subject: [PATCH] System: Add allowedActions option to polkit module --- .../1_deprecated/containers/default.nix | 2 +- system/modules/polkit/default.nix | 65 +++++++++++++++---- system/modules/polkit/options.nix | 13 +++- 3 files changed, 67 insertions(+), 13 deletions(-) diff --git a/system/modules/1_deprecated/containers/default.nix b/system/modules/1_deprecated/containers/default.nix index ca4274e1..99cb568b 100644 --- a/system/modules/1_deprecated/containers/default.nix +++ b/system/modules/1_deprecated/containers/default.nix @@ -54,7 +54,7 @@ in { }; # Allow start/stop containers without root password - modules.polkit.allowed-system-services = let + modules.polkit.allowedSystemServices = let container-services = lib.pipe virtualisation.oci-containers.containers [ builtins.attrNames (builtins.filter (c: cfg.${c}.enable)) diff --git a/system/modules/polkit/default.nix b/system/modules/polkit/default.nix index f8b2c317..25f1b693 100644 --- a/system/modules/polkit/default.nix +++ b/system/modules/polkit/default.nix @@ -14,23 +14,66 @@ in { config = mkIf cfg.enable { security.polkit.enable = true; + # NOTE: Polkit stuff: + # - subject.active: The subject is part of the currently active session + # - subject.local: The subject is spawned from a local seat/session + # - subject.user == ${username}: Only unlock stuff for the user defined by this config security.polkit.extraConfig = let - # Stuff that should always get a rule - always-predicates = []; + # Services that should always get a rule + always-services = []; mkServicePredicate = service: "action.lookup(\"unit\") == \"${service}\""; - predicates = lib.pipe (cfg.allowed-system-services ++ always-predicates) [ + servicePredicates = lib.pipe (cfg.allowedSystemServices ++ always-services) [ (builtins.map mkServicePredicate) (builtins.concatStringsSep " ||\n") ]; - in '' - polkit.addRule(function(action, subject) { - if (action.id == "org.freedesktop.systemd1.manage-units" && subject.user == "${username}" && ( - ${predicates} - )) { + + # Actions that should always be allowed + always-actions = []; + + mkActionPredicate = action: "action.id == \"${action}\""; + actionPredicates = lib.pipe (cfg.allowedActions ++ always-actions) [ + (builtins.map mkActionPredicate) + (builtins.concatStringsSep " ||\n") + ]; + in + lib.concatStrings [ + '' + // NixOS PolKit Rules Start + '' + + # Only add this ruleset if (len servicePredicates) > 0 + (lib.optionalString (builtins.lessThan 0 (builtins.length cfg.allowedSystemServices)) '' + polkit.addRule(function(action, subject) { + if ( + action.id == "org.freedesktop.systemd1.manage-units" && + subject.user == "${username}" && + subject.local && + subject.active && + (${servicePredicates}) + ) { return polkit.Result.YES; - } - }); - ''; + } + }); + '') + + # Only add this ruleset if (len actionPredicates) > 0 + (lib.optionalString (builtins.lessThan 0 (builtins.length cfg.allowedActions)) '' + polkit.addRule(function(action, subject) { + if ( + subject.user == "${username}" && + subject.local && + subject.active && + (${actionPredicates}) + ) { + return polkit.Result.YES; + } + }); + '') + + '' + // NixOS PolKit Rules End + '' + ]; }; } diff --git a/system/modules/polkit/options.nix b/system/modules/polkit/options.nix index bc9f355e..88e4f5d8 100644 --- a/system/modules/polkit/options.nix +++ b/system/modules/polkit/options.nix @@ -7,7 +7,18 @@ with lib; with mylib.modules; { enable = mkEnableOption "Polkit"; - allowed-system-services = mkOption { + allowedActions = mkOption { + type = types.listOf types.str; + description = "Actions that should be manageable by a User without Root Password"; + example = '' + [ + "org.freedesktop.NetworkManager.settings.modify.system" + ] + ''; + default = []; + }; + + allowedSystemServices = mkOption { type = types.listOf types.str; description = "System Services that should be manageable by a User without Root Password"; example = ''