sudoers 文件中任何不正确的语法都会阻止我们访问服务器,并且可能非常危险。
“visudo”将不允许我们以文件中的错误语法退出编辑器。
强烈建议使用“visudo”来编辑 sudoers 文件,而不是使用普通编辑器直接修改原始文件 /etc/sudoers ,因为这样我们将无法进行任何语法检查。
最常用的语法可以概括为
USER_SPACE HOST=RunAs(User) COMMANDS
或者
USER_SPACE HOST=RunAs(User:Group) COMMANDS
如果我们不希望 sudo 在执行分配的任务时提示输入密码,我们也可以使用 NOPASSWD 变量
这里的语法是:
USER_SPACE HOST=RunAs(User) NOPASSWD:COMMANDS
或者
USER_SPACE HOST=RunAs(User:Group) NOPASSWD:COMMANDS
不同字段的含义:
USER_SPACE :这是语法的第一列,可以包含用户名、%group 或者 User_Alias
HOST :这将包含 sudo 将在其上执行分配任务的主机名详细信息
RunAs :此可选子句控制目标用户(和组)sudo 将运行命令的身份。
COMMAND :给出我们希望用户执行的命令列表
sudoers 文件中的别名
sudoers 文件中定义的各种别名,这些是我们在脚本中使用的变量,可以包含适合同一域(用户、主机、命令)的多个条目。
在 sudoers 中的别名如下
User_Alias Host_Alias Cmnd_Alias
User
我们可以使用以下语法为单个用户分配基于 sudo 的权限
user HOST=RunAs COMMAND
例如,我希望允许用户“jack”重新启动crond服务,因此下面是我将使用的语法
jack ALL=(ALL) /usr/bin/systemctl restart crond.service
如果我想让他运行更多命令,那么使用visudo在您的sudoers文件中添加以下内容
jack ALL=(ALL) /usr/bin/systemctl restart crond.service, /usr/bin/systemctl status crond.service
检查确认
[jack@onitroad ~]$sudo systemctl status crond.service [sudo] password for jack: ● crond.service - Command Scheduler Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled) Active: active (running) since Sat 2015-12-30 19:04:36 IST; 4min 18s ago Main PID: 1768 (crond) CGroup: /system.slice/crond.service └─1768 /usr/sbin/crond -n
用户别名 (User_Alias)
如果我们有多个用户列表,我们希望允许使用 sudo 的特定命令列表,那么我们可以使用“User_Alias”,它是 sudoers 文件的内部变量。
语法:
User_Alias ALIAS_NAME = user1, user2, ... ALIAS_NAME HOST = RunAs COMMAND
例如:
我有一个用户“jack”和“bill”,我想允许他们使用systemctl执行crond服务相关的重启和状态命令,然后我的语法如下所示:
(使用 visudo 查看 sudoers 文件)
## User Aliases ## These aren't often necessary, as you can use regular groups ## (ie, from files, LDAP, NIS, etc) in this file - just use %groupname ## rather than USERALIAS # User_Alias ADMINS = jsmith, mikem # The content may look little different based on your distribution, below this you can # create a new line add below content User_Alias CROND_USER = jack, bill
注意:本节下面没有创建新规则的硬性规定,尽管这有助于将每个变量保持在其各自的节下,因此看起来整洁干净,这总是好的
最后,在sudoers文件的末尾添加一个新行
CROND_USER ALL = (ALL) /usr/bin/systemctl restart crond.service, /usr/bin/systemctl status crond.service
正如您所看到的,我创建了一个变量CROND_user,并添加了我希望为其提供公共sudo访问权限的所有用户列表,而不是给出单个用户的名称
%Group
假设我们已经有一个系统组,其中包含我们希望为其允许某些命令或者任务的用户列表,那么我们可以使用以下语法使用 group 参数,而不是使用 User_Alias
%groupname HOST=RunAs COMMAND
例如,我有一个组“mycompany”,其成员是用户“jack”和“bill”,我想再次为他们授予执行重启和检查crond服务状态的权限
使用visudo在sudoers文件/etc/sudoers中添加以下行
%mycompany ALL=(ALL) /usr/bin/systemctl restart crond.service, /usr/bin/systemctl status crond.service
NOPASSWD
默认情况下,sudo 要求用户在运行命令之前对其进行身份验证。
可以通过 NOPASSWD 标签修改此行为
单个用户的语法:
User HOST=RunAs NOPASSWD:COMMAND
单个组的语法:
%group HOST=RunAs NOPASSWD:COMMAND
User_Alias语法
ALIAS_VARIABLE HOST=RunAs NOPASSWD:COMMAND
例如,我有一个用户jack,我想给他重新启动和检查crond服务状态的权限
使用visudo在sudoers文件的行末添加以下内容
jack ALL=(ALL) NOPASSWD:/usr/bin/systemctl restart crond.service, /usr/bin/systemctl status crond.service
假设我有一组命令,其中我想让jack只运行一些无密码命令,而对于某些命令,我想使用密码提示,那么在这种情况下,我们将使用下面的规则
jack ALL=(ALL) NOPASSWD:/usr/bin/systemctl restart crond.service, PASSWD:/usr/bin/systemctl status crond.service
所以这里“jack”将被允许在没有密码的情况下重新启动crond服务,但在检查crond服务的状态时会提示他输入密码
HOST
我是在我的机器上运行时,为什么我们需要“HOST”?
没错,如果是单台服务器,确实没必要,但是如果你有一个包含 1000 台服务器的大型网络,其中每组服务器都有自己的角色,例如有些可以是 DNS 服务器,有些可以是 apache 服务器,我们必须分配 sudo 角色根据各自的用户。
现在,我们不希望作为域管理员的用户“jack”对域服务器具有 sudo 访问权限,也可以对其他服务器进行 sudo 访问?
因此,我将使用sudo中的“Host”部分,并确保允许用户jack作为root用户运行所有需要的命令,但只能在“Domain Server”上运行
语法:
User HOST=RunAs COMMAND
例如,如果我的域服务器主机名是“onitroad”,那么我的sudoers有类似这样的:
jack onitroad=(ALL) <List of commands>
那么,使用此用户“jack”可以在“onitroad”上运行所有允许的命令,但不能在其他服务器上运行
例如,我希望“jack”允许重新启动crond服务,但仅限于onitroad服务器
jack onitroad=(ALL) /usr/bin/systemctl restart crond.service
如果我允许他在所有主机上重新启动此服务器,那么这将变成:
jack ALL=(ALL) /usr/bin/systemctl restart crond.service
Host_Alias
如果我们想允许用户在多个主机上使用 sudo 权限执行某些任务,那么我们可以使用 Host_Alias 变量,它是一个基于 sudoers 的内部变量。
语法:
Host_Alias MAILSERVERS = smtp, smtp2, ...
使用visudo查看sudoers文件中的以下部分,并添加一行新行,为您的需求创建一个新变量
例如,我希望“jack”在dnsserver和dhcpserver上运行一些命令
## Host Aliases ## Groups of machines. You may prefer to use hostnames (perhaps using ## wildcards for entire domains) or IP addresses instead. # Host_Alias FILESERVERS = fs1, fs2 # Host_Alias MAILSERVERS = smtp, smtp2 Host_Alias jack_SERVER = dnsserver, dhcpserver jack Host_Alias=(ALL) /usr/bin/systemctl restart crond.service
这里,dnsserver和dhcpserver是我的服务器的主机名,您可以根据设置将其替换为主机名
RunAs(User:Group)
- Runas_Spec 确定可以运行命令的用户和/或者组。
- 完全指定的 Runas_Spec 由两个 Runas_Lists(如上定义)组成,由冒号 (‘:’) 分隔并括在一组括号中。
- 第一个 Runas_List 指示可以通过 sudo 的 -u 选项运行命令的用户。
- 第二个定义了可以通过 sudo 的 -g 选项指定的组列表。
- 如果指定了两个 Runas_Lists,则可以使用在其各自的 Runas_Lists 中列出的用户和组的任意组合运行该命令。
- 如果只指定了第一个,则可以以列表中的任何用户身份运行该命令,但不能指定 -g 选项。
- 如果第一个 Runas_List 为空但指定了第二个,则该命令可以作为调用用户运行,并将组设置为 Runas_List 中列出的任何一个。
- 如果两个 Runas_Lists 都为空,则该命令只能作为调用用户运行。
通过这个参数,我们告诉 sudo 接受“-u”和“-g”选项,其中“-u”将作为各自的用户运行命令/脚本,而“-g”将作为各自的组执行相同的操作。
仅使用“用户”部分时的语法:
USER_SPACE HOST = RunAs(User) COMMAND
仅使用“组”部分时的语法:
USER_SPACE HOST = RunAs(:Group) COMMAND
如果同时使用“用户”和“组”部分,则使用以下语法:
USER_SPACE HOST = RunAs(User:Group) COMMAND
让我们看一看一些例子
“jack”用户有一个测试脚本
[root@golinuxhub ~]# ls -l /tmp/jack_script.sh -rwxr-xr--. 1 jack jack 47 Dec 30 17:14 /tmp/jack_script.sh
如我们所见,此脚本的用户和组均为“jack:jack”,并且都具有此脚本的可执行权限
如果我以用户“jack”身份运行这个脚本
[jack@golinuxhub ~]$/tmp/jack_script.sh Hello This is jack's fIle
可以正确执行的。
让我们尝试以其他用户比如“bill”的身份运行它
[bill@golinuxhub ~]$/tmp/jack_script.sh -bash: /tmp/jack_script.sh: Permission denied
权限被拒绝。
现在 bill 尝试使用 sudo 访问运行脚本,看行不行:
[bill@golinuxhub ~]$sudo /tmp/jack_script.sh [sudo] password for bill: bill is not in the sudoers file. This incident will be reported.
还是不行。
让我们使用 visudo 在 sudoers 文件中给 bill 添加 “sudo” 权限来执行 jack 的脚本
bill onitroad=(jack) /tmp/jack_script.sh
现在,我们授予 RunAs “jack”的权限,这意味着如果用户“bill”以“jack”身份运行脚本,那么他将被允许运行脚本。
让我们试一下:
[bill@onitroad ~]$sudo /tmp/jack_script.sh [sudo] password for bill: Sorry, user bill is not allowed to execute '/tmp/jack_script.sh' as root on onitroad.lab.
由于bill试图以root用户身份运行jack的脚本(如果没有指定-u,则sudo作为root用户),因此权限被拒绝,让我们使用“-u jack”重试
[bill@onitroad ~]$sudo -u jack /tmp/jack_script.sh [sudo] password for bill: Hello This is jack's file
这一次,成功了。
与此类似,我们也可以授予 RunAs “Group”级别的权限
例如,如果我在sudoers文件中给出以下参数
bill onitroad=(jack:jack) /tmp/jack_script.sh
我为User:jack和Group:jack提供了访问权限,
他可以作为用户和组运行脚本
[bill@onitroad ~]$sudo -g jack /tmp/jack_script.sh Hello This is jack's file [bill@onitroad ~]$sudo -u jack -g jack /tmp/jack_script.sh Hello This is jack's fIle
COMMANDS
在 sudoers 语法的最后一列,是允许用户/组使用的命令列表。
语法:
USER_SPACE HOST=RunAs COMMANDS
例如,允许“jack”重新启动crond服务
jack ALL=(ALL) /usr/bin/systemctl restart crond.service
您可以给出多个命令,这些命令之间用逗号“,”分隔,后跟空格。
Cmnd_Alias
如果我们有一组要为其提供访问权限的命令,那么将它们添加到单个变量中是有意义的,例如:Cmn_Alias,它是一个内部 sudoers 拥有的变量。
语法:
Cmnd_Alias VARIABLE_NAME = /path/to/command1, /path/to/command2, /path/to/command3, ...
请在sudoers文件中查找下面的部分,并使用visudo在sudoers文件中添加一个新行,为您的需求创建一个新变量
例如,我希望“jack”使用变量 CROND_SERVICE 运行一些命令集
## Command Aliases ## These are groups of related commands... Cmnd_Alias CROND_SERVICE = /usr/bin/systemctl restart crond.service, /usr/bin/systemctl status crond.service
jack ALL = (ALL) CROND_SERVICE
如果要禁用命令集的密码提示,请使用下面的行
jack ALL = (ALL) NO_PASSWD:CROND_SERVICE