Linux为普通用户设置sudo权限及通过sudo切换到root
Table of Contents
sudo是干嘛用的?
相信稍微了解Linux的童鞋肯定见过sudo
,它一般用于被加在正常命令的前面,这样普通用户也能以root权限执行命令,比如sudo nginx -s reload
。
sudo
最初是superuser do
的缩写,意思就是“用超级用户来做这件事情”,因为sudo命令最初就是被设置来让普通用户执行超级用户的权限的,但是后来增加“以其他用户的权限来执行”这个功能,也就是说,最开始的时候,这个“其它用户”只有root一个,但是后来变成了不只是root,任何一个其他用户都可以(但需要指定),所以sudo
后来被解释成“substitute user do”(代替用户执行,意思是用另一个用户的权限来代替当前用户执行指定的命令)。
设置sudo权限
注意有些最小化安装的Linux(例如Debian)默认是没有sudo命令的,没有就自己安装一下就好:
apt install sudo
为普通用户设置sudo权限,其实就是在/etc/sudoers
配置文件中添加一个配置,平时我们编辑配置文件一般都用vi/vim,但是这个配置文件,我们要使用另一个命令visudo
来编辑,该命令同样是使用vi来编辑,只不过保存的时候会检查你写的语法是否正确,这样有助于查错,其实你用vi/vim来编辑也是可以的,它只不过是一个配置文件罢了。另外,visudo后面不需要跟文件名,直接输入visudo
回车即可自动打开/etc/sudoers
配置文件。
注意: visudo
命令未必会使用vi
来打开/etc/sudoers
文件,而是取决于系统默认编辑器,像我就遇到过最小化安装的Debian默认是用nano
编辑器的,如果要用vi,我们可以修改一下默认编辑器(centos用这个命令没用):
sudo update-alternatives --config editor
打开配置文件后,找到以下配置
## Allow root to run any commands anywhere
root ALL=(ALL) ALL
把该配置复制一行,然后把root改成你要添加sudo权限的用户名,保存退出即可:
## Allow root to run any commands anywhere
root ALL=(ALL) ALL
xiebruce ALL=(ALL) ALL
注意:该配置保存后立即生效,不需要重启什么东西,也不用关掉终端窗口再开。
添加sudo权限后,普通用户在执行的命令前加上sudo,然后会提示输入密码,回车即可以超级用户的权限执行:
sudo yum -y install vim
详解root ALL=(ALL) ALL
这个到底是什么意思?我想很多人都知道按这格式加一个用户则该用户就可以使用sudo了,但却不知道这具体代表什么意思。
我找了一个StackExchange的回答:
Trying to understand the difference between “modernNeo ALL=(ALL:ALL) ALL” and “modernNeo ALL=(ALL) ALL” in the sudoers file
其实root ALL=(ALL) ALL
是简写,root ALL=(ALL:ALL) ALL
才是完整的格式,都写ALL真的很难理解,我写个其他方式,你就懂了:
xiebruce 10.37.129.5,10.37.129.6=(laoli:laoli) /bin/cat
详解:
– xiebruce
是用户名,表示对这个用户进行sudo权限设置。
– 10.37.129.5,10.37.129.6
是ip,表示只允许ip为这两个ip的服务器上的xiebruce用户才能使用。特别注意,这个ip并不是限制客户端ip,而是限制服务器本身,因为为了管理方便,有可能多台服务器的/etc/sudoers
配置文件是同步的,假设有三台机:
A:10.37.129.5
B:10.37.129.6
C:10.37.129.7
这三台机的/etc/sudoers
配置文件都相同,而且三台机都有xiebruce
这个账号,但C机由于特殊原因,不允许xiebruce
具有sudo权限,就可以像我上面用逗号分隔ip,写A、B两个ip即可。
– (laoli:laoli)
这个就是指定xiebruce
具有谁的权限(这里是让xiebruce
用户以sudo运行时,具有用户名为laoli
的权限和组为laoli
的权限),如果写ALL那就是具有所有权限,实际上就是root权限。其实centos系统默认都不写组,即一般会写成(ALL)而不是(ALL:ALL),而经过我测试,不写组,那么组就是该用户本身所在的组,因为我试过用root组去执行,结果反而不行:
- /bin/cat
是指允许执行的命令,如果写成ALL,那就允许执行所有命令(当然它还需要结合前面的权限,虽然后面允许,但不一定有权限执行),如果要允许多个命令,跟ip一样,用逗号隔开就行。
以下为实例:
注意该实例使用的配置文件就是上面举例的配置:
xiebruce 10.37.129.5,10.37.129.6=(laoli:laoli) /bin/cat
实例详解:
由上图可以看到,有两个测试文件,分别为:
-rw------- 1 laoli laoli 89 Jan 17 14:20 file_of_laoli
-rw------- 1 laowang laowang 95 Jan 17 14:10 file_of_laowang
它们的权限,都只有所有人有读写权限,所有组和其他人都没有任何操作权限。
由图可知当前登录用户为xiebruce
,所以直接执行以下命令肯定是没有权限的:
cat file_of_laoli
cat file_of_laowang
但是加了sudo也提示没有权限,这是为什么呢?因为sudo有两个选项,-u
指定以哪个用户的权限进行运行,-g
表示以哪个组的权限运行,如果没有指定-u
和-g
,那么默认相当于指定了-u root -g root
,即默认以root用户和root组为目标用户,这就很清楚了,我sudo配置指定的是xiebruce
具有laoli
的权限,而你现在却以root
权限去运行,肯定是不允许的,正确的做法是sudo -u laoli -g laoli cat file_of_laoli
,其中-g
可以不指定,因为反正-u
已经有权限了(从实例截图中也可以看到,sudo -u laoli cat file_of_laoli是执行成功的)。
sudo cat file_of_laoli
sudo cat file_of_laowang
最后三条命令也都是不成功的,其中第一条是以root用户执行,前面说了,不指定的话其实默认也是以root用户执行的,现在指定了也一样,所以这肯定是无权限的,第二条是用laowang的权限去看,更不可能,因为laowang这个用户本身就没有权限看file_of_laoli这个文件。第三条是用laoli这个用户执行,为什么也不行呢?仔细看,这次执行的命令是vim
,由前面可知,我只设置了允许cat
命令,所以vim命令也是不允许执行的。
sudo -u root cat file_of_laoli
sudo -u laowang cat file_of_laoli
sudo -u laoli vim file_of_laoli
设置无密码使用sudo权限
方法一:NOPASSWD
方式,即在最后一个ALL
前面加个NOPASSWD:
xiebruce ALL=(ALL) NOPASSWD:ALL
多个用户名的设置方式(注意NOPASSWD:
跟命令之间是有一个空格的,否则虽然不报错,但相当于没有设置NOPASSWD
,但(root)
跟NOPASSWD
之间是可以不用空格的):
xiebruce ALL= (root) NOPASSWD: /sbin/mount, (root) NOPASSWD: /bin/umount, (root) NOPASSWD: /mnt/mount, (root) NOPASSWD: /bin/rm, (root) NOPASSWD: /usr/bin/make, (root) NOPASSWD: /bin/ln, (root) NOPASSWD: /bin/sh, (root) NOPASSWD: /bin/mv, (root) NOPASSWD: /bin/chown, (root) NOPASSWD: /bin/chgrp, (root) NOPASSWD: /bin/cp, (root) NOPASSWD: /bin/chmod
方法二:设置密码过期时间方式
设置密码过期时间为-1
即可免密码使用sudo,visudo
→找到Defaults env_reset
,在它后面加上timestamp_timeout=-1
Defaults env_reset,timestamp_timeout=-1
当然,你还可以设置为0
,表示0分钟后要验证,也就是说这样设置会导致每次使用sudo权限都要密码验证:
Defaults env_reset,timestamp_timeout=0
设置10分钟后过期(即你输入过一次sudo密码后,10分钟内用sudo就不需要密码):
Defaults env_reset,timestamp_timeout=10
另外,你也可以设置su
命令不需要密码,当然不建议:
1)切换到root权限;
2)创建group为wheel,命令为groupadd wheel;
3)将用户加入wheel group中,命令为usermod -G wheel joe;
4)修改su的配置文件/etc/pam.d/su,增加下列项:
auth required pam_wheel.so group=wheel
# Uncomment this if you want wheel members to be able to
# su without a password.
auth sufficient pam_wheel.so trust use_uid
至此你可以使用例如如下的命令且不需要输入密码:su joe -c command。
通过sudo切换到超级用户
除了直接在命令前加sudo外,你也可以直接通过sudo切换到超级用户,以下两个命令都可以切换到超级用户:
sudo -i
sudo -s
根据man sudo
-i:就是initial的缩写
The -i (simulate initial login) option runs the shell specified by the password database entry of the target user as a login shell.
翻译:-i(模拟初始登录)选项将目标用户的密码数据库条目指定的shell作为登录shell运行。
什么是“目标用户的密码数据库条目”?
“目标用户”就是“以哪个用户的权限去执行命令”,sudo -u
指定的用户即为目标用户,如果不用-u
指定,默认为root。
密码数据库(password database)其实就是指/etc/passwd
文件,因为linux系统用户的密码都存放在这里,所以把它说成“密码数据库”也是没错的,“条目”是因为/etc/passwd
中的数据都是一个用户一行(即一条数据),所以“目标用户的密码数据库条目”就是指/etc/passwd
文件中你的用户对应的那一条(即那一行),所以对于“目标用户的密码数据库条目指定的shell”,假设我用户是xiebruce,那么我对应的shell就是/bin/bash
(如下图最后一行):
This means that login-specific resource files such as .profile or .login will be read by the shell.
翻译:这意味着“登录特定的”资源文件比如.profile或.login文件(其实就是用户家目录中的.bashrc/.bash_profile/.zshrc等),将会被那个shell读取(那个shell就是上面说的/bin/bash
)。
If a command is specified, it is passed to the shell for execution via the shell’s -c
option.
翻译:如果指定了命令,那么这个命令会通过那个shell的-c
选项被传到那个shell中去执行。(注意-c
选项是shell的选项而不是sudo的选项,比如你的shell是/bin/bash
,那么-c
就是这个bash的选项,你可以man bash
查看到这个选项)。
If no command is specified, an interactive shell is executed. sudo attempts to change to that user’s home directory before running the shell.
翻译:如果没有指定命令,则交互shell将会被执行,并且sudo会在登录到那个用户之前,试图切换到那个用户的家目录。其实这就相当于切换到了root用户,界面看上去也是root,你可以执行whoami
命令,你会发现当前用户已经是root了,但跟su -
切换到root不同的是,你这个root的权限是受限的,具有受什么限制,得看sudo配置,当然绝大部分情况其实就是完全具有root的所有权限,因为大部分人都是直接全部写ALL(参考前面的root ALL=(ALL) ALL
)。
-s:就是shell的缩写
首先看这句:
The -s (shell) option runs the shell specified by the SHELL environment variable if it is set.
解释:-s 选项运行“SHELL环境变量”指定的shell,如果这个shell被设置了的话(当然绝大多数情况下这个$SHELL
都是设置了的)。那么“SHELL环境变量”是什么?其实就是$SHELL
,你直接执行echo $SHELL
即可打印出它的值。
后面接着:or the shell as specified in the password database.
解释:或者password database所指定的shell,“password database”就是密码数据库,前面已经说过了,密码数据库就是/etc/passwd
。
再往下: If a command is specified, it is passed to the shell for execution via the shell’s -c option.
解释:如果指定了命令,则这个命令会通过那个shell的-c
选项传到那个shell中(那个shell就是指前面echo $SHELL
输出的那个shell,如果这个shell不存在就会去/etc/passwd
中找这个用户的shell)。
最后:If no command is specified, an inter‐active shell is executed.
如果没有指定命令则交互shell将会被执行,其实就是登录到sudo的“目标用户”(不明白什么是目标用户的请往前看),一般情况下目标用户就是root,所以假设你直接执行sudo -s
后面不加具体命令的话,则会直接切换为root用户。
总结:
sudo -i
和sudo -s
有什么区别呢?
sudo -i
模拟了登录目标用户的过程,读取了目标用户(-u
指定,不写默认为root)的登录配置文件(如.bashrc),并且登录后会切换到目标用户的家目录中,退出时会清空当前屏幕,回到原来登录前的界面,就好像一切都没发生过,跟你登录另一个远程机操作完,退出回到原来的界面类似。
而sudo -s
是就地切换,不模拟登录,不会切换到目标用户的家目录中,如果目标用户是root
,那么环境变量$PATH
只有/root/bin
及secure_path指定的路径。
sudo -s
后面可以跟shell名称,比如sudo -s zsh
,那就说明你切换后要使用zsh shell(前提是你电脑安装了zsh shell),如果不指定,那就会直接使用当前用户的默认shell(而不会使用root用户的默认shell)。
sudo报找不到命令
需要注意的是,有可能用普通用户能执行的命令,加了sudo会说找不到该命令,而用普通用户虽然找的到该命令但又不够权限,原因是在 /etc/sudoers 这个文件中有一个配置项是 secure_path
, 当使用sudo执行命令的时候 , PATH 变量会被重置为secure_path
的值(为了安全,可以控制不是所有命令都可以让普通用户通过sudo就能执行):
如图所示,secure_path = /sbin:/bin:/usr/sbin:/usr/bin
,而我编译的nginx在/usr/local/nginx/sbin/nginx
,如果在.bashrc
的PATH中添加了nginx的路径,就会导致加sudo无法执行,原因很简单,secure_path里并没有添加nginx环境变量,修改的方法,你可以把nginx软链到/usr/local/bin
:
sudo ln -s /usr/local/openresty/nginx/sbin/nginx /usr/local/bin/nginx
然后在secure_path
里添加/usr/local/bin
的环境变量:
也可以直接往secure_path
里添加nginx
的环境变量:
有可能你买的国外的云服务器是最小安装的,什么都没有,连sudo也没有,你用visudo命令,然报以下错误(看你用的是什么shell)
zsh: command not found: visudo
bash: command not found: visudo
这时你就要自己安装,如下图,使用yum search sudo,找出三个,根据解释,我们要安装的是最后一个『sudo.x86_64』,即安装的时候使用
yum -y install sudo.x86_64
内建命令无法使用sudo问题
内建命令无法直接使用sudo来提升权限,比如sudo cd /etc
不会像你预料的那样会切换到/etc
目录,而是无任何提示,但还是保持在当前目录,相当于你按了一下回车,没有执行任何命令(我的测试是这样,也有其他人测试提报:sudo: cd: command not found错误)。
内建命令有:type
、cd
、alias
、unalias
、.
、echo
、break
等,你没看错,英文句点.
也是一个命令(用type .
来验证),而且是内建命令,判断命令是否为内建命令,用type命令来判断,如:
type cd
如下图,type自己也可以用type命令来判断是否为内建命令,buildin就表示内建命令。
那没有root密码的情况下怎样执行类似cd /etc
这种需要root命令来执行的操作呢?你可以用sudo -i
或sudo -s
来切换到root用户,这样就可以直接用cd /etc
来进入/etc
目录了。
为什么不直接用root而用sudo?
根据前面的内容,相信你已经了解sudo是干嘛用的了,而且像这种设置xiebruce ALL=(ALL) ALL
就是让“xiebruce”用户具有了root用户的权限,你都有root权限了,还要这个普通用户干嘛呢?为什么不直接用root?
-
原因一:Linux上的操作有时候会有危险(比如
rm -rf
之类的命令),如果用普通用户+sudo权限的方式去执行,那么它会提示你输入密码,这样你有一个认真查看命令的机会,也有个反悔的机会,而如果你直接用root,那就直接删掉就删掉了,没机会反悔。 -
原因二:原因一提到的问题,其实如果你用zsh+ohmyzsh的时候,就算你是root执行
rm -rf
也不会不问你而直接删除,而是会提示你真的要删除吗?那既然这样,为什么还要用到sudo呢?为什么不直接用root用户呢?因为假如一个公司,都给大家root用户,第一,如果出现操作事故了无法追踪是谁什么时候登录了服务器,第二,如果有一个员工离职了,那么root密码他肯定还保留有,你要换root密码吗?大家都用着,你突然把root密码换了,这也麻烦,你不换吧,又不安全,毕竟前员工知道你们服务器的root密码,但是如果用普通用户,他离职了你删掉他的用户就好了,不需要导致改root密码。