Sudo
Sudo 允许系统管理员委派权限,赋予特定用户或用户组以 root 用户或其他用户的身份运行命令的能力,同时提供命令及其参数的审计跟踪。
Sudo 是 su 的替代方案,用于以 root 身份运行命令。与 su 不同,后者启动一个 root shell,允许所有后续命令都以 root 权限访问,而 sudo 则为单个命令授予临时的权限提升。通过仅在需要时启用 root 权限,使用 sudo 可以降低因输入错误或调用的命令中的 bug 而损坏系统的可能性。
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],以获取以 sudoers
优化的格式(从版本 1.8.7 源代码解析)的选项列表。
有关更多信息,例如配置密码超时,请参阅 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 锁定文件,这可能会派上用场。
要永久更改编辑器,请参阅 环境变量#Per user。要仅为 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 补全
为了使功能完善的 bash 补全可用于 sudo 命令,请安装软件包 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 时,除非您使用 -E
/--preserve-env
选项运行 sudo,否则这些变量不会传递到 root 帐户。
$ 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#Deny。
- 请注意,禁用 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
启用侮辱
用户可以通过在 sudoers
文件中使用 visudo
添加以下行来启用 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/Prompt 自定义 以了解更多信息
使用 U2F
U2F 非常适合与 sudo 一起使用,因为它可以有效地消除公共区域中 肩窥 的风险,同时仍让您可以通过简单的物理触摸来有意识地控制批准提示。
请参阅 Universal 2nd Factor#Passwordless 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 上的 How does the vim “write with sudo” trick work? 文章。
故障排除
没有 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)进行联合。这可以防止 sudo 创建权限比用户 umask 允许的更开放的文件。虽然如果没有使用自定义 umask,这是一个合理的默认值,但这可能会导致 sudo 运行的实用程序创建的文件权限与直接以 root 身份运行时不同的情况。如果因此出现错误,sudo 提供了一种修复 umask 的方法,即使所需的 umask 比用户指定的 umask 更宽松。添加此内容(使用 visudo
)将覆盖 sudo 的默认行为
Defaults umask = 0022 Defaults umask_override
这会将 sudo 的 umask 设置为 root 的默认 umask (0022) 并覆盖默认行为,始终使用指示的 umask,而与用户设置的 umask 无关。