Sudo
Sudo 允许系统管理员委派权限,赋予特定用户或用户组以 root 或其他用户身份运行命令的能力,同时提供命令及其参数的审计跟踪。
Sudo 是 su 的替代品,用于以 root 身份运行命令。与启动 root shell 并允许后续所有命令以 root 权限访问的 su 不同,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'
配置
Defaults 骨架
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 锁定文件,这可能会派上用场。
要永久更改编辑器,请参阅 环境变量#按用户。要仅为 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
要允许 group 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 时,这些变量不会传递给 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#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
启用侮辱
用户可以通过使用 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 一起使用,因为它可以有效消除公共区域中肩窥的风险,同时仍然让您可以通过简单的物理触摸有意识地控制批准提示。
请参阅 Universal 2nd Factor#无密码 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。