超级用户授权-sudo
2016年05月13日

概述

授予权限

sudo命令允许系统管理员授予其他用户执行一些程序的权限,正常情况下,非系统管理员用户不具备这些程序的执行权限。与设置程序setuid位域方式不同的是,sudo在谁具有某条命令的执行权限以及何时执行方面可以实现更为严密地控制。
使用sudo可以制作一份清晰的列表来申明哪些用户具有执行哪一个程序的权限。而如果采取设置程序setuid位的方式,则任何用户(或者某一组内任意用户,这依赖于所用的权限位的设置)都可以拥有这一程序的权限。使用sudo,可以在用户运行某一程序时进行口令验证,并且也可以基于用户所在位置(位于本机或通过SSH远程登录的计算机)进行微调。

活动记录

sudo还有一个额外的功能,它可以记录任何使用sudo运行某一程序的尝试(无论是否成功)。这在追踪是谁导致系统致命性错误之时很有帮助,所谓的系统致命行错误是指那种让你耗费10个小时来修正的错误:)

配置Sudo

sudo的配置是由/etc/sudoers文件管理的。该文件无法直接由nano /etc/sudoers或者vim /etc/sudoers或者其他一些你喜欢的编辑器。要想修改这份文件,应当使用visudo。
visudo可以:确保不会有两位系统管理员同时编辑/etc/sudoers文件;维持该文件的操作权限;提供对该文件的语法检查,防止手误而导致致命性错误。

Sudoers语法

基本语法

sudo最难掌握的地方是/etc/sudoers语法,其基本语法如下:

user host = commands

这一语法告诉sudo这样一些信息:用户,以user标识;所登录主机host;commands表示root用户可以执行的任何一组命令列表。基于实例来讲会更清晰一些,譬如使得用户swift可以在本地系统(非SSH远程登录)上执行emerge的语法如下:

swift localhost = /usr/bin/emerge

警示:不要允许用户运行可以提升其操作权限的命令。譬如,若允许用户可以像root用户那样执行emerge,实际上就是授予了该用户完全的系统控制权限,因为他可以利用emerge来修改那些可以限制用户权限的文件系统。所以,如果你对你的sudo用户不是完全的放心,就不要授予他们任何权限。
配置文件中的用户(user)名可以替换为用户组(group)名,这时,应当在组名之前加上%前缀。譬如,要允许wheel组内任一用户可以执行emerge,配置语句应写为:

%wheel localhost = /usr/bin/emerge

在一行配置语句中可以让一个用户拥有多条命令的root执行权限(不必每条命令只对应一个用户或组)。譬如,要允许同一个用户具有emerge、ebuild、emerge-webrsync命令的root执行权限,配置语法为:

swift localhost = /usr/bin/emerge, /usr/bin/ebuild, /usr/sbin/emerge-webrsync

可以更精确的设置命令,而不是仅仅光秃秃的一个命令。这样可以限制某一命令的一些选项的使用。在sudoers文件中,sudo工具容许在路径名或命令行参数中使用shell风格的通配符,但它们并非正则表达式。
现在来测试一下:

sudo emerge -uDN world
We trust you have received the usual lecture from the local System Administrator. It usually boils down to these three things:
1) Respect the privacy of others.
2) Think before you type.
3) With great power comes great responsibility.
Password: (Enter the user password, not root!)

sudo所需要输入执行sudo命令的用户自身的口令,而非root用户口令。这样,即使你偶尔离开,但终端依然不会被居心险恶的人利用。
必须要清楚sudo不会修改$变量:sudo之后尾随的任何命令都是基于当前用户环境运行的。譬如,如果想让普通用户运行/sbin目录下的命令,应当在sudo命令行中给出完整路径:

sudo /usr/sbin/emerge-webrsync

使用别名
在更大一些的环境中,不得不频繁键入各个用户名(主机或命令列表),这可能是令人畏惧的任务。为了简化/etc/sudoers的管理,你可以定义一些别名(alias)。定义别名的语法相当简单:

Host_Alias hostalias = hostname1, hostname2, ...
User_Alias useralias = user1, user2, ...
Cmnd_Alias cmndalias = command1, command2, ...

在任何位置都可以使用的一个通用的别名是ALL(为了区分别名与非别名文本,建议将别名的字母都大写)。顾名思义,ALL别名表示所有可能的设置。
一个有关ALL别名的简单示例是容许所有用户都可以在本机上执行shutdown命令:

ALL localhost = /sbin/shutdown

