nixos/polkit: modernize, make pkexec wrapper opt-in (#530106)
This commit is contained in:
@@ -28,6 +28,8 @@
|
||||
|
||||
- Python 2 has been removed from the top-level package set, as it is long past end-of-life. The `python2`, `python27`, `python2Full`, `python27Full`, `python2Packages`, and `python27Packages` attributes, along with the legacy `python`, `pythonFull`, and `pythonPackages` aliases, now throw an error directing you to `python3`. The `isPy2` and `isPy27` package flags have been removed accordingly. The only remaining Python 2 interpreter is vendored inside the `resholve` package for its `oil` dependency and is not exposed for general use.
|
||||
|
||||
- `security.polkit.enablePkexecWrapper` has been introduced, making the `pkexec` setuid wrapper opt-in.
|
||||
|
||||
- `systemd.user.extraConfig` has been removed in favor of the structured [](#opt-systemd.user.settings.Manager) option. Use `systemd.user.settings.Manager` to set any `systemd-user.conf(5)` option directly. For example, replace `systemd.user.extraConfig = "DefaultTimeoutStartSec=60";` with `systemd.user.settings.Manager.DefaultTimeoutStartSec = 60;`.
|
||||
|
||||
- `services.timesyncd.extraConfig` has been removed in favor of the structured [](#opt-services.timesyncd.settings.Time) option. Use `services.timesyncd.settings.Time` to set any `timesyncd.conf(5)` option directly. For example, replace `services.timesyncd.extraConfig = "PollIntervalMaxSec=180";` with `services.timesyncd.settings.Time.PollIntervalMaxSec = 180;`.
|
||||
|
||||
@@ -11,6 +11,9 @@ in
|
||||
{
|
||||
imports = [ ./installation-cd-graphical-base.nix ];
|
||||
|
||||
# required for calamares
|
||||
security.polkit.enablePkexecWrapper = true;
|
||||
|
||||
# required for kpmcore to work correctly
|
||||
programs.partition-manager.enable = true;
|
||||
|
||||
|
||||
@@ -330,7 +330,7 @@ in
|
||||
'';
|
||||
|
||||
config = lib.mkIf config.system.tools.nixos-rebuild.enableRun0Elevation {
|
||||
security.polkit.enable = lib.mkDefault true;
|
||||
security.run0.enable = lib.mkDefault true;
|
||||
environment.systemPackages = [ pkgs.polkit-stdin-agent ];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -60,7 +60,10 @@ in
|
||||
};
|
||||
|
||||
security = {
|
||||
polkit.enable = true;
|
||||
polkit = {
|
||||
enable = true;
|
||||
enablePkexecWrapper = lib.mkDefault true;
|
||||
};
|
||||
wrappers = lib.mkIf cfg.enableRenice {
|
||||
gamemoded = {
|
||||
owner = "root";
|
||||
|
||||
@@ -64,32 +64,36 @@ in
|
||||
# 3. Put ThroneCore into a systemd service, and let polkit check service name.
|
||||
# This is the most secure and convenient way but requires heavy modification
|
||||
# to Throne source code. Would be good to let upstream support that eventually.
|
||||
security.polkit.extraConfig =
|
||||
lib.mkIf (cfg.tunMode.enable && (!cfg.tunMode.setuid) && config.services.resolved.enable)
|
||||
''
|
||||
polkit.addRule(function(action, subject) {
|
||||
const allowedActionIds = [
|
||||
"org.freedesktop.resolve1.revert",
|
||||
"org.freedesktop.resolve1.set-domains",
|
||||
"org.freedesktop.resolve1.set-default-route",
|
||||
"org.freedesktop.resolve1.set-dns-servers"
|
||||
];
|
||||
security.polkit = {
|
||||
enable = true;
|
||||
enablePkexecWrapper = lib.mkDefault true;
|
||||
extraConfig =
|
||||
lib.mkIf (cfg.tunMode.enable && (!cfg.tunMode.setuid) && config.services.resolved.enable)
|
||||
''
|
||||
polkit.addRule(function(action, subject) {
|
||||
const allowedActionIds = [
|
||||
"org.freedesktop.resolve1.revert",
|
||||
"org.freedesktop.resolve1.set-domains",
|
||||
"org.freedesktop.resolve1.set-default-route",
|
||||
"org.freedesktop.resolve1.set-dns-servers"
|
||||
];
|
||||
|
||||
if (allowedActionIds.indexOf(action.id) !== -1) {
|
||||
try {
|
||||
var parentPid = polkit.spawn(["${lib.getExe' pkgs.procps "ps"}", "-o", "ppid=", subject.pid]).trim();
|
||||
var parentCap = polkit.spawn(["${lib.getExe' pkgs.libcap "getpcaps"}", parentPid]).trim();
|
||||
if (parentCap.includes("cap_net_admin") && parentCap.includes("cap_net_raw")) {
|
||||
return polkit.Result.YES;
|
||||
} else {
|
||||
if (allowedActionIds.indexOf(action.id) !== -1) {
|
||||
try {
|
||||
var parentPid = polkit.spawn(["${lib.getExe' pkgs.procps "ps"}", "-o", "ppid=", subject.pid]).trim();
|
||||
var parentCap = polkit.spawn(["${lib.getExe' pkgs.libcap "getpcaps"}", parentPid]).trim();
|
||||
if (parentCap.includes("cap_net_admin") && parentCap.includes("cap_net_raw")) {
|
||||
return polkit.Result.YES;
|
||||
} else {
|
||||
return polkit.Result.NOT_HANDLED;
|
||||
}
|
||||
} catch (e) {
|
||||
return polkit.Result.NOT_HANDLED;
|
||||
}
|
||||
} catch (e) {
|
||||
return polkit.Result.NOT_HANDLED;
|
||||
}
|
||||
}
|
||||
})
|
||||
'';
|
||||
})
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ aleksana ];
|
||||
|
||||
@@ -6,27 +6,52 @@
|
||||
}:
|
||||
let
|
||||
|
||||
cfg = config.security.polkit;
|
||||
inherit (lib)
|
||||
mkEnableOption
|
||||
mkOption
|
||||
mkIf
|
||||
mkPackageOption
|
||||
mkRemovedOptionModule
|
||||
types
|
||||
;
|
||||
|
||||
cfg = config.security.polkit;
|
||||
in
|
||||
|
||||
{
|
||||
imports = [
|
||||
(mkRemovedOptionModule [ "security" "polkit" "debug" ] "Use security.polkit.extraArgs instead")
|
||||
];
|
||||
|
||||
options = {
|
||||
options.security.polkit = {
|
||||
enable = mkEnableOption "polkit";
|
||||
|
||||
security.polkit.enable = lib.mkEnableOption "polkit";
|
||||
enablePkexecWrapper = mkEnableOption "the setuid pkexec wrapper";
|
||||
|
||||
security.polkit.package = lib.mkPackageOption pkgs "polkit" { };
|
||||
package = mkPackageOption pkgs "polkit" { };
|
||||
|
||||
security.polkit.debug = lib.mkEnableOption "debug logs from polkit. This is required in order to see log messages from rule definitions";
|
||||
extraArgs = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [
|
||||
"--no-debug"
|
||||
"--log-level=notice"
|
||||
];
|
||||
description = ''
|
||||
List of arguments to pass to the polkitd executable.
|
||||
|
||||
security.polkit.extraConfig = lib.mkOption {
|
||||
type = lib.types.lines;
|
||||
::: {.note}
|
||||
To see debug logs you need to negate the default `--no-debug` setting.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = ''
|
||||
/* Log authorization checks. */
|
||||
polkit.addRule(function(action, subject) {
|
||||
// Make sure to set { security.polkit.debug = true; } in configuration.nix
|
||||
// Make sure to negate --no-debug in services.polkit.extraArgs: { security.polkit.extraArgs = [ "--log-level=notice" ]; }
|
||||
polkit.log("user " + subject.user + " is attempting action " + action.id + " from PID " + subject.pid);
|
||||
});
|
||||
|
||||
@@ -41,8 +66,8 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
security.polkit.adminIdentities = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
adminIdentities = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [ "unix-group:wheel" ];
|
||||
example = [
|
||||
"unix-user:alice"
|
||||
@@ -58,25 +83,34 @@ in
|
||||
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
environment.systemPackages = [
|
||||
cfg.package.bin
|
||||
cfg.package.out
|
||||
];
|
||||
|
||||
services.dbus.packages = [ cfg.package.out ];
|
||||
|
||||
systemd.packages = [ cfg.package.out ];
|
||||
|
||||
systemd.services.polkit.serviceConfig.ExecStart = [
|
||||
""
|
||||
"${cfg.package.out}/lib/polkit-1/polkitd ${lib.optionalString (!cfg.debug) "--no-debug"}"
|
||||
];
|
||||
|
||||
systemd.services.polkit.restartTriggers = [ config.system.path ];
|
||||
systemd.services.polkit.reloadTriggers = [
|
||||
config.environment.etc."polkit-1/rules.d/10-nixos.rules".source
|
||||
];
|
||||
systemd.services.polkit.stopIfChanged = false;
|
||||
systemd.services.polkit = {
|
||||
restartTriggers = [ config.system.path ];
|
||||
reloadTriggers = [
|
||||
config.environment.etc."polkit-1/rules.d/10-nixos.rules".source
|
||||
];
|
||||
serviceConfig.ExecStart = [
|
||||
# nuke default ExecStart
|
||||
""
|
||||
# provide our own instead
|
||||
(toString (
|
||||
[
|
||||
"${lib.getLib cfg.package}/lib/polkit-1/polkitd"
|
||||
]
|
||||
++ cfg.extraArgs
|
||||
))
|
||||
];
|
||||
};
|
||||
|
||||
systemd.sockets."polkit-agent-helper".wantedBy = [ "sockets.target" ];
|
||||
|
||||
@@ -89,7 +123,7 @@ in
|
||||
# The upstream unit uses PrivateDevices=yes and ProtectHome=yes,
|
||||
# which prevents PAM modules from accessing hardware (e.g. FIDO
|
||||
# tokens via /dev/hidraw*) or reading key files from home directories.
|
||||
(lib.mkIf config.security.pam.u2f.enable {
|
||||
(mkIf config.security.pam.u2f.enable {
|
||||
# Override upstream PrivateDevices=yes to allow access to /dev/hidraw*
|
||||
PrivateDevices = false;
|
||||
DeviceAllow = [
|
||||
@@ -100,7 +134,7 @@ in
|
||||
# ~/.config/Yubico/u2f_keys (the default key file location)
|
||||
ProtectHome = "read-only";
|
||||
})
|
||||
(lib.mkIf config.security.pam.zfs.enable {
|
||||
(mkIf config.security.pam.zfs.enable {
|
||||
PrivateDevices = false;
|
||||
DeviceAllow = [
|
||||
"/dev/zfs rw"
|
||||
@@ -120,23 +154,16 @@ in
|
||||
${cfg.extraConfig}
|
||||
''; # TODO: validation on compilation (at least against typos)
|
||||
|
||||
services.dbus.packages = [ cfg.package.out ];
|
||||
|
||||
security.pam.services.polkit-1 = { };
|
||||
|
||||
security.wrappers.pkexec = {
|
||||
enable = cfg.enablePkexecWrapper;
|
||||
setuid = true;
|
||||
owner = "root";
|
||||
group = "root";
|
||||
source = "${cfg.package.bin}/bin/pkexec";
|
||||
source = lib.getExe' cfg.package "pkexec";
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
# Probably no more needed, clean up
|
||||
"R /var/lib/polkit-1"
|
||||
"R /var/lib/PolicyKit"
|
||||
];
|
||||
|
||||
users.users.polkituser = {
|
||||
description = "PolKit daemon";
|
||||
uid = config.ids.uids.polkituser;
|
||||
|
||||
@@ -6,6 +6,13 @@
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (lib)
|
||||
mkEnableOption
|
||||
mkIf
|
||||
mkMerge
|
||||
mkOption
|
||||
;
|
||||
|
||||
cfg = config.security.run0;
|
||||
|
||||
sudoAlias = pkgs.writeShellScriptBin "sudo" ''
|
||||
@@ -18,7 +25,9 @@ let
|
||||
in
|
||||
{
|
||||
options.security.run0 = {
|
||||
wheelNeedsPassword = lib.mkOption {
|
||||
enable = mkEnableOption "support for run0";
|
||||
|
||||
wheelNeedsPassword = mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
@@ -27,26 +36,45 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
enableSudoAlias = lib.mkEnableOption "make {command}`sudo` an alias to {command}`run0`.";
|
||||
enableSudoAlias = mkEnableOption "make {command}`sudo` an alias to {command}`run0`.";
|
||||
};
|
||||
|
||||
config = {
|
||||
assertions = [
|
||||
{
|
||||
assertion =
|
||||
cfg.enableSudoAlias -> (!config.security.sudo.enable && !config.security.sudo-rs.enable);
|
||||
message = "`security.run0.enableSudoAlias` cannot be enabled if `security.sudo` or `security.sudo-rs` are enabled.";
|
||||
}
|
||||
];
|
||||
|
||||
security.polkit.extraConfig = lib.mkIf (!cfg.wheelNeedsPassword) ''
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (action.id == "org.freedesktop.systemd1.manage-units" && subject.isInGroup("wheel")) {
|
||||
return polkit.Result.YES;
|
||||
config = mkMerge [
|
||||
{
|
||||
# Late introduction of the enable toggle, this should help during migration.
|
||||
# TODO: Remove after 26.11 release
|
||||
assertions = [
|
||||
{
|
||||
assertion = !cfg.wheelNeedsPassword -> cfg.enable;
|
||||
message = "`security.run0.enable` is currently disabled, but is required for the `security.run0.wheelNeedsPassword` option to take effect";
|
||||
}
|
||||
});
|
||||
'';
|
||||
{
|
||||
assertion = cfg.enableSudoAlias -> cfg.enable;
|
||||
message = "`security.run0.enableSudoAlias` depends on `security.run0.enable`, which is disabled.";
|
||||
}
|
||||
];
|
||||
}
|
||||
(mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion =
|
||||
cfg.enableSudoAlias -> (!config.security.sudo.enable && !config.security.sudo-rs.enable);
|
||||
message = "`security.run0.enableSudoAlias` cannot be enabled if `security.sudo` or `security.sudo-rs` are enabled.";
|
||||
}
|
||||
];
|
||||
|
||||
environment.systemPackages = lib.optional cfg.enableSudoAlias sudoAlias;
|
||||
};
|
||||
security.polkit = {
|
||||
enable = true;
|
||||
extraConfig = mkIf (!cfg.wheelNeedsPassword) ''
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (action.id == "org.freedesktop.systemd1.manage-units" && subject.isInGroup("wheel")) {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
'';
|
||||
};
|
||||
|
||||
environment.systemPackages = lib.optional cfg.enableSudoAlias sudoAlias;
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
@@ -243,6 +243,8 @@ in
|
||||
|
||||
# Required by Budgie's Polkit Dialog.
|
||||
security.polkit.enable = mkDefault true;
|
||||
# Required by Budige's Control Center and Desktop
|
||||
security.polkit.enablePkexecWrapper = mkDefault true;
|
||||
|
||||
# Required by Budgie Panel plugins and/or Budgie Control Center panels.
|
||||
networking.networkmanager.enable = mkDefault true; # for BCC's Network panel.
|
||||
|
||||
@@ -146,7 +146,10 @@ in
|
||||
environment.sessionVariables.X11_EXTRA_RULES_XML = "${config.services.xserver.xkb.dir}/rules/base.extras.xml";
|
||||
programs.dconf.enable = true;
|
||||
programs.dconf.packages = [ pkgs.cosmic-session ];
|
||||
security.polkit.enable = true;
|
||||
security.polkit = {
|
||||
enable = true;
|
||||
enablePkexecWrapper = lib.mkDefault true;
|
||||
};
|
||||
security.rtkit.enable = true;
|
||||
services.accounts-daemon.enable = true;
|
||||
services.displayManager.sessionPackages = [ pkgs.cosmic-session ];
|
||||
|
||||
@@ -325,7 +325,11 @@ in
|
||||
i18n.inputMethod.enable = mkDefault true;
|
||||
i18n.inputMethod.type = mkDefault "ibus";
|
||||
programs.dconf.enable = true;
|
||||
security.polkit.enable = true;
|
||||
security.polkit = {
|
||||
enable = true;
|
||||
# Required by gnome-initial-setup, gnome-system-monitor, gvfs for admin://
|
||||
enablePkexecWrapper = lib.mkDefault true;
|
||||
};
|
||||
security.rtkit.enable = mkDefault true;
|
||||
services.accounts-daemon.enable = true;
|
||||
services.dleyna.enable = mkDefault true;
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
config = lib.mkIf config.services.gnome.gnome-remote-desktop.enable {
|
||||
services.pipewire.enable = true;
|
||||
services.dbus.packages = [ pkgs.gnome-remote-desktop ];
|
||||
security.polkit = {
|
||||
enable = true;
|
||||
enablePkexecWrapper = lib.mkDefault true;
|
||||
};
|
||||
|
||||
environment.systemPackages = [ pkgs.gnome-remote-desktop ];
|
||||
|
||||
|
||||
@@ -246,7 +246,10 @@ in
|
||||
systemPackages = [ cfg.package ];
|
||||
};
|
||||
|
||||
security.polkit.enable = lib.mkDefault true;
|
||||
security.polkit = {
|
||||
enable = lib.mkDefault true;
|
||||
enablePkexecWrapper = lib.mkDefault true;
|
||||
};
|
||||
|
||||
services = {
|
||||
dbus.packages = [ cfg.package ];
|
||||
|
||||
@@ -111,7 +111,10 @@ in
|
||||
services.blueman.enable = mkDefault (notExcluded pkgs.blueman);
|
||||
services.hardware.bolt.enable = mkDefault (notExcluded pkgs.bolt);
|
||||
hardware.bluetooth.enable = mkDefault true;
|
||||
security.polkit.enable = true;
|
||||
security.polkit = {
|
||||
enable = true;
|
||||
enablePkexecWrapper = lib.mkDefault true;
|
||||
};
|
||||
services.accounts-daemon.enable = true;
|
||||
services.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
|
||||
services.dbus.packages = with pkgs; [
|
||||
|
||||
@@ -220,7 +220,10 @@ in
|
||||
|
||||
# Enable helpful DBus services.
|
||||
services.udisks2.enable = true;
|
||||
security.polkit.enable = true;
|
||||
security.polkit = {
|
||||
enable = true;
|
||||
enablePkexecWrapper = lib.mkDefault true;
|
||||
};
|
||||
services.accounts-daemon.enable = true;
|
||||
services.upower.enable = config.powerManagement.enable;
|
||||
services.gnome.glib-networking.enable = true;
|
||||
|
||||
@@ -1701,6 +1701,7 @@ in
|
||||
tiddlywiki = runTest ./tiddlywiki.nix;
|
||||
tigervnc = handleTest ./tigervnc.nix { };
|
||||
tika = runTest ./tika.nix;
|
||||
timekpr = runTest ./timekpr.nix;
|
||||
timezone = runTest ./timezone.nix;
|
||||
timidity = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./timidity { };
|
||||
tinc = handleTest ./tinc { };
|
||||
|
||||
@@ -669,7 +669,7 @@ in
|
||||
|
||||
# Doing this here, since we need an in-session shell & separately starting a terminal again wastes time
|
||||
with subtest("polkit agent works"):
|
||||
machine.send_chars("pkexec touch /tmp/polkit-test\n")
|
||||
machine.send_chars("run0 touch /tmp/polkit-test\n")
|
||||
# There's an authentication notification here that gains focus, but we struggle with OCRing it
|
||||
# Just hope that it's up after a short wait
|
||||
machine.sleep(10)
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
# Provide a little logging of polkit checks - otherwise it's
|
||||
# impossible to know what's going on.
|
||||
security.polkit.debug = true;
|
||||
security.polkit.extraArgs = [ "--log-level=notice" ];
|
||||
security.polkit.extraConfig = ''
|
||||
polkit.addRule(function(action, subject) {
|
||||
const ns = "org.freedesktop.RealtimeKit1.";
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
{ pkgs, lib, ... }:
|
||||
{
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
name = "timekpr";
|
||||
meta.maintainers = [ lib.maintainers.atry ];
|
||||
|
||||
nodes.machine =
|
||||
{ pkgs, lib, ... }:
|
||||
{
|
||||
services.timekpr.enable = true;
|
||||
};
|
||||
containers.machine = {
|
||||
services.timekpr.enable = true;
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
Reference in New Issue
Block a user