跳转至内容

polkit

来自 ArchWiki

来自 polkit 主页

polkit 是一个应用程序级别的工具包,用于定义和处理策略,允许未授权的进程与授权的进程通信:它是一个框架,用于集中决策过程,以授予未授权应用程序访问授权操作的权限。

Polkit 用于控制系统范围的权限。它为非授权进程与授权进程通信提供了一种有组织的方式。与 sudo 等系统不同,它不授予整个进程 root 权限,而是允许对集中式系统策略进行更精细级别的控制。

Polkit 通过界定不同的操作(例如运行 GParted)和按组或按名称界定用户(例如 wheel 组成员)来工作。然后,它定义这些用户如何(如果可以)被允许执行这些操作,例如通过输入密码来识别为组成员。

安装

安装 polkit 包。

认证代理

认证代理用于让会话的用户证明他们确实是该用户(通过以该用户身份进行身份验证)或管理员用户(通过以管理员身份进行身份验证)。polkit 包包含 pkttyagent,一个文本认证代理,用作通用后备。

如果您正在使用图形环境,请确保已安装图形认证代理并在登录时 自动启动(例如通过 xinitrc)。

CinnamonDeepinHyprlandGNOMEGNOME FlashbackKDELXDELXQtMATEXfce 已内置认证代理。在其他 桌面环境 中,您需要选择以下实现之一:


提示 继续之前,请通过查看进程列表来检查您的自动启动配置。例如,使用 pgrep -af polkit-gnome

配置

警告 请勿修改软件包的默认权限文件,因为它们可能在软件包升级时被覆盖。

Polkit 定义可分为两种类型

  • 操作 定义在 XML .policy 文件中,位于 /usr/share/polkit-1/actions。每个操作都附带一组默认权限(例如,您需要以管理员身份进行身份验证才能使用 GParted 操作)。默认设置可以被覆盖,但编辑操作文件不是正确的方法。
  • 授权规则 定义在 JavaScript .rules 文件中。它们存在于两个位置:
    • 第三方软件包可以使用 /usr/share/polkit-1/rules.d
    • /etc/polkit-1/rules.d 用于本地配置。

Polkit 操作基于现有的 Linux 权限系统(组 membership、管理员状态),它并不取代它们。.rules 文件指定用户子集,引用操作文件中指定的一个(或多个)操作,并确定这些用户可以以何种限制来执行这些操作。例如,一个 rules 文件可以覆盖所有用户在使用 GParted 时需要管理员身份验证的默认要求,确定某个特定用户不需要。另一个例子:不允许某个用户使用 GParted。

注意 这并不排除通过不遵守 polkit 的方式运行 GParted,例如命令行。因此,polkit 应用于扩展非授权用户对授权服务的访问,而不是试图限制(半)授权用户的权利。出于安全原因,sudoers 仍然是首选方法。

操作

提示 要在图形界面中显示 Policykit 操作,请安装 polkit-explorer-gitAUR 包。

您通过 polkit 可用的操作取决于您安装的软件包。有些用于多个桌面环境(org.freedesktop.*),有些是特定于 DE 的(org.gnome.*),有些是特定于单个程序的(org.gnome.gparted.policy)。pkaction 命令快速列出 /usr/share/polkit-1/actions 中定义的所有操作。

为了了解 polkit 的功能,这里有一些常用的操作组:

  • systemd-logind (org.freedesktop.login1.policy) 由 polkit 调节的操作包括关闭、重启、挂起和休眠系统,即使其他用户可能仍然登录。
  • udisks (org.freedesktop.udisks2.policy) 由 polkit 调节的操作包括挂载文件系统和解锁加密设备。
  • NetworkManager (org.freedesktop.NetworkManager.policy) 由 polkit 调节的操作包括开启和关闭网络、Wi-Fi 或移动宽带。

每个操作都在 .policy 文件中的 <action> 标签中定义。org.gnome.gparted.policy 包含一个操作,看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC
 "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
 "http://www.freedesktop.org/software/polkit/policyconfig-1.dtd">
<policyconfig>

  <action id="org.gnome.gparted">
    <message>Authentication is required to run the GParted Partition Editor</message>
    <icon_name>gparted</icon_name>
    <defaults>
      <allow_any>auth_admin</allow_any>
      <allow_inactive>auth_admin</allow_inactive>
      <allow_active>auth_admin</allow_active>
    </defaults>
    <annotate key="org.freedesktop.policykit.exec.path">/usr/bin/gparted</annotate>
    <annotate key="org.freedesktop.policykit.exec.allow_gui">true</annotate>
  </action>

