Sudo
Sudo 允许系统管理员委派权限,赋予特定用户或用户组以 root 用户或其他用户的身份运行命令的能力,同时提供命令及其参数的审计跟踪。
Sudo 是 su 的替代品,用于以 root 身份运行命令。与 su 不同,后者启动一个 root shell,允许所有后续命令具有 root 访问权限,而 sudo 仅为单个命令授予临时的权限提升。通过仅在需要时启用 root 权限,sudo 的使用降低了因输入错误或调用命令中的错误而破坏系统的可能性。
Sudo 也可用于以其他用户身份运行命令;此外,sudo 会将所有命令和失败的访问尝试记录到 journal 中,以进行安全审计。
安装
用法
要开始以非特权用户身份使用 sudo
,必须正确配置它。请参阅 #配置。
要使用sudo,只需在命令及其参数前加上 sudo
和一个空格
$ sudo cmd
例如,要使用 pacman
$ sudo pacman -Syu
有关更多信息,请参阅 sudo(8)。
登录 shell
您不能仅仅通过在前面加上 sudo 来以其他用户身份运行每个命令。特别是当使用重定向和命令替换时,您必须使用登录 shell,这可以通过 sudo -iu user
轻松访问(如果所需用户是 root,则可以省略 -u user
)。
在以下示例中,命令替换在完整的 shell 中可以工作,但使用前缀 sudo 则会失败
$ sudo wpa_supplicant -B -i interface -c <(wpa_passphrase MYSSID passphrase)
Successfully initialized wpa_supplicant Failed to open config file '/dev/fd/63', error: No such file or directory Failed to read or parse configuration '/dev/fd/63'
配置
默认值框架
sudoers(5) § SUDOERS OPTIONS 列出了可以在 /etc/sudoers
文件中与 Defaults
命令一起使用的所有选项。
请参阅 [1] 以获取选项列表(从版本 1.8.7 源代码解析),格式针对 sudoers
进行了优化。
有关更多信息,例如配置密码超时,请参阅 sudoers(5)。
查看当前设置
运行 sudo -ll
以打印当前的 sudo 配置,或运行 sudo -lU user
以查看特定用户的配置。
使用 visudo
sudo 的配置文件是 /etc/sudoers
。始终应使用 visudo(8) 命令编辑它。visudo 锁定 sudoers
文件,将编辑内容保存到临时文件,并在将其复制到 /etc/sudoers
之前检查其语法错误。
sudoers
文件中必须没有语法错误!任何错误都会使 sudo 无法使用。始终使用 visudo 编辑它以防止错误。- visudo(8) 警告说,配置 visudo 以遵循用户环境变量中选择的编辑器可能是一个安全漏洞,因为它允许具有 visudo 权限的用户通过将该变量设置为其他内容来以 root 身份运行任意命令而无需记录。
visudo 的默认编辑器是 vi。sudo 软件包在编译时使用了 --with-env-editor
,并遵循 SUDO_EDITOR
、VISUAL
和 EDITOR
变量的使用。当设置了 VISUAL
时,不使用 EDITOR
。
要将 nano 设置为当前 shell 会话期间 visudo 的编辑器,请导出 EDITOR=nano
;要仅使用不同的编辑器一次,只需在调用 visudo 之前设置该变量
# EDITOR=nano visudo
或者,您可以编辑 /etc/sudoers
文件的副本,并使用 visudo -c /copy/of/sudoers
检查它。如果您想绕过使用 visudo 锁定文件,这可能会派上用场。
要永久更改编辑器,请参阅 环境变量#用户级别。要仅为 visudo 系统范围地永久更改所选编辑器,请将以下内容添加到 /etc/sudoers
(假设 nano 是您的首选编辑器)
# Set default EDITOR to restricted version of nano, and do not allow visudo to use EDITOR/VISUAL. Defaults editor=/usr/bin/rnano, !env_editor
示例条目
要允许用户在使用 sudo
前缀命令时获得完全 root 权限,请添加以下行
USER_NAME ALL=(ALL:ALL) ALL
要允许用户在主机名为 HOST_NAME
的机器上以任何用户身份运行所有命令
USER_NAME HOST_NAME=(ALL:ALL) ALL
要允许 wheel 组的成员使用 sudo 访问
%wheel ALL=(ALL:ALL) ALL
wheel
组启用 sudo 访问,并将用户添加到该组,因为默认情况下 Polkit 将 wheel
组的成员视为管理员。如果用户不是 wheel
组的成员,则使用 Polkit 的软件可能会要求使用 root 密码而不是用户密码进行身份验证。要禁用用户 USER_NAME
的密码询问
Defaults:USER_NAME !authenticate
仅对主机 HOST_NAME
上的用户 USER_NAME
启用显式定义的命令
USER_NAME HOST_NAME=/usr/bin/halt,/usr/bin/poweroff,/usr/bin/reboot,/usr/bin/pacman -Syu
%wheel
行之后。仅对主机 HOST_NAME
上的用户 USER_NAME
启用显式定义的命令,且无需密码
USER_NAME HOST_NAME= NOPASSWD: /usr/bin/halt,/usr/bin/poweroff,/usr/bin/reboot,/usr/bin/pacman -Syu
详细的 sudoers
示例如 /usr/share/doc/sudo/examples/sudoers
中所示。否则,请参阅 sudoers(5) 以获取详细信息。
Sudoers 默认文件权限
sudoers
文件的所有者和组都必须为 0。文件权限必须设置为 0440。这些权限是默认设置的,但如果您意外更改了它们,应立即将其改回,否则 sudo 将会失败。
# chown -c root:root /etc/sudoers # chmod -c 0440 /etc/sudoers
技巧与提示
禁用密码提示超时
一个常见的烦恼是,在某个后台终端上运行的长时间运行的进程,以普通权限运行,仅在需要时提升权限。这会导致 sudo 密码提示被忽略并超时,此时进程终止,已完成的工作丢失,或者充其量只是缓存。常见的建议是启用无密码 sudo,或延长 sudo 记住密码的超时时间。这两者都具有负面的安全影响。提示超时也可以禁用,并且由于它不服务于任何合理的安全目的,因此应该是此处的解决方案
Defaults passwd_timeout=0
Bash 补全
要使 sudo 命令可以使用完整功能的 bash 补全,请安装 bash-completion 软件包。如果由于某种原因无法安装此软件包,则另一种提供简化的 sudo 命令自动补全功能的方法是将以下内容添加到您的 .bashrc 中
complete -cf sudo
传递别名
以下内容仅在 bash 补全不可用时相关(无论是完整的还是如上所述的简化版本):Zsh 和 Bash 中的别名通常仅针对命令中的第一个单词进行扩展。这意味着当运行 sudo
命令时,您的别名通常不会被扩展。使下一个单词扩展的一种方法是为以空格结尾的 sudo 创建别名。将以下内容添加到您的shell 配置文件中
alias sudo='sudo '
zshmisc(1) § ALIASING 描述了它的工作原理
- 如果替换文本以空格结尾,则 shell 输入中的下一个单词始终符合别名扩展的条件。
- 如果别名值的最后一个字符是空格,则别名后的下一个命令词也会检查是否进行别名扩展。
在密码提示中添加终端响铃
为了引起对后台终端中 sudo 提示的注意,用户可以简单地使其回显一个 响铃字符
Defaults passprompt="^G[sudo] password for %p: "
请注意 ^G
是一个字面意义上的响铃字符。例如,在 vim 中,使用序列 Ctrl+v
Ctrl+g
插入。如果 Ctrl+v
被映射,例如用于粘贴,则通常可以使用 Ctrl+q
代替。在 nano 中,使用 Alt+v
Ctrl+g
。
另一种选择是设置 SUDO_PROMPT
环境变量。例如,将以下内容添加到您的 shell 配置文件中
export SUDO_PROMPT=$'\a[sudo] password for %p: '
禁用单终端 sudo
如果您对 sudo 的默认设置感到恼火,它要求您每次打开新终端时都输入密码,请将 timestamp_type
设置为 global
Defaults timestamp_type=global
减少密码输入次数
如果您对每 5 分钟(默认)必须重新输入密码感到恼火,您可以通过为 timestamp_timeout
设置更长的值(以分钟为单位)来更改此设置
Defaults timestamp_timeout=10
如果您在长时间运行的脚本中使用 sudo 命令,并且不希望在超时到期时等待用户输入,则可以通过在循环中单独运行 sudo -v
来刷新超时时间(而 sudo -K
会立即撤销它)。
环境变量
如果您有很多环境变量,或者您通过 export http_proxy="..."
导出代理设置,则在使用 sudo 时,这些变量不会传递给 root 帐户,除非您使用 -E
/--preserve-env
选项运行 sudo。
$ sudo -E pacman -Syu
保留环境变量的推荐方法是将它们附加到 env_keep
/etc/sudoers
Defaults env_keep += "ftp_proxy http_proxy https_proxy no_proxy"
Root 密码
用户可以配置 sudo 以要求输入 root 密码而不是用户密码,方法是将 targetpw
(目标用户,默认为 root)或 rootpw
添加到 /etc/sudoers
中的 Defaults 行
Defaults targetpw
为了防止将您的 root 密码暴露给用户,您可以将此限制为特定组
Defaults:%wheel targetpw %wheel ALL=(ALL) ALL
禁用 root 登录
用户可能希望禁用 root 登录。如果没有 root,攻击者必须首先猜测配置为 sudoer 的用户名以及用户密码。例如,请参阅 OpenSSH#拒绝。
- 请注意,您可能会因禁用 root 登录而将自己锁定在外。Sudo 不会自动安装,其默认配置既不允许无密码 root 访问,也不允许使用您自己的密码进行 root 访问。在禁用 root 帐户之前,请确保用户已正确配置为 sudoer!
- 如果您已更改 sudoers 文件以默认使用 rootpw,则不要使用以下任何命令禁用 root 登录!
- 如果您已被锁定在外,请参阅 密码恢复 以获得帮助。
可以通过 passwd
锁定帐户
# passwd -l root
类似的命令会解锁 root。
$ sudo passwd -u root
或者,编辑 /etc/shadow
并将 root 的加密密码替换为 !*
root:!*:12345::::::
要再次启用 root 登录
$ sudo passwd root
如果发生系统紧急情况,恢复提示将要求您输入 root 密码,从而无法登录到恢复 shell。要在紧急情况下自动解锁 root 帐户,请使用 drop-in 文件 将 SYSTEMD_SULOGIN_FORCE=1
环境变量添加到 rescue.service
/etc/systemd/system/rescue.service.d/SYSTEMD_SULOGIN_FORCE.conf
[Service] Environment=SYSTEMD_SULOGIN_FORCE=1
sudo -i
。kdesu
kdesu 可以在 KDE 下使用,以 root 权限启动 GUI 应用程序。默认情况下,即使 root 帐户被禁用,kdesu 也可能会尝试使用 su。幸运的是,您可以告诉 kdesu 使用 sudo 而不是 su。创建/编辑文件 ~/.config/kdesurc
[super-user-command] super-user-command=sudo
或使用以下命令
$ kwriteconfig6 --file kdesurc --group super-user-command --key super-user-command sudo
sudo 强化示例
假设您创建了 3 个用户:admin、devel 和 archie。用户“admin”用于 journalctl、systemctl、mount、kill 和 iptables;“devel”用于安装软件包和编辑配置文件;“archie”是您登录的用户。要让“archie”重启、关机并使用 netctl,我们将执行以下操作
编辑 /etc/pam.d/su
和 /etc/pam.d/su-l
。要求用户属于 wheel 组,但不要将任何人放入其中。
#%PAM-1.0 auth sufficient pam_rootok.so # Uncomment the following line to implicitly trust users in the "wheel" group. #auth sufficient pam_wheel.so trust use_uid # Uncomment the following line to require a user to be in the "wheel" group. auth required pam_wheel.so use_uid auth required pam_unix.so account required pam_unix.so session required pam_unix.so
将 SSH 登录限制为“ssh”组。只有“archie”将成为该组的成员。
# groupadd -r ssh # gpasswd -a archie ssh # echo 'AllowGroups ssh' >> /etc/ssh/sshd_config
重启 sshd.service
。
将用户添加到其他组。
# for g in power network ;do ;gpasswd -a archie $g ;done # for g in network power storage ;do ;gpasswd -a admin $g ;done
设置配置文件的权限,以便 devel 可以编辑它们。
# chown -R devel:root /etc/{http,openvpn,cups,zsh,vim,screenrc}
Cmnd_Alias POWER = /usr/bin/shutdown -h now, /usr/bin/halt, /usr/bin/poweroff, /usr/bin/reboot Cmnd_Alias STORAGE = /usr/bin/mount -o nosuid\,nodev\,noexec, /usr/bin/umount Cmnd_Alias SYSTEMD = /usr/bin/journalctl, /usr/bin/systemctl Cmnd_Alias KILL = /usr/bin/kill, /usr/bin/killall Cmnd_Alias PKGMAN = /usr/bin/pacman Cmnd_Alias NETWORK = /usr/bin/netctl Cmnd_Alias FIREWALL = /usr/bin/iptables, /usr/bin/ip6tables Cmnd_Alias SHELL = /usr/bin/zsh, /usr/bin/bash %power ALL = (root) NOPASSWD: POWER %network ALL = (root) NETWORK %storage ALL = (root) STORAGE root ALL = (ALL) ALL admin ALL = (root) SYSTEMD, KILL, FIREWALL devel ALL = (root) PKGMAN archie ALL = (devel) SHELL, (admin) SHELL
通过此设置,您几乎永远不需要以 root 用户身份登录。
“archie”可以连接到他们的家庭 Wi-Fi。
$ sudo netctl start home $ sudo poweroff
“archie”不能以任何其他用户身份使用 netctl。
$ sudo -u admin -- netctl start home
当“archie”需要使用 journalctl 或 kill 掉失控进程时,他们可以切换到该用户。
$ sudo -i -u devel $ sudo -i -u admin
但是“archie”无法切换到 root 用户。
$ sudo -i -u root
如果“archie”想要以 admin 身份启动 gnu-screen 会话,他们可以这样做
$ sudo -i -u admin [admin]$ chown admin:tty `echo $TTY` [admin]$ screen
使用 /etc/sudoers.d 中的 drop-in 文件配置 sudo
sudo 解析 /etc/sudoers.d/
目录中包含的文件。这意味着您可以更改独立文件中的设置并将其放入该目录,而不是编辑 /etc/sudoers
。这有两个优点
- 无需编辑
sudoers.pacnew
文件; - 如果新条目有问题,您可以删除有问题的的文件,而不是编辑
/etc/sudoers
(但请参阅下面的警告)。
这些 drop-in 文件中的条目格式与 /etc/sudoers
本身的格式相同。要直接编辑它们,请使用 visudo -f /etc/sudoers.d/somefile
。有关详细信息,请参阅 sudoers(5) § Including other files from within sudoers。
/etc/sudoers.d/
目录中的文件按字典顺序解析,文件名包含 .
或 ~
的文件将被跳过。为避免排序问题,文件名应以两位数字开头,例如 01_foo
。
/etc/sudoers.d/
中的文件与 /etc/sudoers
本身一样脆弱:任何格式不正确的文件都将阻止 sudo
工作。因此,出于相同的原因,强烈建议使用 visudo
编辑文件
sudo
提供了 sudoedit
命令(相当于 sudo -e
)。这对于编辑只能由 root 编辑的文件很有用,同时仍然以普通用户身份运行编辑器,并使用该用户的配置。
要编辑文件,请将 SUDO_EDITOR
设置为编辑器的名称,并将文件名传递给 sudoedit
。例如
$ SUDO_EDITOR=vim sudoedit /etc/file
有关设置编辑器的方法,请参阅 #使用 visudo 和 sudo(8) § e,但请注意 可能的安全问题。
如果将多个名称传递给 sudo
,则所有文件都会在单个调用中在编辑器中打开。此功能对于合并文件很有用
$ SUDO_EDITOR=vimdiff sudoedit /etc/file /etc/file.pacnew
启用侮辱模式
用户可以通过使用 visudo
在 sudoers
文件中添加以下行来启用 sudo 中的侮辱彩蛋。
/etc/sudoers
Defaults insults
输入不正确的密码后,这将把 Sorry, try again.
消息替换为幽默的侮辱。
启用密码输入反馈
默认情况下,当您输入密码时,没有视觉反馈。这是为了额外的安全性而故意完成的。但是,如果您希望获得视觉输入,可以通过添加此行来启用它
/etc/sudoers
Defaults pwfeedback
彩色密码提示
要使用颜色和/或粗体字体自定义密码提示,请在 shell 初始化文件中设置 SUDO_PROMPT
环境变量,并使用 tput(1)。
例如,要将密码提示设置为以粗体红色显示 Password:
,请使用此命令
export SUDO_PROMPT="$(tput setaf 1 bold)Password:$(tput sgr0) "
或使用不同的颜色和默认消息,如下所示
export SUDO_PROMPT="$(tput setab 1 setaf 7 bold)[sudo]$(tput sgr0) $(tput setaf 6)password for$(tput sgr0) $(tput setaf 5)%p$(tput sgr0): "
有关更多信息,请参阅 控制台中的彩色输出 和 Bash/提示符自定义
使用 U2F
U2F 非常适合与 sudo 一起使用,因为它可以有效地消除公共区域中 肩窥 的风险,同时仍然让您可以通过简单的物理触摸有意识地控制批准提示。
请参阅 通用第二因素#无密码 sudo。
写入受保护的文件
使用 sudo 时,您可能需要写入受保护的文件。使用 tee 允许这种分离
$ input stream | sudo tee --option protected_file_1 protected_file_2...
当简单的 >
/>>
无效时。
在 Vim 中
当您忘记在编辑其他用户拥有的文件时以 sudo 启动 Vim 时,类似的概念很有用。在这种情况下,您可以在 Vim 内部执行以下操作以保存文件
:w !sudo tee %
您可以将此添加到您的 ~/.vimrc
中,以使用命令模式下的 :w!!
映射轻松使用此技巧
~/.vimrc
" Allow saving of files as sudo when I forgot to start vim using sudo cmap w!! w !sudo tee > /dev/null %
> /dev/null
部分显式地丢弃了标准输出,因为我们不需要将任何内容传递给另一个管道命令。
有关其工作原理的更详细解释,请参见 StackOverflow 上 vim “write with sudo” 技巧如何工作? 文章。
故障排除
没有 TTY 的 SSH 问题
SSH 在运行远程命令时默认不分配 tty。在没有分配 tty 的情况下,sudo 无法阻止密码显示。您可以使用 ssh 的 -t
选项强制其分配 tty。
Defaults
选项 requiretty
仅允许用户在他们拥有 tty 时运行 sudo。
# Disable "ssh hostname sudo <cmd>", because it will show the password in clear text. You have to run "ssh -t hostname sudo <cmd>". # #Defaults requiretty
宽松的 umask
Sudo 将用户的 umask 值与其自身的 umask(默认为 0022)进行 union 运算。这可以防止 sudo 创建权限比用户 umask 允许的更开放的文件。虽然这是在未使用自定义 umask 时合理的默认设置,但这可能会导致 sudo 运行的实用程序创建的文件权限与直接以 root 身份运行时不同的情况。如果由此产生错误,sudo 提供了一种修复 umask 的方法,即使所需的 umask 比用户指定的 umask 更宽松。添加以下内容(使用 visudo
)将覆盖 sudo 的默认行为
Defaults umask = 0022 Defaults umask_override
这会将 sudo 的 umask 设置为 root 的默认 umask (0022),并覆盖默认行为,始终使用指示的 umask,而不管用户设置的 umask 如何。