6个版本 (1个稳定版)

1.0.0 2020年3月26日
0.11.1 2018年6月8日
0.9.2 2018年5月18日

#375 in 命令行工具

Apache-2.0

120KB
2K SLoC

sudo_pair

Build Status Latest Version License

sudo_pair 是一个 sudo 插件,要求另一个人类用户批准和监控特权 sudo 会话。

a demonstrated sudo_pair session

关于

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标志不同。 whereas gids_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 rootsudo -u nobodysudo -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包组成

依赖项

鉴于此项目的安全性敏感性质,目标是有最小化的一组依赖项。目前,这些依赖项包括:

贡献

欢迎贡献!此项目应相对较小(插件本身约500行代码,围绕编写插件的包装约1000行代码)且足够文档化,以便其他人可以无困难地参与。

选择一个待办事项并开始吧!

错误

请将非安全性问题报告到GitHub追踪器。安全问题由Square的错误赏金计划处理。

许可协议

sudo_pair根据Apache License(版本2.0)分发。

有关详细信息,请参阅LICENSE-APACHE

依赖项

~2.6–5.5MB
~110K SLoC