</policyconfig>

id 属性是发送到 D-Bus 的实际命令,message 标签是在需要身份验证时向用户显示的解释,icon_name 顾名思义。

defaults 标签是权限或无权限所在的地方。它包含三个设置:allow_anyallow_inactiveallow_active。这里的 inactive 和 active 都指的是本地控制台或显示器上的本地会话,而 allow_any 设置用于所有其他情况,包括远程会话(SSH、VNC 等)。

对于这些设置中的每一个,都有以下选项可用:

  • no:用户无权执行该操作。因此无需进行身份验证。
  • yes:用户有权执行该操作,无需任何身份验证。
  • auth_self:需要身份验证,但用户不一定是管理员。
  • auth_admin:需要以管理员身份进行身份验证。
  • auth_self_keep:与 auth_self 相同,但与 sudo 一样,授权会持续几分钟。
  • auth_admin_keep:与 auth_admin 相同,但与 sudo 一样,授权会持续几分钟。

这些是默认设置,除非在后续配置中被覆盖,否则将对所有用户有效。

有关详细说明,请参阅 polkit(8) man page。

正如 GParted 操作所示,用户需要以管理员身份进行身份验证才能使用 GParted,无论会话是活动的还是不活动的。

授权规则

/etc/polkit-1/rules.d 中添加自定义规则或覆盖默认设置。规则必须具有 root:polkitd 所有权。添加新规则后,重新加载 polkit.service

addRule() 方法用于添加一个函数,该函数可以在执行操作和主体的授权检查时被调用。函数按添加顺序调用,直到其中一个函数返回一个值。因此,要添加一个在其他规则之前处理的授权规则,请将其放入 /etc/polkit-1/rules.d 中一个名称可以排序在其他规则文件之前的 name,例如 00-early-checks.rules

.rules 文件的布局相当直观

/* Allow users in admin group to run GParted without authentication */
polkit.addRule(function(action, subject) {
    if (action.id == "org.gnome.gparted" &&
        subject.isInGroup("admin")) {
        return polkit.Result.YES;
    }
});

在函数内部,我们检查指定的 action ID(org.gnome.gparted)和用户的组(admin),然后返回“yes”值。

管理员身份

addAdminRule() 方法用于添加一个函数,该函数可以在需要管理员身份验证时被调用。该函数用于指定由操作和主体标识的授权检查所使用的管理员身份验证的身份。添加的函数按添加顺序调用,直到其中一个函数返回一个值。

管理员身份的默认配置包含在文件 /usr/share/polkit-1/rules.d/50-default.rules 中,因此对该配置的任何更改都应通过将文件复制到 /etc/polkit-1/rules.d 目录并编辑该文件来完成。

/etc/polkit-1/rules.d/50-default.rules
polkit.addAdminRule(function(action, subject) {
    return ["unix-group:wheel"];
});

(复制后)唯一需要编辑的部分是函数的返回数组:用户在被要求以管理员身份验证时,应该以谁的身份进行身份验证?如果他们是指定为管理员的组成员,他们只需要输入自己的密码。如果其他用户,例如 root,是唯一的管理员身份,他们将需要输入 root 密码。用户身份的格式与指定权限时使用的格式相同。

Arch 的默认设置是将 wheel 组的所有成员视为管理员。如下规则将使 polkit 在进行管理员身份验证时询问 root 密码而不是用户的密码。

/etc/polkit-1/rules.d/49-rootpw_global.rules
/* Always authenticate Admins by prompting for the root
 * password, similar to the rootpw option in sudo
 */
polkit.addAdminRule(function(action, subject) {
    return ["unix-user:root"];
});

密码过期

返回 AUTH_SELF_KEEPAUTH_ADMIN_KEEP 的 Polkit 规则默认每 5 分钟才询问一次密码。这可以在 polkitd 配置文件中进行配置。

/etc/polkit-1/polkitd.conf
[Polkitd]
ExpirationSeconds=300

示例

允许用户使用 org.freedesktop.timedate1.set-timezone 操作

为了允许名为 archie 的用户在无需身份验证的情况下使用 org.freedesktop.timedate1.set-timezone 操作,请以 root 身份创建以下 polkit 规则文件:

/etc/polkit-1/rules.d/49-allow-archie-set-timezone.rules
polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.timedate1.set-timezone" &&
        subject.user == "archie") {
        return polkit.Result.YES;
    }
});

