温馨提示:
本文所述内容具有依赖性,可能因软硬条件不同而与预期有所差异,故请以实际为准,仅供参考。
不考虑企业运维中权限管控十分严格的情况,个人运维基本上都是一个密码,在此背景下,现在的云主机或者系统一般在新建时都要求不能使用默认的 root
账户,而是新建一个普通用户,造成在运行 sudo
命令时再输一遍密码才能继续,这显然是十分浪费时间的。
解决办法
如果想立即解决输密码问题,参照下列命令直接新增文件即可,可以不用继续看后面的原理分析:
# vim /etc/sudoers.d/sudoers
sudoers ALL=(ALL:ALL) NOPASSWD:ALL
# chmod 440 /etc/sudoers.d/sudoers
其中,命令中的 sudoers
是登录系统时的账户。
原理分析
Linux 是多用户多任务的操作系统, 共享该系统的用户往往不只一个。出于安全性考虑, 有必要通过 useradd
创建一些非 root 用户, 只让它们拥有不完全的权限,如有必要,再来提升权限执行。
sudo
就是来解决这个需求的:这些非 root 用户不需要知道 root 的密码,就可以提权到 root,执行一些 root 才能执行的命令。
执行 sudo -u <用户名> <命令>
, 将允许当前用户,提权到<用户名>的身份,再执行后面的<命令>, 即使<命令>原本需要 root 权限。
提权到<用户名>身份时,是以<用户名>的身份来执行命令的,因此创建的文件默认属于<用户名>用户。
因此,当 userB 执行如下命令时:
sudo -u userA touch /tmp/belong-to-who.tmp
创建的 /tmp/belong-to-who.tmp 文件属于用户 userA。
如果不带 -u, 则默认使用 root 用户,而大多数时候 sudo 都是要提权到 root 的,所以 -u <用户名>可以省略为:
sudo <命令>
需要注意的是: 执行 sudo 时输入的密码是当前用户的密码, 并非<用户名>的密码。
sudo -u <用户名>
和su - <用户名>
相比:前者需要输入当前用户的密码,提权到<用户名>身份执行命令后> 返回当前用户,后者则是输入目标用户的密码,切换到目标用户。
赋予用户 sudo 操作的权限
关于Linux 用户和用户组管理的知识点不是本篇文章要讨论的, 如对 useradd、 usermod、 passwd、 groupadd 等指令生疏,可移步链接 ,那里有详细的讲解。
通过 useradd 添加的用户,并不具备 sudo 权限。在 ubuntu/centos 等系统下,需要将用户加入 admin 组或者 wheel 组或者 sudo 组。
以 root 用户身份执行如下命令,将用户加入 wheel/admin/sudo 组:
usermod -a -G wheel <用户名>
如果提示 wheel 组不存在, 则还需要先创建该组:
groupadd wheel
用公式讲解 /etc/sudoers 的内容
sudo 的权限控制可以在 /etc/sudoers
文件中查看到。
如果想要控制某个用户(或某个组用户)只能执行 root 权限中的一部分命令,或者允许某些用户使用 sudo 时不需要输入密码,就需要对该文件有所了解。
一般来说,通过 cat /etc/sudoers
指令来查看该文件,会看到如下几行代码:
root ALL=(ALL:ALL) ALL
%wheel ALL=(ALL) ALL
%sudo ALL=(ALL:ALL) ALL
对 /etc/sudoers
文件进行编辑的代码公式可以概括为:
授权用户/组 主机=[(切换到哪些用户或组)] [是否需要输入密码验证] 命令1,命令2,...
凡是 [ ]
中的内容都能省略,命令和命令之间用 ,
号分隔;
为了方便说明,将公式的各个部分称呼为字段 1 - 字段 5:
授权用户/组 主机 =[(切换到哪些用户或组)] [是否需要输入密码验证] 命令1,命令2,...
字段 1 字段 2 = [(字段 3)] [字段 4] 字段 5
字段 3、字段 4,是可以省略的,在上面的默认例子中:
“字段 1” 不以
%
号开头的表示 “将要授权的用户”,比如例子中的root
;以%
号开头的表示“将要授权的组”, 比如例子中的%wheel
组和%sudo
组。
“字段 2” 表示允许登录的主机,ALL表示所有,如果该字段不为ALL,表示授权用户只能在某些机器上登录本服务器来执行
sudo
命令,比如:jack mycomputer=/usr/sbin/reboot,/usr/sbin/shutdown
表示:普通用户 jack 在主机(或主机组) mycomputer上,可以通过 sudo 执行 reboot 和 shutdown 两个命令。"字段 3"和"字段 4"省略。
“字段 3” 如果省略,相当于
(root:root)
,表示可以通过sudo
提权到root
;如果为(ALL)
或者(ALL:ALL)
,表示能够提权到(任意用户:任意用户组)
。
请注意,“字段 3”如果没省略,必须使用( )
双括号包含起来,这样才能区分是省略了 “字段 3” 还是省略了 “字段 4”。
“字段 4” 的可能取值是
NOPASSWD:
。请注意NOPASSWD
后面带有冒号:
,表示执行sudo
时可以不需要输入密码。比如:lucy ALL=(ALL) NOPASSWD: /bin/useradd
表示:普通用户
lucy
可以在任何主机上通过sudo
执行/bin/useradd
命令,并且不需要输入密码;又比如:
peter ALL=(ALL) NOPASSWD: ALL
表示:普通用户
peter
可以在任何主机上,通过sudo
执行任何命令,并且不需要输入密码。
“字段 5” 是使用逗号分开一系列命令,这些命令就是授权给用户的操作,
ALL
表示允许所有操作。
你可能已经注意到了,命令都是使用绝对路径,这是为了避免目录下有同名命令被执行,从而造成安全隐患。
如果你将授权写成如下安全性欠妥的格式:lucy ALL=(ALL) chown,chmod,useradd
那么用户就有可能创建一个他自己的程序,也命名为
userad
, 然后放在它的本地路径中,如此一来他就能够使用root
来执行这个名为useradd
的程序,这是相当危险的!
命令的绝对路径可通过 which
指令查看到,比如 which useradd
可以查看到命令 useradd
的绝对路径:/usr/sbin/useradd
。
公式还要扩充
例子 1:
papi ALL=(root) NOPASSWD: /bin/chown,/usr/sbin/useradd
表示:用户 papi
能在所有可能出现的主机上,提权到 root
下执行 /bin/chown
,不必输入密码,但运行 /usr/sbin/useradd
命令时需要密码,这是因为 NOPASSWD:
只影响了其后的第一个命令:命令 1。
所以上面给出的公式只是简化版,完整的公式如下:
授权用户/组 主机 = [(切换到哪些用户或组)] [是否需要输入密码验证] 命令 1, [(字段 3)] [字段 4] 命令 2, ...
在具有 sudo
操作的用户下, 执行 sudo -l
可以查看到该用户被允许和被禁止运行的命令.
通配符和取消命令
例子 2:
papi ALL=/usr/sbin/*,/sbin/*,!/usr/sbin/fdisk
表示:用户 papi
在所有可能出现的主机上,能够运行目录 /usr/sbin
和 /sbin
下所有的程序,但 fdisk
除外。
开始编辑
“你讲了这么多,但是在实践中,我去编辑 /etc/sudoers
文件,系统提示我没权限啊,怎么办?”
这是因为 /etc/sudoers
的内容如此敏感,以至于该文件是只读的。所以,编辑该文件前,请确认清楚你知道自己正在做什么。
强烈建议通过 visudo
命令来修改该文件,通过 visudo
修改,如果配置出错,会有提示。
不过,系统文档推荐的做法,不是直接修改 /etc/sudoers
文件,而是将修改写在 /etc/sudoers.d/
目录下的文件中。
如果使用这种方式修改 sudoers
,需要在 /etc/sudoers
文件的最后行,加上 #includedir /etc/sudoers.d
一行(默认已有):
#includedir /etc/sudoers.d
注意了,这里的指令 #includedir
是一个整体,前面的 #
号不能丢,并非注释,也不能在 #
号后有空格。
任何在 /etc/sudoers.d/
目录下,不以 ~
号结尾的文件和不包含 .
号的文件,都会被解析成 /etc/sudoers
的内容。
文档中是这么说的:
# This will cause sudo to read and parse any files in the /etc/sudoers.d
# directory that do not end in '~' or contain a '.' character.
# Note that there must be at least one file in the sudoers.d directory (this
# one will do), and all files in this directory should be mode 0440.
# Note also, that because sudoers contents can vary widely, no attempt is
# made to add this directive to existing sudoers files on upgrade.
# Finally, please note that using the visudo command is the recommended way
# to update sudoers content, since it protects against many failure modes.
其他知识
输入密码时有反馈
当使用 sudo
后输入密码,并不会显示任何东西 —— 甚至连常规的星号都没有。有个办法可以解决该问题。
打开 /etc/sudoers
文件找到下述一行:
Defaults env_reset
修改成:
Defaults env_reset,pwfeedback
修改 sudo 会话时间
如果你经常使用 sudo
命令,你肯定注意到过当你成功输入一次密码后,可以不用再输入密码就可以运行几次 sudo
命令,但是一段时间后,sudo
命令会再次要求你输入密码。
默认是 15
分钟,该时间可以调整。添加 timestamp_timeout=分钟数
即可(时间以分钟为单位,-1
表示永不过期,但强烈不推荐)。
比如我希望将时间延长到 1小时,还是打开 /etc/sudoers
文件找到下述一行:
Defaults env_reset
修改成:
Defaults env_reset,pwfeedback,timestamp_timeout=60
参考文章:
1、《sudoers的深入剖析与用户权限控制》
2、《How to Run ‘sudo’ Command Without Entering a Password in Linux》