必须用绝对路径+systemctl显式命令组合并优先通过/etc/sudoers.d/管理,因sudoers仅支持精确字符串匹配,不解析通配符、shell扩展或service兼容层,否则易被绕过或锁死sudo。

直接给结论:不能用模糊匹配或通配符,必须用绝对路径 + systemctl 显式命令组合,并优先走 /etc/sudoers.d/ 单独文件管理。否则极易被绕过或因语法错误锁死 sudo。
为什么不能写 service nginx restart 或 /usr/bin/systemctl * nginx
systemd 环境下,service 命令只是兼容层包装,实际调用 systemctl;而通配符(*)、shell 扩展(如 restart *)在 sudoers 中完全不生效,且显式禁止——它只认字面量命令路径。更危险的是,如果只写 /usr/bin/systemctl 不带参数,用户可执行 sudo systemctl start sshd 甚至 sudo systemctl edit --full nginx,等同于任意服务控制权。
- 所有命令必须写完整绝对路径:
/usr/bin/systemctl,不是systemctl - 每个允许的操作都要单独列出:
/usr/bin/systemctl restart nginx、/usr/bin/systemctl reload nginx、/usr/bin/systemctl status nginx -
/usr/bin/systemctl后面的空格和参数是规则的一部分,少一个空格或拼错单词(如restar)都会拒绝执行
怎么用 Cmnd_Alias 把多个服务操作打包管理
运维人员常需管不止一个服务(比如 nginx + redis + prometheus),硬编码每条规则难维护。用 Cmnd_Alias 是标准解法,把命令集合命名后统一授权。
- 新建文件:
sudo visudo -f /etc/sudoers.d/ops-web - 写入别名定义(注意缩进无关,但逗号后必须有空格):
Cmnd_Alias WEB_SERVICES = \ /usr/bin/systemctl start nginx, \ /usr/bin/systemctl stop nginx, \ /usr/bin/systemctl restart nginx, \ /usr/bin/systemctl reload nginx, \ /usr/bin/systemctl status nginx, \ /usr/bin/systemctl start redis-server, \ /usr/bin/systemctl status redis-server - 绑定用户组(推荐,比单个用户更易扩展):
%webops ALL=(root) NOPASSWD: WEB_SERVICES
- 确保该组存在:
sudo groupadd webops && sudo usermod -aG webops alice
验证时最容易忽略的三个细节
配置完不测试,等于没配。但测试方式不对,会误判成功。
- 切到目标用户后,先运行
sudo -l -U alice,确认输出里明确列出你授权的那几条/usr/bin/systemctl ...,而不是只显示(root) NOPASSWD: WEB_SERVICES—— 后者说明别名没加载或路径写错 - 执行
sudo systemctl restart nginx时,如果报错Failed to connect to bus: No such file or directory,不是权限问题,是没进 systemd 用户 session;改用sudo -i systemctl restart nginx或确保在有 dbus 的终端中运行 - 修改后必须检查文件权限:
ls -l /etc/sudoers.d/ops-web必须是-r--r----- 1 root root(即 0440),否则整条规则被忽略,且无任何提示
真正难的不是写那几行规则,而是意识到:sudoers 不是 shell 脚本,它不解析参数、不展开变量、不支持正则——它只做精确字符串匹配。任何想“省事”的写法,最后都得花三倍时间排查。











