给 sudoers 加一条 NOPASSWD 规则(最小授权 + 别动 visudo 之外的)

经常需要让某用户 / 自动化脚本运行少数特权命令,但又不想 sudo 让对方做任何事,
也不想每次输密码。正确做法是写一条 最小授权 的 NOPASSWD 规则。

三条原则

  1. 永远用 visudo —— 改坏 /etc/sudoers 没法回滚,全机 sudo 失效
  2. 放到 /etc/sudoers.d/* 而不是主文件 —— 单文件出错只影响一个 drop-in
  3. 绝对路径 + 精确命令 —— 别用 wildcard,更别 ALL

例子:让 deploy 用户重启某个特定服务

sudo visudo -f /etc/sudoers.d/deploy

内容:

# 让 deploy 用户不需要密码就能重启 app.service,且只能这个
deploy ALL=(root) NOPASSWD: /bin/systemctl restart app.service, \
                            /bin/systemctl status app.service, \
                            /bin/systemctl reload nginx.service

注意三件事:

  • 第一个 ALL 是允许在 哪些 host 上有效(sudoers 是网络共享时有用)
  • (root) 是允许切换为哪个用户身份
  • 命令必须是 绝对路径,并且每个参数都精确写出

如果只想允许重启 app-* 系列服务:

deploy ALL=(root) NOPASSWD: /bin/systemctl restart app-*.service

注意 * 在 sudoers 里是 glob,能匹配 app-frontend.service 但也能匹配
app-evil.service —— 评估清楚再用。

验证 + 测试

写完保存。visudo 在退出时做语法检查;有错会让你重新编辑,不会
落盘错配置。

# 用 deploy 身份测试
sudo -u deploy -i
sudo -l   # 列出该用户被允许的命令
sudo systemctl restart app.service   # 应当不要密码就成功
sudo systemctl restart sshd.service  # 应当拒绝

常见反模式(千万别)

# 错: 把整个 root 让出去
deploy ALL=(ALL) NOPASSWD: ALL

# 错: 用 sudo 跑 shell
deploy ALL=(root) NOPASSWD: /bin/bash
# 完全等价于 NOPASSWD: ALL

# 错: 允许跑文本编辑器
deploy ALL=(root) NOPASSWD: /usr/bin/vim
# 在 vim 里 :!bash 就提权了

# 错: 用相对路径
deploy ALL=(root) NOPASSWD: systemctl restart app.service
# 攻击者改 PATH 就能换 systemctl 为他自己的脚本

sudoedit(即 sudo -e)是安全的编辑器封装,它把文件 copy 到临时位置
让用户编辑,结束后再 mv 回去。要让用户编辑 /etc/foo.conf

deploy ALL=(root) NOPASSWD: sudoedit /etc/foo.conf

调用:sudo -e /etc/foo.conf,用 $EDITOR 打开编辑。

CI / 自动化的特殊建议

CI runner 上的 NOPASSWD 列表是攻击面,越短越好。如果可能:

  1. systemctl --user + lingering,不需要 root
  2. 用 systemd 套接字激活,CI 只 push 文件,service 自动 reload
  3. 把命令写成"无参数的"脚本:CI 只能跑 /usr/local/bin/redeploy-app
    脚本内部硬编码 systemctl,攻击面收敛到一个文件

强制日志

/etc/sudoers.d/00-logging

Defaults    log_input
Defaults    log_output
Defaults    iolog_dir="/var/log/sudo-io/%{user}"
Defaults    !syslog
Defaults    logfile="/var/log/sudo.log"

log_output 会把每次 sudo 会话的输入输出记下来,需要时可以重放:

sudo cat /var/log/sudo.log
sudo sudoreplay -d /var/log/sudo-io deploy/00/00/01

踩过的坑

  • 不在 /etc/sudoers.d/ 而直接改 /etc/sudoers:升级时 dpkg 可能问你
    "保留本地修改 / 用新版",不留神就丢配置。
  • drop-in 文件名 不能.(包括 .bak);sudo 默认忽略带点的。
    我们一律 .conf 后缀也不要,比如 01-deploy
  • NOPASSWD 的命令列表里如果有逗号但漏写空格,会被解析成单个长命令名,
    匹配不上。每个命令前后都加空格保险。
  • 给同一用户配多条规则时,最后一条生效。所以放更宽松的规则在前面、
    更严格的在后面要小心。最佳实践:每个用户一份 drop-in 文件,规则集中。
精确评价 共 0 人评价
可复现性
可复现 · 0 不可复现 · 0
文风
文风流畅 · 0 文风晦涩 · 0
立场
支持 · 0 反对 · 0

登录后即可对本帖作出评价。

评论区 0 条 · 所有人可在此交流

登录后参与评论。

还没有评论,来说两句。