使用手册
本文档是 Censorguard的系统使用手册,覆盖核心概念、策略编写、 运行时开关、进程纳管、策略热更新、观测与故障排查。构建与安装见 构建指南;DeepSeek Harness 集成见 DSH 插件指南。
1. 核心概念
作用域模型:策略引擎基于 eBPF LSM + 自建 PID 树。只有被纳管的进程及其 全部子孙才受策略约束,系统其它进程完全不受影响。fork 出的子进程自动继承 所属域;纳管发生在 exec 屏障上,子进程 exec 前即被拦截,无竞态窗口。
域与策略组:每个被纳管的进程属于一个域(domain),域绑定一个策略组 (group)。进程实际受 全局基线(rules)+ 所在组规则 叠加约束。策略编译为 inode/地址等内核可直接匹配的形式,写进双 bank(one active bank switch): 新策略全部写完后单次切换,失败 reload 不产生"部分新部分旧"的窗口。
fail-closed 语义:enable_* 开关关闭某维度时该维度放行(fail-open); 但策略拒绝永远即时生效。审计默认只记 DENY,ALLOW 需显式打开。
运行模型:
YAML -> Rust typed snapshot -> inactive policy bank
-> one active_bank switch
tgid -> domain/logical slot -> active bank inner maps
syscall -> LSM/tracepoint -> allow or -EPERM -> ringbuf audit2. 组件与二进制
| 二进制 | 角色 |
|---|---|
censorguardd | 守护进程:加载 eBPF、维护进程树域、执行策略(root) |
censorguardctl | 控制入口:策略发布、域绑定、进程纳管、运行时开关 |
censorguard-audit | 观测入口:订阅事件流(DENY/ALLOW) |
censorguard-grpc | 非特权 gRPC 适配器:127.0.0.1:50051 → ui.sock/events.sock,供 DSH 插件使用 |
censorguard-exec | 启动器:供外部宿主登记进程 |
daemon 暴露五条 Unix socket,各有角色 ACL(SO_PEERCRED 鉴权):
| socket | 默认路径 | 角色 | 用途 |
|---|---|---|---|
| ctl.sock | /run/censorguard/ctl.sock | Admin | root 级控制(reload/bind/apply) |
| events.sock | /run/censorguard/events.sock | Audit | 事件流订阅 |
| launch.sock | /run/censorguard/launch.sock | Launcher | 以域身份启动命令 |
| dsh.sock | /run/censorguard/dsh.sock | Dsh | DSH 自助 attach(普通用户) |
| ui.sock | /run/censorguard/ui.sock | Ui | DSH 委托面:白名单组策略读写、开关切换 |
daemon 从不监听网络端口;gRPC 适配器只绑 127.0.0.1。
3. 策略配置(一行式,唯一合法格式)
策略 YAML 只接受三个顶层键,旧格式字段(enable_file、policy_groups、 file_rules 等)一律被严格拒绝(报 unknown field):
rules: # 全局基线,对所有被纳管进程生效,可省略
- file deny+audit /etc/shadow
- exec deny /usr/bin/nc
groups: # 命名策略组,每组只有 rules,可省略
web:
rules:
- net deny 0.0.0.0/0
- net allow api.github.com:443
domains: # 域 → 组绑定,可省略;省略 group 表示仅受基线约束
- name: dsh-web
group: web3.1 规则语法
一行式:file|exec|net 动作 目标 [掩码]
以下示例展示的都是 rules: 列表内的单行写法(规则语法与所在位置无关): 同一个 rules: 列表既可以出现在顶层(全局基线),也可以出现在 groups.<name>.rules(组规则),行内语法完全一致。只写 rules: 一个键 的文件同样合法(如 config/base.yaml)。
- 动作:
allow、deny、allow+audit、deny+audit(+audit表示命中 ALLOW 也上报;DENY 永远上报)。 - file 掩码可选:
none(默认,全部操作)、ro、rw、noattr、[read,write,delete,rename,attr]。 - exec 目标可带参数前缀:
exec deny /usr/bin/git push只拦 push 子命令。 - net 支持 IPv4/IPv6 地址、CIDR、端口、域名(域名由 daemon 做 DNS 展开 与周期刷新)。
rules:
- file deny+audit /var/lib/censorguard [write,delete,rename]
- exec deny+audit /usr/bin/rm -rf /
- net deny 2001:db8::/32 # 裸 IPv6/CIDR 无端口
- net allow+audit [::1]:443 # 带端口必须 [IPv6/CIDR]:PORT
- net deny api.example.com:8443 # 域名规则,DNS 自动展开3.2 inode 陷阱
file/exec 规则在编译期解析为 inode。策略加载后重建目标文件会改变 inode,需 reload 策略才能重新命中。规则"不生效"时先用 policy-dump 确认规范化策略,再检查目标文件是否被重建过。
完整示例见 config/base.yaml、config/standard-dev.yaml、 config/high-priv.yaml、config/policy.dsh-default.yaml(DSH 默认组)。
4. 运行时开关(替代旧配置字段)
enable_file/enable_exec/enable_net(默认全开)与 audit_file/audit_exec/audit_net(默认全关)是运行时开关,不写在 配置文件里:
sudo censorguardctl set --audit-file on # 打开文件 ALLOW 审计
sudo censorguardctl set --enable-net off --audit-exec on # 可一次多个- 等价接口:RPC v2
set_switches;DSH WebUI 设置页(经 ui.sock 委托面)。 - ctl 设置需 root(SO_PEERCRED 鉴权)。
- 不持久化:daemon 重启恢复默认;reload 保持当前值。
- 任一
audit_*打开时,该类 ALLOW 事件全量上报;enable_*=off时对应 维度 fail-open(放行)。
5. 启动 daemon
5.1 systemd 方式(生产推荐)
sudo systemctl enable --now censorguardd.service
sudo systemctl status censorguardd # 日志出现 [READY] 即就绪unit 内置 --spawn-grpc:daemon 自动派生并守护 gRPC 适配器 (127.0.0.1:50051),DSH 插件无需额外配置即可连接。状态目录为 /var/lib/censorguard(策略 revision 快照,跨重启恢复)。
5.2 手动方式(测试/调试)
# socket 父目录必须属 root 且 group/other 不可写(/tmp 会被拒绝)
sudo install -d -m 0755 /run/agsec
sudo censorguardd \
--config /run/agsec/policy.yaml \
--bpf-object /usr/lib/censorguard/enforce.bpf.o \
--ctl-sock /run/agsec/ctl.sock \
--event-sock /run/agsec/events.sock常用参数:--duration N(N 秒后自动退出)、--state-dir DIR、 --socket-group NAME、--launch-sock PATH、--dsh-sock PATH、 --ui-sock PATH、--spawn-grpc/--grpc-bin/--grpc-listen(派生适配器)、 --check-config(只校验不加载)。socket 在 /run/censorguard 之外时 状态目录是临时的,退出自动清理。
6. 纳管进程
# 在域里启动命令(推荐,带执行屏障,无竞态)
sudo censorguardctl spawn --domain dsh-web -- curl https://example.com
# 纳管已在运行的进程(--seed 回填已有子孙)
sudo censorguardctl attach --pid 12345 --domain dsh-web --seedspawn 透明地以子进程退出码退出(子进程 exit 3 → ctl 退出码 3; 被策略拒绝 → 非零)。跨 UID attach 需要 root。
纳管后整棵进程树(fork 自动继承 + pending 降级层)都在 eBPF LSM 强制 之下,不经任何插件通道启动的子进程也逃不掉。
7. 策略热更新
# 整份替换(原子双 bank 切换,失败自动回滚)
sudo censorguardctl reload --file /path/to/policy-v2.yaml
# 组级热更新(组文档只有 rules 一个键)
printf 'rules:\n - exec deny /usr/bin/id\n' | \
sudo censorguardctl policy apply --name web --stdin
# 换绑 / 解绑(空组 = 仅受基线约束)
sudo censorguardctl bind dsh-web --group web
sudo censorguardctl bind dsh-web --group ''组级 apply 带 revision 乐观锁:传 --expected-revision N 与当前不符则 409 冲突。全量 reload 支持 SIGHUP(systemctl reload censorguardd)。 已应用策略以 revision 快照持久化在 /var/lib/censorguard/revisions/, daemon 重启自动恢复最新 revision。
8. 观测
sudo censorguard-audit launch --socket /run/censorguard/events.sock # 全量事件流
sudo censorguard-audit launch --socket /run/censorguard/events.sock --kind 2 # 只看 exec (1=file 2=exec 3=net 4=guard)
censorguardctl status # 开关/版本/bank/reload 状态
censorguardctl tree # 域进程树
censorguardctl policy-dump # 当前生效的规范化策略事件字段要点:每事件带单调 sequence(从 1 起)、daemon_boot_id(区分 daemon 重启)与 dropped_before(本订阅者累计丢失)。事件无持久化,是 实时观察窗。
一个动态链接程序可能产生多个 FILE ALLOW(动态加载器、libc、locale 和 配置文件的读取),这表示文件打开检查点,不表示执行了多个可执行文件; 只关心执行事件用 --kind 2 过滤。
9. 测试
make check # 静态检查(fmt/clippy/bash -n/工具语法)
make test # Rust 单元与编译器测试(不需要 root)
cd plugins/dsh-censorguard && pnpm test # DSH 插件测试(不需要 root)
sudo bash scripts/test/integration-basic.sh # 基础验收(14 用例,root + BPF LSM)
sudo make integration # 全量 30+ 场景(root + BPF LSM)集成测试要求内核启用 BPF LSM(cat /sys/kernel/security/lsm 含 bpf)。 integration-basic.sh 是门禁:全部隔离在临时目录,不碰 /run 与生产 state。场景覆盖:文件 read/write/delete/rename/chmod、link/symlink/mkdir/ rmdir/mknod、chown/xattr/ACL、预打开 fd、命令与参数级 exec、多域隔离、 execveat、IPv4/IPv6 与 DNS、reload/bind/SIGHUP/回滚、PID generation/ fork/draining/churn、事件丢弃压力、审计开关、文件压力、graceful shutdown 等。
10. 故障排查
| 现象 | 原因与处理 |
|---|---|
socket parent must be owned by uid 0 ... | socket 父目录权限不合(如 /tmp 1777)。建专用目录:sudo install -d -m 0755 /run/agsec |
启动报 unknown field 'enable_file' 等 | 配置是旧格式,按 §3 改写成一行式;或 /var/lib/censorguard 里有旧格式 revision 快照,停机后 sudo rm -rf /var/lib/censorguard |
daemon 反复重启,日志报 unknown argument "--spawn-grpc" | 旧二进制 + 新 systemd unit 不匹配:重新构建并同步安装二进制 |
Text file busy 复制二进制失败 | 二进制正在运行,先 systemctl stop 再复制 |
ctl 报 No such file or directory | daemon 未启动或 socket 路径不一致,先确认日志 [READY] |
policy apply/bind/set 报权限错误 | 需要 root(SO_PEERCRED),用 sudo |
| 规则不命中 | file/exec 规则按 inode 编译,目标文件重建后需 reload(§3.2);用 policy-dump 确认规范化策略 |
| 看不到 ALLOW 事件 | 默认只记 DENY;set --audit-<维度> on 或给规则加 +audit |
DSH attach 报 references uninstalled group | DSH 策略组未下发,root 执行 sudo censorguardctl policy apply --name censorguard-dsh-default --file config/policy.dsh-default.yaml |