Sudo

出自 ArchWiki
(重定向自 Sudoedit

Sudo 允许系统管理员委派权限,赋予特定用户或用户组以 root 用户或其他用户的身份运行命令的能力,同时提供命令及其参数的审计跟踪。

Sudo 是 su 的替代品,用于以 root 身份运行命令。与 su 不同,后者启动一个 root shell,允许所有后续命令具有 root 访问权限,而 sudo 仅为单个命令授予临时的权限提升。通过仅在需要时启用 root 权限,sudo 的使用降低了因输入错误或调用命令中的错误而破坏系统的可能性。

Sudo 也可用于以其他用户身份运行命令;此外,sudo 会将所有命令和失败的访问尝试记录到 journal 中,以进行安全审计。

安装

安装 sudo 软件包。

用法

要开始以非特权用户身份使用 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'

配置

本文或章节需要扩充。

原因: 创建一个介绍 Defaults 的引言,可能包含一个列出常用设置的表格(在 Talk:Sudo 中讨论)

默认值框架

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 的默认编辑器是 visudo 软件包在编译时使用了 --with-env-editor,并遵循 SUDO_EDITORVISUALEDITOR 变量的使用。当设置了 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 访问,并将用户添加到该组,因为默认情况下 Polkitwheel 组的成员视为管理员。如果用户不是 wheel 组的成员,则使用 Polkit 的软件可能会要求使用 root 密码而不是用户密码进行身份验证。

要禁用用户 USER_NAME 的密码询问

警告: 这将允许任何以您的用户名运行的进程在无需询问权限的情况下使用 sudo。
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-completion。(在 Talk:Sudo 中讨论)

要使 sudo 命令可以使用完整功能的 bash 补全,请安装 bash-completion 软件包。如果由于某种原因无法安装此软件包,则另一种提供简化的 sudo 命令自动补全功能的方法是将以下内容添加到您的 .bashrc

complete -cf sudo

传递别名

以下内容仅在 bash 补全不可用时相关(无论是完整的还是如上所述的简化版本):ZshBash 中的别名通常仅针对命令中的第一个单词进行扩展。这意味着当运行 sudo 命令时,您的别名通常不会被扩展。使下一个单词扩展的一种方法是为以空格结尾的 sudo 创建别名。将以下内容添加到您的shell 配置文件

alias sudo='sudo '

zshmisc(1) § ALIASING 描述了它的工作原理

如果替换文本以空格结尾,则 shell 输入中的下一个单词始终符合别名扩展的条件。

以及 bash(1) § ALIASES

如果别名值的最后一个字符是空格,则别名后的下一个命令词也会检查是否进行别名扩展。

在密码提示中添加终端响铃

为了引起对后台终端中 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 的情况也是如此。是否有替代方案,例如使用“-B”选项作为默认值?(在 Talk:Sudo 中讨论)

另一种选择是设置 SUDO_PROMPT 环境变量。例如,将以下内容添加到您的 shell 配置文件中

export SUDO_PROMPT=$'\a[sudo] password for %p: '

禁用单终端 sudo

警告: 这将允许任何进程使用您的 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

本文或章节的事实准确性存在争议。

原因: 在大多数情况下,当用户最终进入紧急 shell 时,他们使用的是 initramfs,除非添加到 mkinitcpio 的配置 中的 FILES,否则不会使用以下配置。(在 Talk:Sudo 中讨论)

如果发生系统紧急情况,恢复提示将要求您输入 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
提示: 要在禁用 root 帐户后仍然获得交互式 root 提示符,请使用 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

注意: drop-in 文件中条目的顺序很重要:确保语句不会相互覆盖。
警告: /etc/sudoers.d/ 中的文件与 /etc/sudoers 本身一样脆弱:任何格式不正确的文件都将阻止 sudo 工作。因此,出于相同的原因,强烈建议使用 visudo

编辑文件

sudo 提供了 sudoedit 命令(相当于 sudo -e)。这对于编辑只能由 root 编辑的文件很有用,同时仍然以普通用户身份运行编辑器,并使用该用户的配置。

要编辑文件,请将 SUDO_EDITOR 设置为编辑器的名称,并将文件名传递给 sudoedit。例如

$ SUDO_EDITOR=vim sudoedit /etc/file

有关设置编辑器的方法,请参阅 #使用 visudosudo(8) § e,但请注意 可能的安全问题

如果将多个名称传递给 sudo,则所有文件都会在单个调用中在编辑器中打开。此功能对于合并文件很有用

$ SUDO_EDITOR=vimdiff sudoedit /etc/file /etc/file.pacnew

启用侮辱模式

用户可以通过使用 visudosudoers 文件中添加以下行来启用 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 问题

本文或章节是与 #配置 合并的候选对象。

注意: 请使用模板的第二个参数来提供更详细的指示。(在 Talk:Sudo 中讨论)

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

本文或章节是与 #配置 合并的候选对象。

注意: 请使用模板的第二个参数来提供更详细的指示。(在 Talk:Sudo 中讨论)

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 如何。