6 个超实用的 Sudo 命令使用技巧

Posted by Mike on 2021-03-12

Sudo 授权需谨慎,否则亲人两行泪!

sudo 表示 “superuser do”,它允许已验证的用户以其他用户的身份来运行命令。其他用户可以是普通用户或者超级用户。然而,大部分时候我们用它来提权运行命令,以替代直接使用 root 用户的操作。sudo 命令与安全策略配合使用,安全策略可以通过文件 /etc/sudoers 来配置。其安全策略具有高度可拓展性,支持插件扩展。默认情况下 /etc/sudoers 是不能被任何人直接编辑的,因为它的权限是 440,虽然也可以对其赋予写权限后再编辑,但推荐使用 visudo 命令编辑该文件。

1. 工作模式理解

简述其使用工作流程和配置文件配置!

  • [1] 理解 sudo 命令的工作流程
    • sudo 会读取和解析 /etc/sudoers 文件,查找调用命令的用户及其权限。
    • 然后提示调用该命令的用户输入密码,或者也可以通过 NOPASSWD 标志来跳过密码验证。
    • 之后,sudo 创建一个子进程,调用 setuid() 来切换到目标用户。
    • 最好,它会在上述子进程中执行参数给定的 shell 或命令。
  • [2] 理解 sudo 命令授权配置
    • USER/GROUP HOST=(USER[:GROUP]) [NOPASSWD:] COMMANDS
    • USER/GROUP: 表示需要被授权的用户或者组;如果是组则需要以 % 开头
    • HOST: 表示允许从哪些主机登录的用户运行 sudo 命令;ALL 表示允许从任何终端、机器访问
    • (USER[:GROUP]): 表示使用 sudo 可切换的用户或者组,组可以不指定;ALL 表示可以切换到系统的所有用户
    • NOPASSWD: 如果指定,则该用户或组使用 sudo 时不必输入密码
    • COMMANDS: 表示运行指定的命令;ALL 表示允许执行所有命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 允许 sudo 组执行所有命令
%sudo ALL=(ALL:ALL) ALL

# 允许用户执行所有命令,且无需输入密码
escape ALL =(ALL) NOPASSWD: ALL

# 仅允许用户执行 echo, ls 命令
escape ALL =(ALL) NOPASSWD: /bin/echo /bin/ls

# 运行本机的用户执行关机命令
escape localhost=/sbin/shutdown -h now

# 允许 users 用户组中的用户像 root 用户一样使用 mount、unmount、chrom 命令
%users ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom
  • [3] 配置 Defaults 选项
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 指定用户尝试输入密码的次数,默认值为3
Defaults passwd_tries=5

# 设置密码超时时间,默认为 5 分钟
Defaults passwd_timeout=2

默认 sudo 询问用户自己的密码,添加 targetpw 或 rootpw 配置可以让 sudo 询问 root 密码
Defaults targetpw

# 指定自定义日志文件
Defaults logfile="/var/log/sudo.log"

# 要在自定义日志文件中记录主机名和四位数年份,可以加上 log_host 和 log_year 参数
Defaults log_host, log_year, logfile="/var/log/sudo.log"

# 保持当前用户的环境变量
Defaults env_keep += "LANG LC_ADDRESS LC_CTYPE COLORS DISPLAY HOSTNAME EDITOR"
Defaults env_keep += "ftp_proxy http_proxy https_proxy no_proxy"

# 安置一个安全的 PATH 环境变量
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

2. 使用技巧总结

主要介绍使用 sudo 相关命令的使用技巧和问题处理方式!

  • [1] 如何将 visudo 编辑器从 nano 更改为 vim?

当我使用 visudo 命令的时候,它总是用 nano 编辑器打开它,对应平时习惯使用 vi 或者 vim 的用户来说,显得有些别扭,以及操作不够自如。所以,如何更好的将 visudo 编辑器从 nano 更改为 vim 就变得非常重要了。

最佳的解决办法,就是调用命令,永久的将终端的编辑器更换成为 vim 编辑器,一劳永逸。我们只需要执行如下命令,输入自己需要的编辑器序号并按下回车键即可。下次执行 visudo 命令的时候,就会使用 vim 编辑器打开文件。

