unix/linux,sudo,其基本属性、语法、操作、api

现在我们要深入到sudo的“微观结构”了——它的属性、语法、操作以及是否有传统意义上的“API”。这就像我们从宏观的宇宙现象深入到基本粒子的相互作用一样,充满了探索的乐趣!

一、 sudo 的基本属性 (Fundamental Attributes)

这些属性是sudo作为一款软件和系统工具的核心特征:

可执行文件 (Executable)

sudo本身是一个编译后的二进制可执行文件,通常位于/usr/bin/sudo/bin/sudo

SetUID Root 程序 (Set User ID Root Program)

关键属性sudo程序文件通常设置了SetUID位,并且其所有者是root用户。

ls -l $(which sudo)
# 输出可能类似:-rwsr-xr-x 1 root root 157000 Jan 1 2023 /usr/bin/sudo
# 注意那个 's' 位,它替代了所有者的 'x' 位,表示SetUID

含义:当任何用户执行一个设置了SetUID位且所有者为root的程序时,该程序在执行期间会以root用户的权限运行。这是sudo能够提升权限的根本机制。它先以root身份启动,然后根据/etc/sudoers的策略决定是否以及如何为用户执行后续命令。

配置文件驱动 (Configuration File Driven)

其行为完全由/etc/sudoers文件(以及/etc/sudoers.d/目录下的片段文件)中的策略定义。

日志记录能力 (Logging Capability)

通过syslog(或系统配置的其他日志机制)记录所有授权尝试和执行结果。

用户认证机制 (User Authentication Mechanism)

依赖PAM (Pluggable Authentication Modules) 或系统自身的认证方式来验证发起用户的密码。

有状态 (Stateful – regarding timestamp)

sudo会在成功验证用户密码后,在一段时间内(timestamp_timeout)记住这个验证状态,允许用户在此期间无需重复输入密码即可再次使用sudo。这个状态信息通常存储在/var/run/sudo/ts/或类似目录下,以用户名为文件名。

二、 sudoers 文件的语法 (Syntax of /etc/sudoers)

/etc/sudoers的语法是sudo功能的核心,虽然初看复杂,但其设计是为了提供极大的灵活性和精确性。记住,始终使用visudo编辑此文件!

基本规则格式:

user   host = (runas_user:runas_group) command_list

user:

用户名 (e.g., john)
用户组 (e.g., %admin,以%开头)
用户别名 (User_Alias, 在文件中预定义)
ALL (所有用户)

host:

主机名 (e.g., server1, localhost)
IP地址
主机别名 (Host_Alias, 在文件中预定义)
ALL (所有主机)

=: 分隔符。
(runas_user:runas_group):

runas_user: 命令将以哪个用户身份运行 (e.g., root, apache, ALL)。如果省略,默认为root
runas_group: 命令将以哪个用户组身份运行 (e.g., wheel, www-data)。此项可选。
如果两者都省略,括号也可以省略,默认为(root).
(ALL:ALL)表示可以作为任何用户和任何组运行。

command_list:

一个或多个逗号分隔的命令。
命令的绝对路径 (e.g., /usr/bin/apt, /sbin/reboot)。强烈推荐使用绝对路径以增强安全性。
命令别名 (Cmnd_Alias, 在文件中预定义)。
ALL (所有命令)。
可以带参数,但需要小心处理参数的安全性。
可以有否定形式,以!开头,表示禁止执行某命令 (e.g., !/usr/bin/su)。

别名 (Aliases)

用于简化和组织配置。有四种类型的别名:

User_Alias USER_ALIAS_NAME = user1, %group1, user2
Host_Alias HOST_ALIAS_NAME = host1, host2, 192.168.1.0/24
Runas_Alias RUNAS_ALIAS_NAME = user_a, user_b
Cmnd_Alias CMND_ALIAS_NAME = /usr/bin/foo, /usr/sbin/bar

别名必须在使用前定义。

标签 (Tags)

标签用于修改规则的行为,紧跟在command_list中的命令之后(或应用于整个规则)。
NOPASSWD:: 允许用户无需输入密码即可执行该命令。

john ALL = NOPASSWD: /usr/local/bin/backup_script.sh

PASSWD:: (默认行为) 执行命令前需要输入密码。
NOEXEC:: 防止通过该命令执行其他程序(例如,在shell脚本中使用sudo some_script.sh时,防止脚本内部再执行其他命令)。这通常用于限制shell的权限。
SETENV: / NOSETENV:: 控制是否允许用户通过-E选项或Defaults env_keep来保留或设置环境变量。
LOG_INPUT / LOG_OUTPUT: 用于I/O日志记录,记录命令的输入和/或输出。
MAILWARN: 当用户尝试执行一个他们没有权限的sudo命令时,发送邮件警告。

Defaults 指令:

用于为特定用户、主机或全局设置默认选项。
格式: Defaults[:user_list] setting=value, another_setting

Defaults targettype:targetlist option, option, ...

常用Defaults选项:

