场景 1:允许普通用户挂载外部USB驱动器
这个场景完美体现了从“命令控制”到“动作控制”的范式转变。
1. 使用 sudo
/ doas
实现(传统方式)
思路: 找到挂载命令(mount
, udisksctl
),授权用户执行它。
-
sudo
配置 (visudo
):# 授权用户 alice 执行 mount 命令来挂载 /dev/sdb1 这个特定设备(不灵活) alice ALL=(root) /usr/bin/mount /dev/sdb1 /mnt/usb# 或者,更危险地:授权 alice 挂载任何设备(极度不安全!) alice ALL=(root) /usr/bin/mount# 更现代的做法:授权使用 udisksctl 命令(桌面环境实际在后台使用的) alice ALL=(root) /usr/bin/udisksctl mount -b /dev/sdb1
缺点: 非常不灵活。设备名(
/dev/sdb1
)会变,且授权整个mount
命令风险极高。 -
doas
配置 (/etc/doas.conf
):# 和 sudo 类似,语法更简洁 permit alice as root cmd /usr/bin/udisksctl mount -b /dev/sdb1
缺点: 同样存在灵活性和安全性的问题。
2. 使用 polkit
实现(现代方式)
思路: 定义“允许普通用户挂载可移动存储设备”这个动作。
-
Polkit 规则文件 (
/etc/polkit-1/rules.d/10-allow-mount.rules
):polkit.addRule(function(action, subject) {if (action.id == "org.freedesktop.udisks2.filesystem-mount-system" &&subject.isInGroup("users")) {return polkit.Result.YES;} });
或者,更简单的方法: 大多数发行版已经自带了默认规则,通常位于
/usr/share/polkit-1/rules.d/
,你只需要确认或轻微修改即可。
-------------------
场景 2:允许普通用户重启系统
这是一个经典需求,对比非常明显。
1. 使用 sudo
/ doas
实现
思路: 授权 reboot
或 systemctl reboot
命令。
-
sudo
配置:# 授权 wheel 组用户执行重启命令 %wheel ALL=(root) /usr/bin/systemctl reboot
-
doas
配置:# 授权 wheel 组用户执行重启命令 permit :wheel as root cmd /usr/bin/systemctl reboot
用户体验: 在终端中需要输入 sudo systemctl reboot
或 doas systemctl reboot
,然后输入自己的密码。
2. 使用 polkit
实现
思路: 定义“允许控制台本地用户或某些组用户重启系统”这个动作。
-
Polkit 规则文件 (
/etc/polkit-1/rules.d/10-allow-reboot.rules
):polkit.addRule(function(action, subject) {if (action.id == "org.freedesktop.login1.reboot" ||action.id == "org.freedesktop.login1.reboot-multiple-sessions") {if (subject.isInGroup("wheel")) {return polkit.Result.YES;}// 或者更精细:允许本地活动会话用户无需密码// if (subject.active && subject.local) {// return polkit.Result.YES;// }} });
用户体验:
-
图形界面 (GUI): 在GNOME/KDE的菜单中点击“重启”,不会弹出密码框,直接执行。体验无缝。
-
命令行 (CLI): 用户可以直接使用
systemctl reboot
,同样不会提示密码。或者使用pkexec systemctl reboot
,这会弹出一个图形化的认证对话框。
对比分析:
-
sudo/doas
: 只能在命令行使用,且体验一致:需要输入密码。 -
polkit
: 提供了统一的后端策略,同时服务于图形前端和命令行后端,并能根据上下文(用户组、会话位置)提供不同的认证体验。 -
--------------------场景 3:允许开发用户绑定到特权端口(如80端口)
-
Web开发常见需求,需要绑定1024以下的端口。
1. 使用
sudo
/doas
实现(危险!)思路: 授权用户以 root 权限运行 Node.js、Python 等服务器程序。
-
sudo
配置:# 授权用户 devuser 以 root 身份运行 /usr/bin/node devuser ALL=(root) /usr/bin/node /path/to/app.js
巨大风险: 这意味着这个脚本拥有了完全的 root 权限,可以执行任何操作,极度危险。
2. 使用
setcap
实现(更安全的方式,但仍属 sudo/doas 范畴)思路: 给特定的二进制文件授予特定权限,而不是给用户。
-
命令行:
# 授予 node 二进制文件绑定到特权端口的能力 sudo setcap 'cap_net_bind_service=+ep' /usr/bin/node
优点: 比直接以 root 运行整个程序安全得多。
缺点: 权限被授予了整个二进制文件。任何用户都可以用/usr/bin/node
来绑定特权端口。
3. 使用
polkit
实现(不适用)结论: 对于这种“给程序文件本身赋予能力”的场景,不是 Polkit 的设计目标。Polkit 管理的是用户动作的授权。
本场景最佳实践: 使用
setcap
是一种改进,但最好的方式是使用反向代理(如 Nginx)或将服务配置为通过 systemd socket 激活,从而完全避免让用户进程直接处理特权端口。 -