6个版本 (1个稳定版)
1.0.0 | 2020年3月26日 |
---|---|
0.11.1 | 2018年6月8日 |
0.9.2 | 2018年5月18日 |
#375 in 命令行工具
120KB
2K SLoC
sudo_pair
sudo_pair
是一个 sudo 插件,要求另一个人类用户批准和监控特权 sudo 会话。
关于
sudo
被工程师们每天用来以特权用户身份运行命令。但在一些敏感系统中,您确实想确保没有个人可以完全独立行动。在 Square,这包括管理我们内部访问控制系统的应用程序、存储会计账簿,甚至处理真钱。此插件允许我们确保在这些系统中,没有任何用户可以完全根据自己的权限行事。
此插件及其组件仍在预发布阶段,因为我们想在正式发布 1.0 之前从开源社区获取反馈。
安装
警告:sudo 配置错误可能会使您无法访问您的机器。请在可丢弃的环境中测试。
目前,sudo_pair
必须从源代码编译。它是一个标准的 Rust 项目,以下内容足以在 Rust 的任何最新版本上构建它
git clone https://github.com/square/sudo_pair.git
cd sudo_pair
cargo build --release
一旦构建完成,插件本身需要安装在一个 sudo 可以找到的位置。通常是在 /usr/libexec/sudo
(在 macOS 主机上为 /usr/local/libexec/sudo
)。必须安装适当的批准脚本到 PATH
。必须为 sudo_pair
创建一个目录,以便它管理用于插件和客户端之间通信的套接字。最后,sudo 必须配置为加载和使用此插件。
# WARNING: these files may not be set up in a way that is suitable
# for your system. Proceed only on a throwaway host.
# install the plugin shared library
install -o root -g root -m 0644 ./target/release/libsudopair.dylib /usr/libexec/sudo
# create a socket directory
install -o root -g root -m 0644 -d /var/run/sudo_pair
# install the approval script; as currently configured, it denies access
# to users approving their own sudo session and may lock you out
install -o root -g root -m 0755 ./sample/bin/sudo_approve /usr/bin/sudo_approve
# your `/etc/sudo.conf` may already have entries necessary for sudo to
# function correctly; if this is the case, the two files will need to be
# merged
install -o root -g root -m 0644 ./sample/etc/sudo.conf /etc/sudo.conf
# if these prompts don't work for you, they're configurable via a simple
# templating language explained later in the README
install -o root -g root -m 0644 ./sample/etc/sudo.prompt.user /etc/sudo.prompt.user
install -o root -g root -m 0644 ./sample/etc/sudo.prompt.pair /etc/sudo.prompt.pair
这仅将插件文件放置在预期位置。除非您遵循下面的 配置 步骤,否则插件尚未启用。
配置
/etc/sudoers
默认情况下,/etc/sudoers
不会告诉日志插件为任何命令记录输出。您需要通过以下方式启用此功能:告诉sudo
为所有命令启用日志记录(并排除任何希望绕过的命令),或者选择将个别命令加入日志记录。
示例(默认记录,排除个别命令)
Defaults log_output
%wheel ALL = (ALL) NOLOG_OUTPUT: /bin/cat, /bin/ls
示例(加入个别命令)
%wheel ALL = (ALL) LOG_OUTPUT: /usr/bin/visudo
/etc/sudo.conf
插件可以提供多个选项来修改其行为。这些选项是通过在/etc/sudo.conf
中的Plugin
行末添加来提供给插件的。
示例
Plugin sudo_pair sudo_pair.so socket_dir=/var/tmp/sudo_pair gids_exempted=42,109
完整的选项列表如下
-
binary_path
(默认:/usr/bin/sudo_approve
)这是批准二进制文件的位置。批准命令本身需要在目标用户或组的权限下运行,这通过sudo实现,因此它必须被免除自己的配对批准要求。
-
user_prompt_path
(默认:/etc/sudo_pair.prompt.user
)这是向调用sudo的用户显示提示模板的位置;如果在此位置找不到模板,将打印一个极其简化的默认模板。有关详细信息,请参阅提示部分。
-
pair_prompt_path
(默认:/etc/sudo_pair.prompt.pair
)这是向被要求批准sudo会话的用户显示提示模板的位置;如果在此位置找不到模板,将打印一个极其简化的默认模板。有关详细信息,请参阅提示部分。
-
socket_dir
(默认:/var/run/sudo_pair
)这是此插件将存储待批准会话套接字的位置。此目录必须由root拥有,并且只能由root写入,否则插件将中止。
-
gids_enforced
(默认:0
)这是一个以逗号分隔的gid列表,sudo_pair将控制对这些组的访问。如果用户sudo到一个属于这些组的用户,他们将被要求有一个配对批准他们的会话。
-
gids_exempted
(默认:无)这是一个以逗号分隔的gid列表,其用户将免除sudo_pair的要求。请注意,这与
gids_enforced
标志不同。 whereasgids_enforced
控制对组的访问到,gids_exempted
免除sudo从组的要求。例如,此设置可以用来确保值班系统管理员可以在无需找到配对的情况下响应故障。请注意,root始终是免除的。
提示
此插件允许您配置向被要求找到配对的用户和被要求批准其他用户的sudo
会话的用户显示的提示。如果未配置提示(或无法在文件系统中找到),将提供极其简化的默认提示。
提示文件的包含内容是应该打印到用户终端的原始字节。这允许使用终端处理ANSI转义代码进行着色、调整终端大小和设置窗口标题等功能,所有这些都在提供的示例提示中被(滥用)。
这些提示也 实现了 一个简单的 %
转义的模板语言。任何以 %
字符开头的已知指令将被替换为展开,而其他任何内容则被视为字面量(例如,%%
是字面量的 %
,而 %a
是字面量的 a
)。
可用的展开
%b
:二进制审批 _b_inary 的名称%B
:二进制 _B_inary 的完整路径%C
:被调用sudo
的完整 _C_ommand(尽可能重建)%d
:在sudo
下运行的命令的 cw_d_%h
:执行sudo
的机器的 _h_ostname%H
:调用用户终端的 _H_eight,以行为单位%g
:调用sudo
的用户的真实 _g_id%p
:此sudo
进程的 _p_id%u
:调用sudo
的用户的真实 _u_id%U
:运行sudo
的用户的 _U_sername%W
:调用用户终端的 _W_idth,以列为单位
审批脚本
提供的 审批脚本 只是一个小(但完整)的示例。尽可能多的功能已被移入插件中,但有一个(重要,暂时)例外:当前,脚本必须验证审批 sudo
会话的用户不是请求会话的用户。
除此之外,“协议”所需做的只是
- 连接到套接字(作为被
sudo
的用户或组) - 将套接字的输入和输出连接到用户的 STDIN 和 STDOUT
- 发送一个
y
进行批准,或发送其他任何内容以拒绝 - 关闭套接字以终止会话
实际上,您可以使用 socat
完成这些操作
socat STDIO /path/to/socket
与此项目一起提供的脚本并没有多少不同。它执行了一些额外的功能(如果需要,隐式 sudo
,关闭终端回显,禁用 Ctrl-C,并在 Ctrl-D 上终止会话),但并不多。Ctrl-C 被禁用,这样用户就不会本能地使用 Ctrl-C 杀死这个终端。
局限性
在 sudo_pair
下的会话无法通过管道传输。
允许管道数据进入标准输入,据我所知,很可能会导致安全模型被完全绕过。命令通常可以在 stdin
上接受输入,并且没有合理的方式将此信息展示给双端。
安全模型
此插件允许用户使用sudo -u ${user}
成为用户或使用sudo -g ${group}
获得额外的组。
当用户这样做时,将创建一个由${user}
(或${group}
)所有并仅可写文件的套接字。为了连接到该套接字,审批者必须能够以该${user}
(或${group}
)的身份写入文件。换句话说,他们需要在密封舱的另一边。在实用意义上,这意味着审批者也需要能够以该用户或组的身份sudo
。
为此,插件免除了审批脚本需要成对出现的限制。示例审批脚本会自动检测您需要成为的用户或组,并隐式运行sudo -u ${user}
(或sudo -g ${group}
)。
具体示例,以下是在sudo -u root
、sudo -u nobody
和sudo -g sys
时打开的套接字。
drwxr-xr-x 3 root wheel 96 May 8 09:17 .
s-w------- 1 root wheel 0 May 8 09:16 1882.29664.sock # sudo -u root
s-w------- 1 nobody wheel 0 May 8 09:17 1882.29921.sock # sudo -u nobody
s----w---- 1 root sys 0 May 8 09:18 1882.29994.sock # sudo -g sys
唯一能够批准对用户或组sudo
会话的人也必须能够以该用户或组的身份sudo
。
由于POSIX文件系统权限模型的限制,用户可以sudo到一个新用户(并获得其组)或sudo到一个新组(保留当前用户),但不能同时进行。
项目布局
此项目由三个Rust包组成
sudo_plugin-sys
:对sudo_plugin(8)
接口的原始Rust FFI绑定sudo_plugin
:一组Rust结构和宏,用于简化插件的编写sudo_pair
:此插件的实现
依赖项
鉴于此项目的安全性敏感性质,目标是有最小化的一组依赖项。目前,这些依赖项包括:
- rust-lang/libc
- rust-lang-nursery/rust-bindgen
- rust-lang-nursery/failure
- rust-lang-nursery/error-chain(即将删除)
贡献
欢迎贡献!此项目应相对较小(插件本身约500行代码,围绕编写插件的包装约1000行代码)且足够文档化,以便其他人可以无困难地参与。
选择一个待办事项并开始吧!
错误
请将非安全性问题报告到GitHub追踪器。安全问题由Square的错误赏金计划处理。
许可协议
sudo_pair
根据Apache License(版本2.0)分发。
有关详细信息,请参阅LICENSE-APACHE。
依赖项
~2.6–5.5MB
~110K SLoC