在 Linux 中使用 sudo 委派权限

了解如何在保护 root 密码安全的同时,将管理网络功能或特定服务的权限分配给受信任的用户。
490 位读者喜欢这个。
unspoken blockers

Opensource.com

我最近编写了一个简短的 Bash 程序,用于将 MP3 文件从一个网络主机上的 USB 拇指驱动器复制到另一个网络主机。这些文件被复制到我在一个志愿者组织运行的服务器上的特定目录,文件可以从那里下载和播放。

我的程序还做了一些其他事情,例如在复制文件之前更改文件名,以便它们在网页上自动按日期排序。它还在验证传输已正确完成后,删除 USB 驱动器上的所有文件。这个不错的小程序有一些选项,例如 -h 显示帮助,-t 用于测试模式,以及其他几个选项。

我的程序虽然很棒,但必须以 root 用户身份运行才能执行其主要功能。不幸的是,这个组织只有少数人对管理我们的音频和计算机系统感兴趣,这使我不得不寻找半技术人员并培训他们登录到用于执行传输的计算机并运行这个小程序。

并非我自己不能运行该程序,但是由于各种原因,包括旅行和疾病,我并不总是在那里。即使我在场,作为“懒惰的系统管理员”,我也喜欢让别人为我工作。因此,我编写脚本来自动化这些任务,并使用 sudo 来授权几个用户运行这些脚本。许多 Linux 命令需要用户成为 root 用户才能运行。这可以保护系统免受意外损坏(例如我自己的愚蠢造成的损坏)以及恶意用户的故意损坏。

出色地使用 sudo

sudo 程序是一个方便的工具,它允许我作为具有 root 访问权限的系统管理员,将所有或部分管理任务的责任委派给计算机的其他用户。它允许我执行委派,而不会泄露 root 密码,从而保持主机上的高安全性。

让我们假设,例如,我已经授予普通用户“ruser”访问我的 Bash 程序“myprog”的权限,该程序必须以 root 用户身份运行才能执行其部分功能。首先,用户以 ruser 身份使用自己的密码登录,然后使用以下命令运行 myprog。

	sudo myprog

sudo 程序检查 /etc/sudoers 文件,并验证是否允许 ruser 运行 myprog。如果是,sudo 会请求用户输入他们的密码,而不是 root 密码。在 ruser 输入他们的密码后,程序运行。此外,sudo 会记录对 myprog 的访问事实,包括程序运行的日期和时间、完整命令以及运行该命令的用户。此数据记录在 /var/log/security 中。

我发现拥有 sudo 运行的每个命令的日志对于培训很有帮助。我可以查看谁做了什么以及他们是否正确输入了命令。

我这样做是为了委派权限给自己和另一位用户运行单个程序;但是,sudo 可以用于做更多的事情。它可以允许系统管理员将管理网络功能或特定服务的权限委派给个人或一组受信任的用户。它允许在保护 root 密码安全性的同时委派这些功能。

配置 sudoers 文件

作为系统管理员,我可以使用 /etc/sudoers 文件来允许用户或用户组访问单个命令、定义的命令组或所有命令。这种灵活性是使用 sudo 进行委派的强大功能和简单性的关键。

我最初发现 sudoers 文件非常令人困惑,因此下面我复制并解构了我正在使用它的主机上的整个 sudoers 文件。希望当您完成此分析后,它对您来说不会那么晦涩难懂。顺便说一句,我发现基于 Red Hat 的发行版中的默认配置文件往往有很多注释和示例来提供指导,这使得事情变得更容易,减少了在线搜索的需求。

不要使用标准编辑器修改 sudoers 文件。使用 visudo 命令,因为它旨在在文件保存并退出编辑器后立即启用任何更改。可以使用除 Vi 之外的编辑器,其方式与 visudo 相同。

让我们从文件开头的几个别名类型开始分析。

主机别名

主机别名部分用于创建主机组,命令或命令别名可以在这些主机组上使用,以提供访问权限。基本思想是,此单个文件将为组织中的所有主机维护,并复制到每个主机的 /etc。因此,某些主机(例如服务器)可以配置为组,以授予某些用户访问特定命令的权限,例如启动和停止 HTTPD、DNS 和网络等服务的能力;挂载文件系统;等等。

IP 地址可以代替主机名在主机别名中使用。

## Sudoers allows particular users to run various commands as
## the root user, without needing the root password.
##
## Examples are provided at the bottom of the file for collections
## of related commands, which can then be delegated out to particular
## users or groups.
## 
## This file must be edited with the 'visudo' command.

