细粒度命令执行控制Cmnd_Alias /etc/sudoers

/etc/sudoers 里的 Cmnd_Aliassudo 权限控制中一个非常实用、易被忽略的特性。它可以让我们把多个命令归类成一个命令组别名,然后在用户授权时引用,从而让配置更加清晰和可维护。


一、Cmnd_Alias 的作用

2sudoers 文件中四种“别名类型”之一:

别名类型 作用说明
User_Alias 用户或用户组别名
Runas_Alias 以哪个用户/组身份执行命令
Host_Alias 主机或主机组别名
Cmnd_Alias 命令别名,将多个命令定义为一个逻辑组

举例来说:
你希望开发人员可以执行某些系统管理命令(如重启 Nginx、查看日志等),但不能直接执行 shutdownuseradd 等危险操作。
你可以用 Cmnd_Alias 把安全命令集中起来:

1
Cmnd_Alias WEB_CMDS = /bin/systemctl restart nginx, /bin/systemctl status nginx, /usr/bin/tail /var/log/nginx/access.log

二、Cmnd_Alias 的定义语法

基本格式如下:

1
Cmnd_Alias NAME = command1, command2, command3

规则:

  • NAME 必须是大写字母、数字、下划线组成(习惯上全大写)
  • 多个命令之间用逗号分隔
  • 命令必须写绝对路径sudo 不使用 PATH 查找)

示例:

1
2
Cmnd_Alias ADMIN_CMDS = /usr/bin/systemctl restart httpd, /usr/bin/systemctl start httpd, /usr/bin/systemctl stop httpd
Cmnd_Alias LOG_CMDS = /usr/bin/tail /var/log/messages, /usr/bin/less /var/log/secure

三、结合用户授权使用

定义好命令组别名后,在用户权限配置中直接引用即可:

1
2
%devops ALL=(ALL) NOPASSWD: WEB_CMDS
alice ALL=(ALL) NOPASSWD: LOG_CMDS

含义:

  • %devops 组中的所有用户可以在任何主机上以任何身份执行 WEB_CMDS 定义的命令。
  • 用户 alice 可以执行 LOG_CMDS 中的命令,无需输入密码。

四、多层组合用法

1
2
3
4
5
6
User_Alias   WEBADMINS = tom, jerry
Runas_Alias OP = root
Host_Alias WEBSERVERS = web01, web02, web03
Cmnd_Alias WEB_CMDS = /bin/systemctl restart nginx, /bin/systemctl status nginx

WEBADMINS WEBSERVERS = (OP) NOPASSWD: WEB_CMDS

意思是:

用户 tom、jerry 可以在 web01~03 上以 root 身份执行 Nginx 的重启与状态查看命令,不需要密码。


五、验证配置是否正确

修改完 /etc/sudoers不要直接保存退出,一定要用安全编辑方式:

1
visudo

它会:

  • 自动语法检查
  • 防止多个用户同时修改
  • 保存错误配置会被拒绝写入

测试:

1
sudo -l

可以看到当前用户允许执行的命令和命令别名解析结果。


六、实践技巧

  1. 建议按功能分类命令别名

    1
    2
    Cmnd_Alias NETWORK_CMDS = /sbin/ifconfig, /sbin/ip
    Cmnd_Alias SYSTEM_CMDS = /usr/bin/systemctl *, /usr/bin/journalctl
  2. 支持通配符(谨慎使用)

    1
    Cmnd_Alias SCRIPT_CMDS = /usr/local/bin/deploy_*
  3. 可组合多个别名

    1
    Cmnd_Alias ALL_SAFE_CMDS = NETWORK_CMDS, SYSTEM_CMDS, SCRIPT_CMDS
  4. 拒绝特定命令

    1
    bob ALL = ALL, !/bin/su, !/bin/bash

七、完整示例

1
2
3
4
5
6
7
8
# 定义别名
User_Alias DEVOPS = flame, spark
Runas_Alias ROOT = root
Host_Alias ALLHOSTS = ALL
Cmnd_Alias SAFE_WEB = /usr/bin/systemctl restart nginx, /usr/bin/systemctl status nginx, /usr/bin/tail /var/log/nginx/*

# 授权
DEVOPS ALLHOSTS = (ROOT) NOPASSWD: SAFE_WEB