保存规则文件后,策略应立即生效。您可以通过使用 timedatectl 来测试它。

[archie]$ timedatectl set-timezone America/New_York

如果操作在不要求身份验证的情况下完成,则规则按预期工作。如果操作似乎不允许,请确保 /etc/polkit-1/rules.d/ 中没有具有更高优先级的冲突规则(数字前缀较低)。

调试/日志记录

要使用 polkit.log() 函数启用日志记录,请从 polkit.service 文件的 ExecStart 命令中删除 --no-debug 标志;可以通过 临时编辑 unit(使用 systemctl --runtime)或永久编辑:

/etc/systemd/system/polkit.service.d/debug.conf
[Service]
ExecStart=
ExecStart=/usr/lib/polkit-1/polkitd --log-level=notice

以下规则记录有关任何请求访问的详细信息:

/etc/polkit-1/rules.d/00-log-access.rules
polkit.addRule(function(action, subject) {
    polkit.log("action=" + action);
    polkit.log("subject=" + subject);
});

要手动测试规则,请使用 pkcheck[1]

$ pkcheck -u -p $$ --enable-internal-agent -a action

禁用挂起和休眠

本文或本章节的准确性存在争议。

原因:如果 logind 不可用,systemctl(1) 会回退到直接启动 suspend.target/hibernate.target。要实际禁用 systemd-sleep,应使用 Power management/Suspend and hibernate#Disable sleep completely。(在 Talk:Polkit 中讨论)

以下规则禁用所有用户的挂起和休眠。

/etc/polkit-1/rules.d/10-disable-suspend.rules
polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.login1.suspend" ||
        action.id == "org.freedesktop.login1.suspend-multiple-sessions" ||
        action.id == "org.freedesktop.login1.hibernate" ||
        action.id == "org.freedesktop.login1.hibernate-multiple-sessions")
    {
        return polkit.Result.NO;
    }
});

绕过密码提示

要实现类似于 sudoNOPASSWD 选项,并且仅根据 用户/组 身份进行授权,您可以在 /etc/polkit-1/rules.d/ 中创建自定义规则。这允许您覆盖密码身份验证,可以是 仅针对特定操作全局。有关示例规则集,请参阅 [2]

全局

以 root 身份创建以下文件:

/etc/polkit-1/rules.d/49-nopasswd_global.rules
/* Allow members of the wheel group to execute any actions
 * without password authentication, similar to "sudo NOPASSWD:"
 */
polkit.addRule(function(action, subject) {
    if (subject.isInGroup("wheel")) {
        return polkit.Result.YES;
    }
});

wheel 替换为您喜欢的任何组。

这将导致对 Polkit 所需的任何需要管理员权限的操作自动进行身份验证。因此,请谨慎选择您要赋予此类权限的组。

还有 AUTH_ADMIN_KEEP,它允许将授权保留 5 分钟。

polkit 127 上的 run0 默认保留授权。

针对特定操作

以 root 身份创建以下文件:

/etc/polkit-1/rules.d/49-nopasswd_limited.rules
/* Allow members of the wheel group to execute the defined actions 
 * without password authentication, similar to "sudo NOPASSWD:"
 */
polkit.addRule(function(action, subject) {
    if ((action.id == "org.gnome.gparted" ||
	 action.id == "org.libvirt.unix.manage") &&
        subject.isInGroup("wheel"))
    {
        return polkit.Result.YES;
    }
});

这里选择的 action.ids 仅仅是 GParted 和 Libvirt 的(有效的)示例,但您可以将它们替换为您喜欢的任何其他操作,只要它们存在(自定义或由软件包提供),您也可以定义任何组而不是 wheel

|| 操作符用于分隔操作(逻辑 OR),而 && 表示逻辑 AND,并且必须作为最后一个操作符保留。

Udisks

文件管理器在尝试挂载存储设备时可能会要求输入密码,或显示“未授权”或类似的错误。有关详细信息,请参阅 Udisks#Configuration

允许普通用户管理单个 systemd 服务

通过检查传递给 polkit 策略检查的特定值,您可以授予特定用户或组管理特定服务的权限。例如,您可能希望普通用户启动和停止 wpa_supplicant

/etc/polkit-1/rules.d/10-wifimanagement.rules
polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.systemd1.manage-units") {
        if (action.lookup("unit") == "wpa_supplicant.service") {
            var verb = action.lookup("verb");
            if (verb == "start" || verb == "stop" || verb == "restart") {
                return polkit.Result.YES;
            }
        }
    }
});

参见