## Host Aliases
## Groups of machines. You may prefer to use hostnames (perhaps using 
## wildcards for entire domains) or IP addresses instead.
# Host_Alias     FILESERVERS = fs1, fs2
# Host_Alias     MAILSERVERS = smtp, smtp2

## User Aliases
## These aren't often necessary, as you can use regular groups
## (ie, from files, LDAP, NIS, etc) in this file - just use %groupname 
## rather than USERALIAS
# User_Alias ADMINS = jsmith, mikem
User_Alias AUDIO = dboth, ruser

## Command Aliases
## These are groups of related commands...

## Networking
# Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, /sbin/dhclient, /usr/bin/net, /sbin/iptables, /usr/bin/rfcomm, /usr/bin/wvdial, /sbin/iwconfig, /sbin/mii-tool

## Installation and management of software
# Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/up2date, /usr/bin/yum

## Services
# Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig

## Updating the locate database
# Cmnd_Alias LOCATE = /usr/bin/updatedb

## Storage
# Cmnd_Alias STORAGE = /sbin/fdisk, /sbin/sfdisk, /sbin/parted, /sbin/partprobe, /bin/mount, /bin/umount

## Delegating permissions
# Cmnd_Alias DELEGATING = /usr/sbin/visudo, /bin/chown, /bin/chmod, /bin/chgrp 

## Processes
# Cmnd_Alias PROCESSES = /bin/nice, /bin/kill, /usr/bin/kill, /usr/bin/killall

## Drivers
# Cmnd_Alias DRIVERS = /sbin/modprobe

# Defaults specification

#
# Refuse to run if unable to disable echo on the tty.
#
Defaults   !visiblepw

Defaults    env_reset
Defaults    env_keep =  "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS"
Defaults    env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
Defaults    env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
Defaults    env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
Defaults    env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"


Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

## Next comes the main part: which users can run what software on 
## which machines (the sudoers file can be shared between multiple
## systems).
## Syntax:
##
##      user    MACHINE=COMMANDS
##
## The COMMANDS section may have other options added to it.
##
## Allow root to run any commands anywhere 
root    ALL=(ALL)       ALL

## Allows members of the 'sys' group to run networking, software, 
## service management apps and more.
# %sys ALL = NETWORKING, SOFTWARE, SERVICES, STORAGE, DELEGATING, PROCESSES, LOCATE, DRIVERS

## Allows people in group wheel to run all commands
%wheel  ALL=(ALL)       ALL

## Same thing without a password
# %wheel        ALL=(ALL)       NOPASSWD: ALL

## Allows members of the users group to mount and unmount the 
## cdrom as root
# %users  ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom

## Allows members of the users group to shutdown this system
# %users  localhost=/sbin/shutdown -h now

## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment)
#includedir /etc/sudoers.d

################################################################################
# Added by David Both, 11/04/2017 to provide limited access to myprog          #
################################################################################
#
AUDIO   guest1=/usr/local/bin/myprog

带有粗体修改的默认 sudoers 文件。

用户别名

用户别名配置允许 root 用户将用户分类到别名组中,以便整个组可以访问某些 root 功能。这是我添加 User_Alias AUDIO = dboth, ruser 行的部分,它定义了别名 AUDIO 并将两个用户分配给该别名。

正如 sudoers 文件中所述,可以简单地使用 /etc/groups 文件中定义的组来代替别名。如果您已经在那里定义了一个满足您需求的组,例如“audio”,请在使用 sudoers 文件稍后部分分配给组的命令时,使用以 % 符号开头的该组名称,例如:%audio

命令别名

在 sudoers 文件的下方是命令别名部分。这些别名是相关命令的列表,例如网络命令或安装更新或新 RPM 包所需的命令。这些别名允许系统管理员轻松地允许访问命令组。

此部分中已经设置了许多别名,可以轻松地委派对特定类型命令的访问权限。

环境默认值

下一部分设置了一些默认环境变量。本节中最有趣的项目是 !visiblepw 行,它阻止 sudo 在用户环境设置为显示密码时运行。这是一个不应被覆盖的安全预防措施。

命令部分

命令部分是 sudoers 文件的主要部分。您需要做的所有事情都可以在没有所有别名的情况下完成,只需在此处添加足够的条目即可。别名只是让事情变得容易得多。

本节使用您已定义的别名来告诉 sudo 谁可以在哪些主机上做什么。一旦您理解本节中的语法,这些示例就一目了然了。让我们看一下我们在命令部分中找到的语法。

ruser		ALL=(ALL) ALL 

这表示 ruser 可以以任何用户身份在任何主机上运行任何程序。

