VPN 按钮在管理员手里能用,在其他人手里却失败,于是有人往 sudoers 里加了一行。那行通常比它要解决的问题活得更久,而且往往授予了按钮并不需要的权限。修改策略之前,先确认受支持的连接所有者是否已经能完成这项工作。下面三个条件决定 sudo 到底该不该出场。

条件 1:受支持的所有者无需 sudo 即可完成

在大多数 Linux 桌面上,网络管理器本身就持有 VPN 连接,其授权走的是 polkit 而不是 sudo。被允许启用连接的用户可以直接在命令行完成,不需要任何 root 规则。在假定按钮需要特权之前,先看看管理器允许什么。如果答案是肯定的,那么修改 sudoers 就是在解决一个并不存在的问题。

nmcli connection show
nmcli connection up "Work VPN"

如果管理器拒绝,先读原因:缺少 polkit 规则、连接属于另一个用户,或者配置文件存放在该用户读不到的位置。这些情况各自都有比 sudo 规则更窄的受支持修法。提权是最后手段,而不是第一手段。

条件 2:规则只点名一个可执行文件及其参数

如果确实需要 sudo,规则应当点名确切的命令,并在可能时点名它可用的参数。允许用户运行包装脚本的规则,其安全性只等于该脚本的权限,因为用户可以改动 root 将要执行的内容。在命令后面加通配符的规则,只是同一问题的更短形式。

sudo -l -U alice
ls -l /usr/local/sbin/vpn-up

检查命令链上的每一条路径:二进制文件、它调用的脚本、它读取的配置文件,以及它们之间的任何目录。只要其中任何一个用户可写,这条受限规则实际上就是不受限制的 root。参数同样重要,因为接受配置路径的命令可以被指向用户控制的文件。规则要为这项操作而写,而不是为按钮而写。

如果命令必须依赖用户控制才能工作,就停下来。那说明设计是错的,任何 sudoers 语法都救不了它。

条件 3:解析的是整份策略,而不只是你那一行

用会锁定文件并检查语法的编辑器来校验,而且要校验拼装后的整份策略,而不是一个片段。单独能解析的文件,仍可能破坏包含顺序,或以一种改变行为的方式重复某条规则。visudo 手册 同时记录了这里用到的锁定式编辑器和只检查模式。

sudo visudo -c
sudo visudo -cf /etc/sudoers.d/vpn-launcher

检查失败时会报告文件和行号,那份报告才是有用的部分。应当通过编辑器修正原本要做的改动,而不是强行保存一个已知错误,因为坏掉的策略会一次锁死所有管理员。包含目录下的文件还需要手册所要求的属主和权限模式,否则会被忽略或拒绝。语法只是第一道门:通过之后,再读一遍这条规则,问问它实际允许了什么。

如果让改动生效的唯一办法是关掉语法检查,就停下来。那不是策略,那是一场等着重启的故障。

恢复:保留一个仍然可用的会话

保存之前,先确保已经有一个已授权的管理会话打开,并且存在进入机器的第二条路径。一个 sudoers 错误就可能夺走你修复它的能力,而桌面按钮不值得冒这个险。如果 sudo 已经坏了,请使用系统文档记录的恢复路径,而不是自己临时发明一条。

sudo -n true
id

像 pkexec 这样的替代方案依赖各自的安装和策略,因此并不是有保证的第二个 root 提示。同样要把本地授权与提供 VPN 密钥分开:sudo 规则无法解锁并不存在的密钥代理,也满足不了网关的多因素认证。修正之后,先用普通账户只执行预期操作来测试,然后再使用管理器的常规控件。

当你能够说清是哪个条件使 sudo 成立、规则点名了什么、整份策略能够解析,以及万一不行该如何恢复时,这个决定才算结束。一个让你失去管理访问权的特权启动器是糟糕的交易,而且通常是可以避免的。

相关文章