env_reset: (默认开启) 重置环境变量为一个最小安全集。
env_keep += "VAR1 VAR2": 保留特定的环境变量。
secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin": 定义sudo执行命令时的安全PATH
timestamp_timeout=15: 密码缓存超时时间(分钟)。设为0则每次都需要密码,设为-1则永不超时(极不推荐)。
logfile=/var/log/sudo.log: 指定sudo日志文件(通常由syslog处理,但也可直接指定)。
insults: 一个有趣的选项,当用户输错密码时显示侮辱性信息(用于娱乐,不建议在生产环境使用)。

注释: 以#开头的行是注释。

包含目录:

#include /etc/sudoers.d
#includedir /etc/sudoers.d (更推荐,会自动包含该目录下所有不含.或以~结尾的文件)
这允许将配置拆分成多个小文件,便于管理(例如,每个应用或用户组一个配置文件)。

三、 sudo 的操作 (Operations / Command-Line Usage)

sudo命令本身有很多选项来控制其行为:

基本用法:

sudo <command> [arguments...]

以目标用户(通常是root)身份执行<command>

常用选项:

-u <user> or --user=<user>: 以指定的用户身份执行命令,而不是默认的root

sudo -u apache_user /usr/sbin/httpd -k restart

-g <group> or --group=<group>: 以指定的用户组身份执行命令。
-i or --login: 以目标用户的登录shell方式执行命令。这意味着会加载目标用户的完整环境(.bashrc, .profile等),并且当前目录会切换到目标用户的主目录。类似于su - <user>

sudo -i
sudo -i -u otheruser

-s or --shell: 执行由SHELL环境变量指定的shell,或者目标用户的默认shell。命令可以从标准输入读取。

-k or --reset-timestamp: 强制sudo在下次执行时要求输入密码,即使密码缓存尚未过期。使当前的密码时间戳失效。

-K or --remove-timestamp: 与-k类似,但彻底移除时间戳文件。

-v or --validate: 验证用户当前的sudo权限并更新密码时间戳,但不执行任何命令。如果密码已过期,会提示输入密码。

-l or --list: 列出当前用户可以执行的命令(以及被禁止的命令)。如果指定了其他用户 (sudo -l -U otheruser),则列出该用户的权限。

-E or --preserve-env: 保留当前用户的环境变量传递给被执行的命令。需谨慎使用,因为某些环境变量可能不安全。sudoers中的env_resetenv_keep会影响此选项的行为。

-e or sudoedit: 安全地编辑文件。等同于sudoedit <file>

sudo -e /etc/hosts
sudoedit /etc/hosts

-A or --askpass: 使用图形界面的密码提示程序(如果配置了SUDO_ASKPASS环境变量或sudo.conf中的askpass选项)。

-b or --background: 在后台运行命令。

-p <prompt> or --prompt=<prompt>: 自定义密码提示符。

-S or --stdin: 从标准输入读取密码,而不是从终端。

四、 sudo 的 “API” (Application Programming Interface)

严格来说,sudo本身是一个命令行工具,它没有提供传统意义上的C库或Python模块等形式的编程API让其他应用程序直接链接和调用其内部函数来实现权限提升。

然而,我们可以从几个层面来理解其“接口”:

命令行接口 (Command-Line Interface – CLI)

这是sudo最主要的接口。其他脚本或程序可以通过执行sudo命令(例如,使用subprocess模块在Python中,或system()函数在C中)来间接利用sudo的功能。这是最常见的“集成”方式。

/etc/sudoers 文件作为配置接口:

sudoers文件本身可以被视为sudo的“策略配置接口”。管理员通过编写这个文件来定义sudo的行为。

PAM (Pluggable Authentication Modules) 集成:

sudo通过PAM进行用户认证。这意味着PAM模块可以影响sudo的认证过程。从这个角度看,PAM为sudo提供了一个认证服务的接口。

插件API (Sudo Plugin API)

这可能是最接近传统API的概念了。 sudo从1.8版本开始引入了插件架构。这允许第三方开发者编写动态链接库(.so文件)来扩展sudo的功能。
类型

策略插件 (Policy Plugins):可以替代或增强/etc/sudoers的功能,决定用户是否有权限执行命令。例如,可以编写一个从LDAP或数据库中读取授权策略的插件。
I/O 日志插件 (I/O Logging Plugins):用于记录命令的输入、输出和错误流。
审批插件 (Approval Plugins):可以在执行命令前引入一个审批流程。
审计插件 (Audit Plugins):可以自定义审计信息的格式和目的地。

接口sudo提供了一组C头文件 (sudo_plugin.h) 和定义的函数入口点,插件开发者需要实现这些接口函数。
配置:插件在sudo.conf文件(通常是/etc/sudo.conf)中加载和配置。
示例:官方sudo源码中就包含了一个示例插件。一些第三方工具,如用于双因素认证的插件(如pam_duo, pam_google_authenticatorsudo结合),虽然不直接是sudo插件,但通过PAM间接影响sudo;而专门的sudo插件则可以直接与sudo核心交互。

日志作为输出接口:

sudo产生的日志可以被其他系统(如SIEM)消费和分析,这也可以看作是一种单向的数据输出接口。

所以,总结一下:

直接的编程库API(像libcurl那样的)是没有的。
最主要的交互方式是CLI。
sudoers是其核心配置接口。
sudo插件API是其最接近可编程扩展接口的形式,允许深度定制其行为。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容