现场是这样的。Ubuntu 20.04 上给运维账号只放行 systemctl restart nginx 和 journalctl,写在 /etc/sudoers.d/ops 里,执行时仍然提示 [sudo] password for ops,别的命令倒是被正确拒绝。
中间走过弯路,把「sudoers.d 里的文件名带点号或波浪号,被 sudo 直接忽略」当成主因,改完现象没变。
真正麻烦的地方在于,几个原因的现象几乎一样。NOPASSWD 标签只对同一条规则里它后面的命令生效,写在了行首以外的位置;同一个用户在后加载的文件里有另一条需要密码的规则,后面的匹配覆盖了前者;用户属于多个组,组的规则先匹配上并且没有 NOPASSWD。
第一件事是用 visudo 校验语法并查看生效顺序
visudo -c && sudo -l -U ops
接着把 NOPASSWD 提到命令列表前统一声明
echo 'ops ALL=(root) NOPASSWD: /bin/systemctl restart nginx, /usr/bin/journalctl' > /etc/sudoers.d/ops
随后确认文件权限和命名符合要求
chmod 440 /etc/sudoers.d/ops && ls -l /etc/sudoers.d/
以目标用户身份实测免密与拒绝两种情况
su - ops -c 'sudo -n systemctl restart nginx'
别只看报错消失,验证要多做一步。sudo -l -U ops 输出里两条命令都带 NOPASSWD,sudo -n 执行不再提示密码,而白名单外的命令仍然报 not allowed。
改 sudoers 一定要走 visudo 或 sudoers.d 并且保留 root 会话,语法错会让所有人包括 root 都进不去 sudo;文件名不要带点。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。