一、什么是 doas
doas(全称为 dedicated openbsd application subexecutor)是一个类 Unix 系统中的权限提升工具,由 OpenBSD 开发者 Ted Unangst 于 2015 年创建,随 OpenBSD 5.8 版本首次发布。它的设计目标是替代历史悠久但日益臃肿的 sudo,在保留核心功能的前提下,以极简的代码和配置实现同样的权限委托能力。
与 sudo 相比,doas 的核心优势在于简洁性和安全性。sudo 的代码库超过 20 万行 C 代码,包含插件架构、LDAP 集成、主机感知配置等大量高级功能;而 doas 的核心代码仅约 500 行,专注于“让普通用户以另一个用户身份运行命令”这一单一任务。 这种“做减法”的设计哲学直接来源于 OpenBSD 项目一贯的安全理念:更少的代码意味着更少的 bug,更小的攻击面意味着更高的安全性。
doas 与 sudo 架构对比
flowchart TB
subgraph SUDO["sudo 架构"]
S1["sudoers 文件<br/>复杂语法"]
S2["插件系统<br/>LDAP/SSSD"]
S3["日志审计<br/>visudo 验证"]
S4["代码量: ~200,000+ 行"]
S1 --> S2 --> S3 --> S4
end
subgraph DOAS["doas 架构"]
D1["doas.conf<br/>简洁规则"]
D2["无插件<br/>纯 C 实现"]
D3["syslog 日志<br/>-C 语法检查"]
D4["代码量: ~500 行"]
D1 --> D2 --> D3 --> D4
end
SUDO -->|"功能重叠 95%"| DOAS
DOAS -->|"攻击面更小"| SUDO
二、诞生背景与设计哲学
2.1 为什么需要 doas
Ted Unangst 创建 doas 的动机源于对 sudo 的复杂性和默认配置的不满。sudo 的配置文件 sudoers 语法复杂,即便是经验丰富的系统管理员也时常需要查阅文档;而 sudo 的默认配置在某些场景下过于宽松,增加了潜在的安全风险。
更重要的是,sudo 庞大的代码库使其成为安全审计的噩梦。2021 年曝光的 Baron Samedit 漏洞(CVE-2021-3156) 就是一个典型案例:这是一个存在于 sudo 中的堆缓冲区溢出漏洞,影响从 1.8.2 到 1.9.5p1 的几乎所有主流版本,攻击者无需任何认证即可将权限提升至 root。 而 doas 由于代码量极小、功能精简,天然避开了这类复杂漏洞。
2.2 OpenBSD 的安全哲学
doas 的设计深受 OpenBSD 安全哲学影响:
- 默认拒绝(Deny by Default):空配置文件意味着所有请求都被拒绝
- 代码简洁(Less Code = Less Bugs):~500 行 vs ~200,000+ 行
- 可审计性(Auditable):任何人都能在几小时内通读全部源码
- 最小权限原则(Principle of Least Privilege):精确到命令和参数的权限控制
graph TB
subgraph PHIL["OpenBSD 安全哲学"]
P1["默认拒绝<br/>Deny by Default"]
P2["代码简洁<br/>Less Code = Less Bugs"]
P3["可审计性<br/>Auditable"]
P4["最小权限<br/>Principle of Least Privilege"]
end
subgraph IMPL["doas 实现"]
I1["空配置 = 全部拒绝"]
I2["~500 行 C 代码"]
I3["无插件/无 LDAP"]
I4["精确命令匹配<br/>cmd + args"]
end
PHIL --> IMPL
I2 -->|对比 sudo ~200,000+ 行| S["更小的攻击面"]
S -->|CVE-2021-3156<br/>Baron Samedit| V["sudo 历史漏洞<br/>doas 不受影响"]
三、安装与部署
3.1 OpenBSD(原生内置)
OpenBSD 5.8 及更高版本已预装 doas,无需额外安装。系统安装后,只需配置 /etc/doas.conf 即可使用。
3.2 Linux 发行版
在 Linux 上,doas 通常以 OpenDoas(由 Duncaen 维护的移植版本)的形式提供:
Debian/Ubuntu:
sudo apt update
sudo apt install doas
Arch Linux:
sudo pacman -S opendoas
Fedora:
sudo dnf install doas
NixOS:
security.doas.enable = true;
Alpine Linux:
apk add doas
从源码编译(适用于所有平台):
git clone https://github.com/Duncaen/OpenDoas.git
cd OpenDoas
make
sudo make install
3.3 FreeBSD
pkg install doas
# 或从 Ports
cd /usr/ports/security/doas && make install clean
3.4 macOS
macOS 上可通过 MacPorts 安装,或从源码手动编译:
sudo port install opendoas
graph LR
O["OpenBSD 5.8+<br/>原生内置"] --> P["OpenDoas<br/>Linux/macOS 移植"]
O --> F["FreeBSD Ports<br/>security/doas"]
P --> A["Arch Linux<br/>pacman -S opendoas"]
P --> D["Debian/Ubuntu<br/>apt install doas"]
P --> R["Fedora/RHEL<br/>dnf install doas"]
P --> N["NixOS<br/>security.doas"]
P --> L["Alpine Linux<br/>apk add doas"]
F --> B["Ansible<br/>become_method: doas"]
P --> B
style O fill:#e1f5fe
style P fill:#fff3e0
四、配置文件详解
4.1 基本语法
doas 的配置文件位于 /etc/doas.conf(Linux 上部分发行版也支持 /usr/local/etc/doas.conf),其语法灵感来源于 OpenBSD 的包过滤配置 pf.conf,极其直观。
通用语法格式:
permit|deny [options] identity [as target] [cmd command [args ...]]
permit/deny:允许或拒绝options:可选修饰符identity:用户名或:组名(组名前加冒号)as target:目标用户(默认 root)cmd command:限制可执行的命令args ...:限制命令参数(必须完全匹配)
4.2 常用配置选项
| 选项 | 说明 |
|---|---|
nopass |
无需密码直接执行 |
persist |
认证成功后缓存密码(一段时间内免密) |
keepenv |
保留当前环境变量 |
setenv {VAR=value ...} |
设置/覆盖特定环境变量 |
nolog |
不记录日志 |
cmd |
限制只允许执行的命令 |
args |
限制命令参数 |
4.3 配置示例
示例 1:允许 wheel 组成员以 root 身份执行任何命令(最常用)
permit persist keepenv :wheel
示例 2:允许特定用户免密执行
permit nopass alice as root
示例 3:允许组内用户执行特定命令(最小权限原则)
# 允许 wheel 组用户免密重启 nginx 服务
permit nopass :wheel as root cmd /usr/sbin/service args nginx restart
# 允许 plugdev 组用户运行 smartctl
permit nopass :plugdev as root cmd /usr/bin/smartctl
示例 4:允许用户以其他非 root 用户身份执行
permit nopass bob as postgres
示例 5:保留环境变量(适合图形化程序)
permit keepenv nopass alice
示例 6:设置特定 PATH
permit setenv {PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin} :wheel
4.4 配置文件权限
配置文件必须属于 root,且权限严格限制:
chown root:root /etc/doas.conf
chmod 0400 /etc/doas.conf
4.5 语法检查
doas -C /etc/doas.conf && echo "config ok" || echo "config error"
也可以测试特定命令的权限:
doas -C /etc/doas.conf cat
# 输出 permit 或 deny
flowchart TD
A["doas 请求到达"] --> B{"读取 doas.conf<br/>逐行匹配"}
B --> C{"规则类型?"}
C -->|permit| D{"选项检查"}
C -->|deny| E["拒绝执行"]
D --> F{"身份匹配?"}
F -->|用户/组匹配| G{"目标用户?"}
F -->|不匹配| H["继续下一规则"]
H --> B
G -->|as root| I{"命令限制?"}
G -->|as 其他用户| I
I -->|cmd 指定| J{"参数匹配?"}
I -->|无限制| K["允许执行"]
J -->|args 匹配| K
J -->|不匹配| E
K --> L{"密码选项?"}
L -->|nopass| M["直接执行"]
L -->|persist| N["缓存认证"]
L -->|默认| O["要求密码"]
O --> P["验证通过?"]
P -->|是| M
P -->|否| E
五、工作流程
sequenceDiagram
participant U as 普通用户
participant D as doas
participant C as doas.conf
participant T as 目标用户(root)
U->>D: doas command
D->>C: 读取配置规则
C-->>D: 匹配 permit/deny
alt 规则允许
D->>D: 验证密码(可选)
D->>D: 设置环境变量
D->>T: 切换 UID/GID
T-->>U: 执行命令并返回结果
else 规则拒绝
D-->>U: doas: Operation not permitted
end
六、doas vs sudo:详细对比
| 特性 | doas | sudo |
|---|---|---|
| 代码量 | ~500 行(OpenBSD 原生) | ~200,000+ 行 |
| 配置文件 | /etc/doas.conf,语法简洁 |
/etc/sudoers,语法复杂 |
| 配置验证 | doas -C |
visudo |
| 插件系统 | 无 | 有(LDAP、SSSD 等) |
| 主机感知配置 | 无 | 有 |
| 密码缓存 | persist 选项(OpenBSD 原生/Linux 移植版) |
默认支持 |
| 日志 | syslog | 自定义日志 + syslog |
| 命令参数限制 | cmd + args,精确匹配 |
更灵活但复杂 |
| 环境变量控制 | keepenv / setenv |
丰富的环境变量配置 |
| 适用场景 | 个人桌面、小型服务器 | 大型企业基础设施 |
6.1 何时选择 doas?
- 个人桌面/笔记本:配置简单,日常
doas pacman -Syu足够 - OpenBSD 系统:原生支持,无需额外安装
- 安全敏感环境:更小的攻击面,代码可审计
- 追求简洁的运维:不想记忆
sudoers的复杂语法
6.2 何时仍需 sudo?
- 需要 LDAP/AD 集成 的企业环境
- 多主机共享配置 的集群环境
- 需要复杂审计和策略 的合规场景
- 团队已熟悉 sudo 且迁移成本过高
七、注意事项与最佳实践
7.1 nopass 的安全风险
nopass 选项虽然方便,但如果用户账户被攻破,攻击者可直接获得 root 权限。建议仅在受信任的单用户桌面环境使用,多用户或服务器环境应要求密码认证。
7.2 cmd + args 的精确匹配陷阱
doas 要求命令和参数完全匹配。例如:
# 配置
permit nopass :wheel as root cmd /usr/sbin/service args nginx onestart
# 以下执行会失败
$ doas service nginx onestart
doas: Operation not permitted # 因为路径不匹配!
# 正确执行
$ doas /usr/sbin/service nginx onestart
7.3 OpenDoas 的已知问题
Linux 上的 OpenDoas 移植版存在一个与 TTY hijacking(TIOCSTI) 相关的未修复安全漏洞(CVE-2023-28339),该问题在 OpenBSD 原生版本中不存在。 如果你对此类攻击面敏感,建议:
- 在 Linux 内核中禁用 TIOCSTI
- 或考虑使用
sudo-rs等替代方案
7.4 从 sudo 平滑迁移
可以在安装 doas 后创建一个别名,让肌肉记忆逐渐过渡:
# ~/.bashrc 或 ~/.zshrc
alias sudo='doas'
八、生态系统与工具集成
8.1 Ansible 支持
Ansible 原生支持 doas 作为 become_method:
# ansible.cfg
[privilege_escalation]
become = true
become_method = doas
become_user = root
8.2 相关工具
- doasedit:一个包装脚本,允许用
doas编辑需要 root 权限的文件 - polkit-fakesudo:用 polkit 模拟 sudo 行为的包装器
九、总结
doas 是 OpenBSD 哲学在权限管理领域的完美体现——用 5% 的代码实现 95% 的功能。它不是 sudo 的完全替代品,但对于绝大多数个人用户和小型系统而言,doas 提供了恰到好处的功能与无与伦比的安全性。
正如 Ted Unangst 所说,他的目标是让工具“更简单,无论从用户角度还是开发者角度”。 在一个安全漏洞层出不穷的时代,doas 证明了“少即是多”的设计原则依然有效。如果你正在管理 OpenBSD 系统,或者只是厌倦了 sudoers 的复杂性,不妨给 doas 一个机会。
参考资源
- OpenBSD doas 官方手册
- OpenBSD doas.conf 手册
- OpenDoas GitHub 仓库
- Jesse Smith 的 doas 移植
- ArchWiki - Doas
- FreeBSD Ports - security/doas
- Ted Unangst 的博客 - doas 设计思路
原文 https://blog.csdn.net/2301_79518550/article/details/146442208