1
2
3
4
5
6
7
8
9
10
11
12
# 因为/etc/sudoers普通用户无法打开和使用
$ sudo update-alternatives --config editor
There are 4 choices for the alternative editor (providing /usr/bin/editor).
Selection Path Priority Status
------------------------------------------------------------
* 0 /bin/nano 40 auto mode
1 /bin/ed -100 manual mode
2 /bin/nano 40 manual mode
3 /usr/bin/vim.basic 30 manual mode
4 /usr/bin/vim.tiny 10 manual mode

Press enter to keep the current choice[*], or type selection number: 3

其次的解决方法,就是通过环境变量修改当前终端的默认编辑器。

1
2
3
4
5
6
7
8
# 在.zshrc或.profile文件中
$ export EDITOR=vim;

# 希望执行对visudo生效
$ sudo EDITOR=vim visudo

# 或者修改/etc/sudoers文件的默认编辑器
Defaults editor=/usr/bin/vim
  • [2] Vim 如何强制保存只读文件?

在使用 vim 的时候,当以普通用户打开一个只有 root 用户才有权限操作的文件时,在编辑完成之后保存时发现,这个文件没有权限修改。好不容易把文件编辑完了,却无法保存,就只能放弃,然后退出,再以 root 权限打开,重新编辑,是在痛苦!那有没有好的方法来解决这个问题呢?咳咳咳,肯定是有的。

1
2
3
4
5
6
# Vim命令模式下执行即可强制保存
# w: 表示保存文件
# !: 表示执行外部命令
# tee: 表示把数据重定向到给定文件和屏幕上
# %: 在执行外部命令时,%会扩展成当前文件名
:w !sudo tee %

上述方式非常完美的解决了不能保存只读文件的问题,但毕竟命令还是有些长,为了避免每次输入一长串的命令,可以将它映射为一个简单的命令加到 .vimrc 中。这样,简单的运行 :w!! 即可,命令后半部分 > /dev/null 作用为显式的丢掉标准输出的内容。

1
2
" Allow saving of files as sudo when I forgot to start vim using sudo.
cmap w!! w !sudo tee > /dev/null %
  • [3] 如何更加安全地编辑文件?

Sudoedit 是一个内置命令,允许用户安全地编辑文件。根据 sudo 手册页,sudoedit 等效于使用 -e 命令行选项执行 sudo

那么这个命令会做什么呢,它会首先创建你要编辑的文件的临时副本。然后,命令将搜索 SUDO_EDITORVISUALEDITOR 环境变量(按此顺序),以确定应调用哪个编辑器来打开刚刚创建的临时副本。 用户完成修改工作后,更改将复制回原始文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Sudo命令手册页
-e, --edit
Edit one or more files instead of running a command. In lieu of a path name,
the string "sudoedit" is used when consulting the security policy. If the user
is authorized by the policy, the followingsteps are taken:

1. Temporary copies are made of the files to be edited with
the owner set to the invoking user.

2. The editor specified by the policy is run to edit the
temporary files. The sudoers policy uses the
SUDO_EDITOR, VISUAL and EDITOR environment variables (in
that order). If none of SUDO_EDITOR, VISUAL or EDITOR
are set, the first program listed in the editor
sudoers(5) option is used.

3. If they have been modified, the temporary files are
copied back to their original location and the temporary
versions are removed.

If the specified file does not exist, it will be created. Note that unlike most
commands run by sudo, the editor is run with the invoking user is environment
unmodified. If, for some reason, sudo is unable to update a file with its edited
version, the user will receive a warning and the edited copy will remain in a
temporary file.
  • [4] 如何让 sudo 会话时间随心所欲?

其中 sudo 命令是权限委派的命令,在生产环境中是非常常用的,默认情况下 sudo 命令会话时间是在 15 分钟。要设置 sudo 密码超时的值,需要使用 passwd_timeout 参数进行设置。

可以以分钟设置为你所需的任何时间,它会在超时之前一直等待。 如果要为每个执行的 sudo 命令弹出密码提示,你也可以将时间设置为 0,或者通过设置值 -1 永久禁用密码提示。

1
2
3
# 设置timeout时间
# 意味着sudo密码提示将会在用户使用20分钟后过期
Defaults env_reset,timestamp_timeout=20
  • [5] 如何更加安全的授权服务器权限?

如何我们管理的服务器,开发或者其他人员需要登录该服务器,进行环境调试或者问题复现等情况。这时,就需要我们给对应的用户开通登录的访问权限。但是如果我们直接编辑 /etc/sudoers 文件的话,之后当对方使用完成之后我就还需要手动进行清理。如果我们忘记的话,该开发或者其他人员将一直可以登录该服务器,会有一定程度的安全问题。