这是我们用户 ruser 的通用条目。行中的第一个 ALL 表示此规则适用于所有主机。第二个 ALL 允许 ruser 以任何其他用户身份运行命令。默认情况下,命令以 root 用户身份运行,但 ruser 可以在 sudo 命令行上指定程序以任何其他用户身份运行。最后的 ALL 表示 ruser 可以不受限制地运行所有命令。这将有效地使 ruser 成为 root 用户。

请注意,root 用户有一个条目,如下所示。这允许 root 用户对所有主机上的所有命令具有全方位访问权限。

root	ALL=(ALL) ALL 

这表示 root 用户可以以任何用户身份在任何主机上运行任何程序。

为了尝试这一点,我注释掉了该行,并以 root 用户身份尝试在没有 sudo 的情况下运行 chown。这确实有效——这让我很惊讶。然后我使用了 sudo chown,结果失败并显示消息“Root 不在 sudoers 文件中。此事件将被报告。” 这意味着 root 用户可以以 root 用户身份运行所有内容,但在使用 sudo 命令时无法运行任何内容。这将阻止 root 用户通过 sudo 命令以其他用户身份运行命令,但 root 用户有很多方法可以绕过该限制。

下面的代码是我添加的用于控制对 myprog 的访问权限的代码。它指定 sudoers 文件顶部附近定义的 AUDIO 组中的用户只能访问一台主机 guest1 上的一个程序 myprog。

AUDIO   guest1=/usr/local/bin/myprog

允许 AUDIO 组中的用户访问主机 guest1 上的 myprog。

请注意,上面行的语法仅指定允许此访问的主机和程序。它没有指定用户可以以任何其他用户身份运行程序。

绕过密码

您还可以使用 NOPASSWORD 允许 AUDIO 组中指定的用户运行 myprog,而无需输入密码。方法如下:

AUDIO   guest1=NOPASSWORD : /usr/local/bin/myprog

允许 AUDIO 组中的用户访问主机 guest1 上的 myprog。

我没有为我的程序这样做,因为我认为具有 sudo 访问权限的用户必须停下来思考他们在做什么,这可能会对此有所帮助。我使用了我的小程序条目作为示例。

wheel

sudoers 文件命令部分中的 wheel 规范(如下所示)允许“wheel”组中的所有用户在任何主机上运行所有命令。“wheel”组在 /etc/group 文件中定义,用户必须添加到该组才能使其工作。组名称前面的 % 符号表示 sudo 应该在 /etc/group 文件中查找该组。

%wheel		ALL = (ALL) ALL 

允许“wheel”组(在 /etc/group 文件中定义)的所有成员在任何主机上运行所有命令。

这是将完全 root 访问权限委派给多个用户而无需提供 root 密码的好方法。只需将用户添加到 wheel 组即可授予他们完全 root 权限。它还提供了一种通过 sudo 创建的日志条目来监控其活动的方法。某些发行版(例如 Ubuntu)将用户的 ID 添加到 /etc/group 中的 wheel 组,这使他们可以使用 sudo 命令来执行所有特权命令。

最终想法

我在这里使用 sudo 的目标非常有限——为一两个用户提供对单个命令的访问权限。我用两行代码完成了这项工作(如果您忽略我自己的注释)。将执行某些任务的权限委派给没有 root 访问权限的用户很简单,并且可以为您(作为系统管理员)节省大量时间。它还会生成日志条目,这些条目可以帮助检测问题。

sudoers 文件为配置提供了大量功能和选项。查看 sudo 和 sudoers 的 man 文件以获取详细信息。

David Both
David Both 是开源软件和 GNU/Linux 的倡导者、培训师、作家和演讲者。自 1996 年以来,他一直从事 Linux 和开源软件工作,自 1969 年以来一直从事计算机工作。他是“系统管理员 Linux 哲学”的坚定支持者和传播者。

3 条评论

好文章。关于 NOPASSWORD 的一个补充说明,如果您给用户任何命令的 NOPASSWORD 选项,那么他们(或任何已破坏其帐户的人)都可以运行“sudo -l”来查找他们可以使用 sudo 运行的所有命令,而无需知道用户的密码。这在您的情况下是一个现实的场景,即用户不是很偏执/在社交环境中信任太多人。

您如何应对在您管理的所有不同机器上获得相同设置?对于所有这些容器化服务器来说,这很困难 - 由于数量庞大,管理起来并不总是容易。

1. 我们使用 ansible 来分发这样的配置
2. 对于我们的用例,我们更喜欢 drop-in 文件 (sudoers.d) 而不是更改 /etc/sudoers (这是一个来自 SO 的很好的对比答案:https://unix.stackexchange.com/a/375435/34589)

回复 ,作者:OneEye

知识共享许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.