sudo
以其他身份来执行命令
补充说明
sudo
命令用来以其他身份来执行命令,预设的身份为 root。在 /etc/sudoers
中设置了可执行 sudo
指令的用户。若其未经授权的用户企图使用 sudo
,则会发出警告的邮件给管理员。用户使用 sudo
时,必须先输入密码,之后有 5 分钟的有效期限,超过期限则必须重新输入密码。
语法
sudo [options] [command]
选项
-b
:在后台执行指令;-E
:继承当前环境变量;-h
:显示帮助;-H
:将 HOME 环境变量设为新身份的 HOME 环境变量;-k
:结束密码的有效期限,也就是下次再执行sudo
时便需要输入密码;-l
:列出目前用户可执行与无法执行的指令;-p
:改变询问密码的提示符号;-s<shell>
:执行指定的 shell;-u<user>
:以指定的用户作为新的身份。若不加上此参数,则预设以 root 作为新的身份;-v
:延长密码有效期限 5 分钟;-V
:显示版本信息。
参数
command
:需要运行的指令和对应的参数。
实例
$ sudo su -
# env | grep -E '(HOME|SHELL|USER|LOGNAME|^PATH|PWD|TEST_ETC|TEST_ZSH|TEST_PRO|TEST_BASH|TEST_HOME|SUDO)'
这个命令相当于使用 root 超级用户重新登录一次 shell,只不过密码是使用的当前用户的密码。而且重要是,该命令会重新加载 /etc/profile
文件以及 /etc/bashrc
文件等系统配置文件,并且还会重新加载 root 用户的 $SHELL
环境变量所对应的配置文件 ,比如:root 超级用户的 $SHELL
是 /bin/bash
,则会加载 /root/.bashrc
等配置。如果是 /bin/zsh
,则会加载 /root/.zshrc
等配置,执行后是完全的 root 环境。
$ sudo -i
# env | grep -E '(HOME|SHELL|USER|LOGNAME|^PATH|PWD|TEST_ETC|TEST_ZSH|TEST_PRO|TEST_BASH|TEST_HOME|SUDO)'
这个命令基本与 sudo su -
相同,执行后也是 root 超级用户的环境,只不过是多了一些当前用户的信息。
$ sudo -s
# env | grep -E '(HOME|SHELL|USER|LOGNAME|^PATH|PWD|TEST_ETC|TEST_ZSH|TEST_PRO|TEST_BASH|TEST_HOME|SUDO)' --color
这个命令相当于以当前用户的 $SHELL
开启了一个 root 超级用户的 no-login 的 shell,不会加载 /etc/profile
等系统配置。所以 /etc/profile
文件中定义的 TEST_ETC
环境变量就看不到了,但是会加载 root 用户对应的配置文件,比如 root 用户的 $SHELL
是 /bin/zsh
,那么会加载 /root/.zshrc
配置文件,执行完后,不会切换当前用户的目录。
配置
sudo
必须通过编辑 /etc/sudoers
文件进行配置,而且只有超级用户才可以修改它,还必须使用 visudo
编辑。之所以使用 visudo
有两个原因,一是它能够防止两个用户同时修改它;二是它也能进行有限的语法检查。所以,即使只有你一个超级用户,你也最好用 visudo
来检查一下语法。
visudo
默认的是在 vi 里打开配置文件,用 vi 来修改文件。我们可以在编译时修改这个默认项。visudo
不会擅自保存带有语法错误的配置文件,它会提示你出现的问题,并询问该如何处理,就像:
>>> sudoers file: syntax error, line 22 <<
此时我们有三种选择:键入 “e” 是重新编辑,键入 “x” 是不保存退出,键入 “Q” 是退出并保存。如果真选择 “Q”,那么 sudo
将不会再运行,直到错误被纠正。
现在,我们一起来看一下神秘的配置文件,学一下如何编写它。让我们从一个简单的例子开始:让用户 Foobar 可以通过 sudo
执行所有 root 可执行的命令。以 root 身份用 visudo
打开配置文件,可以看到类似下面几行:
# Runas alias specification
# User privilege specification
root ALL=(ALL) ALL
我们一看就明白个差不多了,root 有所有权限,只要仿照现有 root 的例子就行,我们在下面加一行(最好用 tab 作为空白):
foobar ALL=(ALL) ALL
保存退出后,切换到 foobar 用户,我们用它的身份执行命令:
[foobar@localhost ~]$ ls /root
ls: /root: 权限不够
[foobar@localhost ~]$ sudo ls /root
PassWord:
anaconda-ks.cfg Desktop install.log install.log.syslog
好了,我们限制一下 foobar 的权利,不让他为所欲为。比如我们只想让他像 root 那样使用 ls
和 ifconfig
,把那一行改为:
foobar localhost= /sbin/ifconfig, /bin/ls
再来执行命令:
[foobar@localhost ~]$ sudo head -5 /etc/shadow
Password:
Sorry, user foobar is not allowed to execute '/usr/bin/head -5 /etc/shadow' as root on localhost.localdomain.
[foobar@localhost ~]$ sudo /sbin/ifconfig eth0 Linkencap:Ethernet HWaddr 00:14:85:EC:E9:9B...
现在让我们来看一下那三个 ALL 到底是什么意思。第一个 ALL 是指网络中的主机,我们后面把它改成了主机名,它指明 foobar 可以在此主机上执行后面的命令。第二个括号里的 ALL 是指目标用户,也就是以谁的身份去执行命令。最后一个 ALL 当然就是指命令名了。例如,我们想让 foobar 用户在 linux 主机上以 jimmy 或 rene 的身份执行 kill
命令,这样编写配置文件:
foobar linux=(jimmy, rene) /bin/kill
但这还有个问题,foobar 到底以 jimmy 还是 rene 的身份执行?这时我们应该想到了 sudo -u
了,它正是用在这种时候。 foobar 可以使用 sudo -u jimmy kill PID
或者 sudo -u rene kill PID
,但这样挺麻烦,其实我们可以不必每次加 -u
,把 rene 或 jimmy 设为默认的目标用户即可。再在上面加一行:
Defaults:foobar runas_default=rene
Defaults
后面如果有冒号,是对后面用户的默认,如果没有,则是对所有用户的默认。就像配置文件中自带的一行:
Defaults env_reset
另一个问题是,很多时候,我们本来就登录了,每次使用 sudo
还要输入密码就显得烦琐了。我们可不可以不再输入密码呢?当然可以,我们这样修改配置文件:
foobar localhost=NOPASSWD: /bin/cat, /bin/ls
再来 sudo
一下:
[foobar@localhost ~]$ sudo ls /root
anaconda-ks.cfg Desktop install.log install.log.syslog
当然,你也可以说“某些命令用户 foobar 不可以运行”,通过使用 !
操作符,但这不是一个好主意。因为,用 !
操作符来从 ALL 中 “剔出” 一些命令一般是没什么效果的,一个用户完全可以把那个命令拷贝到别的地方,换一个名字后再来运行。
日志与安全
sudo
为安全考虑得很周到,不仅可以记录日志,还能在有必要时向系统管理员报告。但是,sudo
的日志功能不是自动的,必须由管理员开启。这样来做:
touch /var/log/sudo
vi /etc/syslog.conf
在 syslog.conf
最后面加一行(必须用 tab 分割开)并保存:
local2.debug /var/log/sudo
重启日志守候进程:
ps aux | grep syslogd
把得到的 syslogd
进程的 PID(输出的第二列是 PID)填入下面:
kill -HUP PID
这样,sudo
就可以写日志了:
[foobar@localhost ~]$ sudo ls /root
anaconda-ks.cfg Desktop install.log install.log.syslog
$cat /var/log/sudo
Jul 28 22:52:54 localhost sudo: foobar : TTY=pts/1 ; pwd=/home/foobar ; USER=root ; command=/bin/ls /root
不过,有一个小小的 “缺陷”,sudo
记录日志并不是很忠实:
[foobar@localhost ~]$ sudo cat /etc/shadow > /dev/null
cat /var/log/sudo...Jul 28 23:10:24 localhost sudo: foobar : TTY=pts/1 ;
PWD=/home/foobar ; USER=root ; COMMAND=/bin/cat /etc/shadow
重定向没有被记录在案!为什么?因为在命令运行之前,shell 把重定向的工作做完了,sudo
根本就没看到重定向。这也有个好处,下面的手段不会得逞:
[foobar@localhost ~]$ sudo ls /root > /etc/shadow
bash: /etc/shadow: 权限不够
sudo
有自己的方式来保护安全。以 root 的身份执行 sudo -V
,查看一下 sudo
的设置。因为考虑到安全问题,一部分环境变量并没有传递给 sudo
后面的命令,或者被检查后再传递的,比如:PATH
、HOME
、SHELL
等。当然,你也可以通过 sudoers
来配置这些环境变量。
从零学 python
【从零学习python 】92.使用Python的requests库发送HTTP请求和处理响应
【从零学习python 】91. 使用装饰器和字典管理请求路径的简洁Web应用
【从零学习python 】93.使用字典管理请求路径
【从零学习python 】89. 使用WSGI搭建简单高效的Web服务器
【从零学习python 】88. WSGI接口详解:实现简单高效的Web开发
【从零学习python 】87. 手动搭建HTTP服务器的Python实现及多线程并发处理
【从零学习python 】86. 深入了解HTTP协议及其在浏览器和服务器通信中的作用
【从零学习python 】85.Python进程池的并行计算技术应用
【从零学习python 】84.深入理解线程和进程
【从零学习python 】83. Python多进程编程与进程池的使用
【从零学习python 】82. 基于多线程的聊天程序实现
【从零学习python 】81.Python多线程通信与队列的应用
【从零学习python 】80.线程访问全局变量与线程安全问题
【从零学习python 】79. 线程访问全局变量与线程安全问题
【从零学习python 】78. 文件下载案例
【从零学习python 】77. TCP服务端编程及注意事项
【从零学习python 】76.服务器与客户端:网络通信的关键组成部分
【从零学习python 】75. TCP协议:可靠的面向连接的传输层通信协议
【从零学习python 】74. UDP网络程序:端口问题与绑定信息详解
【从零学习python 】73. UDP网络程序-发送数据
【从零学习python 】72. 深入理解Socket通信及创建套接字的方法
【从零学习python 】71. 网络端口及其作用
【从零学习python 】70.网络通信方式及其应用:从直接通信到路由器连接多个网络
【从零学习python 】69. 网络通信及IP地址分类解析
【从零学习python 】68. Python正则表达式中的贪婪和非贪婪模式
【从零学习python 】67.Python中的re模块:正则替换与高级匹配技术
【从零学习python 】66.深入了解正则表达式:模式匹配与文本处理的利器
【从零学习python 】65. Python正则表达式修饰符及其应用详解
【从零学习python 】64. Python正则表达式中re.compile方法的使用详解
【从零学习python 】63.正则表达式中的re.Match类及其属性和方法介绍
【从零学习python 】62. Python正则表达式:强大的字符串匹配工具
【从零学习python 】61.Python中的property属性详解和应用示例
【从零学习python 】60.探索生成器:迭代的灵活利器
【从零学习python 】59.迭代器:优化数据遍历的高效工具
【从零学习python 】58.Python中的自定义异常及引发异常的方法
【从零学习python 】57.Python中使用with关键字正确关闭资源
【从零学习python 】56. 异常处理在程序设计中的重要性与应用
【从零学习python 】55.Python中的序列化和反序列化,JSON与pickle模块的应用
【从零学习python 】54. 内存中写入数据
【从零学习python 】53. CSV文件和Python的CSV模块
【从零学习python 】52.文件的读写 - Python文件操作指南
【从零学习python 】51.文件的打开与关闭及其在Python中的应用
【从零学习python 】49. Python中对象相关的内置函数及其用法
【从零学习python 】48.Python中的继承与多继承详解
【从零学习python 】47. 面向对象编程中的继承概念及基本使用
【从零学习python 】46. Python中的__new__和__init__方法解析及单例设计模式
【从零学习python 】45.Python中的类方法和静态方法
【从零学习python 】44.面向对象编程中的私有属性和方法
【从零学习python 】43. Python面向对象编程中的实例属性和类属性
【从零学习python 】42.Python中的内置属性和方法
【从零学习python 】41.python魔法方法(二)
【从零学习python 】40.python魔法方法(一)
【从零学习python 】39.面向对象基本语法及应用示例
【从零学习python 】38.Python包的使用及导入方式
【从零学习python 】37.Python自定义模块的使用和注意事项
【从零学习python 】36.Python中使用pip进行第三方包管理的方法与技巧
【从零学习python 】35. Python常见系统模块及其用法
【从零学习python 】34.Python模块的导入和使用方法详解
【从零学习python 】33.装饰器的作用(二)
【从零学习python 】32.装饰器的作用(一)
【从零学习python 】31.深入理解Python中的高阶函数和闭包
【从零学习python 】30.深入理解递归函数和匿名函数
【从零学习python 】29. 「函数参数详解」——了解Python函数参数的不同用法
【从零学习python 】28. Python中的局部变量和全局变量
【从零学习python 】27. Python 函数的使用及嵌套调用
【从零学习python 】25.函数:提高代码编写效率的利器
【从零学习python 】24. Python中的字符串操作与遍历方法
【从零学习python 】23. Python中集合(set)的使用方法和常见操作
【从零学习python 】22. Python中的字典的增删改查及字典的变量
【从零学习python 】21.Python中的元组与字典
【从零学习python 】20. Python列表操作技巧及实例
【从零学习python 】19. 循环遍历列表和列表嵌套的应用
【从零学习python 】18. Python列表的基本操作详解(一)
【从零学习python 】17. Python字符串的format方法(二)
【从零学习python 】16. Python字符串的format方法(一)
【从零学习python 】15.深入了解字符串及字符集编码
【从零学习python 】14.Python字符串常见操作(二)
【从零学习python 】13.Python字符串常见操作(一)
【从零学习python 】12.Python字符串操作与应用
【从零学习python 】11.Python循环语句和控制流程
【从零学习python 】10.Python条件语句和if嵌套详解
【从零学习python 】09.Python 中的条件判断语句
【从零学习python 】08.Python了解位运算符, 运算符优先级
【从零学习python 】07.Python运算符详解:赋值、比较和逻辑运算符
【从零学习python 】06. Python中运用算数运算符进行计算和字符串拼接
【从零学习python 】05. Python中的输出和输入
【从零学习python 】04. Python编程基础:变量、数据类型与标识符
【从零学习python 】03. Python交互式编程及注释详解
【从零学习python 】02. 开发工具介绍
【从零学习python 】01. 安装配置python