另一个例子是无论用户swift从哪里登录本机,都允许他可以像root用户那样执行emerge:

swift ALL = /usr/bin/emerge

更有趣的例子是定义一组用户,让他们可以运行一些软件包管理程序(譬如emerge和ebuild);再定义一组系统管理员,让他们可以修改除root用户之外的所有用户的密码。如下:

User_Alias SOFTWAREMAINTAINERS = swift, john, danny
User_Alias PASSWORDMAINTAINERS = swift, sysop
Cmnd_Alias SOFTWARECOMMANDS = /usr/bin/emerge, /usr/bin/ebuild
Cmnd_Alias PASSWORDCOMMANDS = /usr/bin/passwd [a-zA-Z0-9_-]*, !/usr/bin/passwd root
SOFTWAREMAINTAINERS localhost = SOFTWARECOMMANDS
PASSWORDMAINTAINERS localhost = PASSWORDCOMMANDS

非root用户身份切换
让一名用户像其他用户(非root用户)那样地运行程序是可行的。这非常有趣,你可以使用另一个用户(譬如网络服务器apache)的身份来运行程序或执行一些系统管理操作(比如杀死僵死进程)。
在/etc/sudoers文件中,在命令列表之前,可以在( 与 )之间列举需要改变身份的用户。

users hosts = (run-as) commands

譬如要设置允许swift可以像apache或gorg用户那样执行kill命令,语法如下:

Cmnd_Alias KILL = /bin/kill, /usr/bin/pkill
swift ALL = (apache, gorg) KILL

使用这一设置,用户可以运行sudo -u来选择他想担当的角色:

sudo -u apache pkill apache

可以使用Runas_Alias指令为这些要切换身份的用户设置别名,它的用法与前面所讲的别名设置指令的用法相似。
密码与默认设置
默认情况下,sudo要求用户提供自己的系统登录口令来验证其身份。一旦输入了相应口令(密码),sudo会记忆它5分钟,用户要把任务集中在这段时间内来完成,否则就要每5分钟重复输入一次口令。
当然,这种默认行为是可以改变的:可以在/etc/sudoers中设置Defaults:指令来修改一名用户的默认行为。
例如,要将默认的5分钟修改为0分钟(即不记忆所输入口令):

Defaults:swift timestamp_timeout=0

如果将timestamp_timeout设置为-1,sudo会永远记住用户口令,直至系统重新启动。
有一个设置可以在使用sudo时要输入所执行命令的所属用户口令,而不是执行sudo命令的用户口令。这一功能可由runaspw指令进行设置。下面示例演示了runaspw的用法,同时也演示了重复输入口令次数限制的设置方法:

Defaults:john runaspw, passwd_tries=2

还有一个有趣的功能是保持DISPLAY变量不变,这样就可以运行一些X Window工具了:

Defaults:john env_keep=DISPLAY

使用Defaults:指令可以更改许多默认设置,要知详情,可在sudo手册中搜索Defaults。
如果很想允许一名用户使用sudo运行一些程序时无需输入任何口令,应当在命令列表前冠以NOPASSWD:,例如:
swift localhost = NOPASSWD: /usr/bin/emerge

使用sudo

列出权限
运行sudo -l可以查看当前用户的sudo权限:

sudo -l
User swift may run the following commands on this host:
(root) /usr/libexec/xfsm-shutdown-helper
(root) /usr/bin/emerge
(root) /usr/bin/passwd [a-zA-Z0-9_-]*
(root) !/usr/bin/passwd root
(apache) /usr/bin/pkill
(apache) /bin/kill

若在/etc/sudoers中设置了任何命令都不需要输入口令,那么在使用sudo -l时也不需要输入口令。否则,在口令未被sudo记忆时,依然要输入相应口令。
延长口令时限
默认情况下,sudo的验证口令会维持在5分钟内有效。如果用户想延长这一时间,可以运行sudo -v重设时间戳,这样就会又开始一个5分钟口令记忆时间。

sudo -v

相反,若要停掉当前时间戳,可使用sudo -k.

其他

用户名为user1 如果使用组使用%groupname替代
获得权限时候使用root密码,重试次数为2次
该用户获得全部权限
关机不需要密码
重启不需要密码

vim /etc/sudoers
Defaults:user1 runaspw,passwd_tries=2
user1 ALL=(ALL) ALL
user1 ALL=(root)NOPASSWD:/sbin/poweroff
user1 ALL=(root)NOPASSWD:/sbin/reboot