Sudo

来自 ArchWiki
(重定向自 Sudoers

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

Sudo 是 su 的替代品,用于以 root 用户身份运行命令。与 su 不同,后者启动一个 root shell,允许所有后续命令获得 root 访问权限,而 sudo 则为单个命令授予临时的权限提升。通过仅在需要时启用 root 权限,sudo 的使用减少了在调用的命令中出现拼写错误或 bug 从而破坏系统的可能性。

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

要在当前 shell 会话期间将 nano 建立为 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 密码而不是用户密码,方法是在 /etc/sudoers 中的 Defaults 行添加 targetpw(目标用户,默认为 root)或 rootpw

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 runaway process 时,他们可以切换到该用户。

$ 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) § 包括来自 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 “使用 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)合并。这可以防止 sudo 创建权限比用户 umask 允许的权限更开放的文件。虽然如果没有使用自定义 umask,这是一个合理的默认值,但这可能会导致 sudo 运行的实用程序创建的文件权限与直接由 root 运行的文件权限不同的情况。如果由此产生错误,sudo 提供了一种修复 umask 的方法,即使所需的 umask 比用户指定的 umask 更宽松。添加此项(使用 visudo)将覆盖 sudo 的默认行为

Defaults umask = 0022
Defaults umask_override

这将 sudo 的 umask 设置为 root 的默认 umask (0022) 并覆盖默认行为,始终使用指示的 umask,而不管用户设置的 umask 是什么。