不幸的是,对应临时授权的话,/etc/sudoers 文件中没有对应的配置,可以对某个用户或者用户组进行指定范围的时间授权。当用户到达指定时间点之后,将拒绝该用户再次进行登录了。对应此种情况,我们可以通过 crontab 定时任务与 /etc/sudoers.d 目录的机制可以完美的解决上述问题。

我们通过定时任务的定时执行目录,来定时刷掉 /etc/sudoers.d/ 目录下的用户或者用户组的授权配置文件。比如,我们需要定时每日刷掉今日临时授权的用户或者用户,可以在 /etc/cron.daily 目录下面创建用于删除 /etc/sudoers.d/ 目录的 rm -rf 命令,之后在固定的时间会自动删除。对应授权用户,我们使用在 /etc/sudoers.d/ 目录下创建单独的配置文件,而不是直接修改 /etc/sudoers 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Crontab有多种定时机制
# 下述分别表示每天、每时、每月、每周定时执行
$ ls -dl /etc/cron.* | grep -v cron.d$
drwxr-xr-x 2 root root 4096 May 15 06:18 /etc/cron.daily
drwxr-xr-x 2 root root 4096 Feb 14 2019 /etc/cron.hourly
drwxr-xr-x 2 root root 4096 Feb 14 2019 /etc/cron.monthly
drwxr-xr-x 2 root root 4096 Jun 18 09:57 /etc/cron.weekly

# 创建单独的授权配置文件
$ ls -lh /etc/sudoers.d/
-r--r----- 1 root root 666 Oct 6 2017 lisi
-r--r----- 1 root root 958 Jan 18 2018 zhangsan

# 查看授权配置文件的内容
$ cat /etc/sudoers.d/zhangsan
ALL ALL = (root) NOPASSWD: zhangsan
  • [6] 如何解决 sudo 命令找不到环境变量?

我们日常在使用 sudo 命令的时候,常常会遇到,当切换用户之后,发现之前设置的环境变量怎么不见了呢?这是因为,我们执行 sudo 命令之后会切换用户,如果保留环境变量会有一定的安全问题,系统会默认重置环境变量为安全的环境变量。先前设置的变量都会失效,只有少数配置文件中指定的环境变量能够保存下来。

我们可以看一下 sudo 配置文件 /etc/sudoers 来找找作用原因。我们执行如下命令之后,可以看到如下输入(有可能和我这里的不一样)。其中 env_reset 表示默认会重置环境变量,因此我们自定义的变量会在 sudo 命令执行之后失效,也就不会正确获取变量值了。而 env_keep 则表示用于保留部分环境变量不被重置,需要保留的变量就写入双引号之中,可自行追加需要保留的变量。最后就是 secure_path 变量,其作用就是包含的路径将被当做 sudo 环境的 PATH 变量来使用。如果在 sudo 环境无法找到某些命令,那么可以将这些命令的路径加入该配置项之中。

1
2
3
4
5
$ sudo sed '/^#/d;/^$/d' /etc/sudoers
Defaults env_reset
Defaults env_keep = "COLORS IDSPLAY HOSTNAME HISTSIZE LS_COLORS"
Defaults env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS"
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"

我们知道原因之后,就可以针对上述情况作出不用的处理方式,来解决 sudo 命令找不到环境变量的问题。

第一种解决方法,就是在使用的时候,使用 -E 参数。加上 -E 选项后,用户可以在 sudo 执行时保留当前用户已存在的环境变量,不会被 sudo 重置。另外,如果用户对于指定的环境变量没有权限,则会报错。需要注意的是,在内部测试机器中,安全性要求不高的情况下使用。

1
$ sudo sudo -E

第二种解决方法,就是修改 sudo 配置文件。可以通过修改 /etc/sudoers 文件的 env_keepsecure_path 配置项,来指定 sudo 环境中需要保留的环境变量和路径。当然,我们也可以把配置文件的变量 !env_reset 给去掉,这样就不会有限制了。

1
2
$ sudo vim /etc/sudoers
Defaults !env_reset

3. 参考链接地址

本文转载自:「 Escape 的博客 」,原文:https://tinyurl.com/y4r6d5fu,版权归原作者所有。欢迎投稿,投稿邮箱: editor@hi-linux.com