RudrenduPaul/TenantGuard
GitHub: RudrenduPaul/TenantGuard
TenantGuard 是一款针对自托管多租户 AI-agent 平台的 CLI 配置审计工具,通过 14 条 fail-closed 的 OPA/Rego 规则在部署前发现租户隔离缺陷。
Stars: 0 | Forks: 0
# TenantGuard
**在审计员或攻击者发现之前,找出您的自托管多租户 AI-agent 平台中的租户隔离漏洞。**
[](https://github.com/RudrenduPaul/TenantGuard/actions/workflows/ci.yml)
[](https://github.com/RudrenduPaul/TenantGuard/releases/tag/v0.1.0)
[](LICENSE)
## 安装
```
go install github.com/RudrenduPaul/TenantGuard/cmd/tenantguard@v0.1.0
```
此仓库中已经存在一个 npm 包 (`tenantguard`) 且已接近发布状态,但它尚未在 npm registry 上发布。一旦发布,安装命令将如下所示:
```
npm install -g tenantguard
tenantguard scan --demo
```
或者直接使用 npx 运行,无需安装步骤:
```
npx tenantguard scan --target ./deployment/config
```
**即将推出,目前尚未生效。** 现在运行上述任何命令都会因 registry 404 错误而失败。在此部分更新为可用的安装命令之前,请使用上方的 `go install` 或 Homebrew tap。
## 目录
- [功能](#features)
- [快速开始](#quickstart)
- [CLI 参考](#cli-reference)
- [TenantGuard 的对比](#how-tenantguard-compares)
- [什么是 TenantGuard 以及它为什么存在](#what-is-tenantguard-and-why-does-it-exist)
- [常见问题解答](#faq)
- [贡献](#contributing)
- [许可证](#license)
## 功能
TenantGuard 会根据 14 条规则对自托管的多租户 AI-agent 部署配置进行扫描,每条规则均源自一个真实且已确认的租户隔离失效场景。每条规则均采用失败即拒绝(fail-closed)原则:未声明或模棱两可的设置都会被视为违规,而不是静默通过。
### 租户隔离边界
| 规则 | 检测内容 |
|---|---|
| **TA01** | 沙箱/工作区挂载属于违规,除非其路径包含 `${TENANT_ID}` 范围限定占位符,或者显式声明 `scoped_per_tenant` 为 true。对应 goclaw#1163。 |
| **TA03** | 定时任务(cron)绑定的 `target_agent` 必须属于声明该绑定的租户;悬空或跨租户引用将直接报错。对应 goclaw#1217。 |
| **TA11** | 标记两个共享相同 `device_session_id` 但声明了不同租户的 `channel_instances` 条目(例如共享的 WhatsApp 设备行)。对应 goclaw#1064/#1065。 |
| **TA14** | 每个 agent 的资源配置(浏览器/container)属于违规,除非其路径包含 `${TENANT_ID}` 占位符。对应 goclaw#778。 |
### 网络与凭证暴露
| 规则 | 检测内容 |
|---|---|
| **TA02** | 对目标地址为私有/回环/保留地址的已保存 MCP 工具 URL 进行标记。它对字面量或 DNS 解析后的 IP(而非字符串匹配)使用真实的 `net.cidr_contains` 进行检查。除非部署同时声明了 `validates_private` 和 `pins_resolved_ip`(或该主机被显式加入白名单)。明确指出了 DNS 重绑定/TOCTOU 的局限性。对应 goclaw#1070。 |
| **TA04** | 标记那些拒绝直接读取环境变量但未拒绝间接读取(例如 `jq $ENV`)的 exec 工具,并独立标记任何设置了 `allow_chain_exec: true` 的工具,因为凭证环境变量会泄露给 shell 操作符链中的每一个命令。对应 goclaw#1227 和 goclaw#1033。 |
| **TA08** | Provider 配置属于违规,除非它声明了一种受认可的强加密算法(目前仅限 `aes-256-gcm`)用于存储 OAuth/凭证 token。对应 goclaw#65。 |
### 执行与审批强化
| 规则 | 检测内容 |
|---|---|
| **TA05** | 仅基于基本文件名(而非完整路径)匹配的“始终允许” exec 审批属于违规,因为它可能被复用于共享该文件名的其他可执行文件。对应 goclaw#1216。 |
| **TA07** | 标记默认以 root 执行、完整传递宿主机环境、缺少 `noexec`/`nosuid`/`nodev` 的 tmpfs 挂载,或添加了任何危险的 Linux capability(`SETUID`、`SETGID`、`CHOWN`、`SYS_ADMIN`、`DAC_OVERRIDE`、`NET_ADMIN`、`SYS_PTRACE`)。对应 goclaw#1014、#1015、#524。 |
| **TA09** | 部署必须显式声明 `sandbox.on_unavailable: fail_closed`;未声明的值将被视为违规,而不是静默通过。对应 goclaw#246。 |
### 身份、审计与恢复
| 规则 | 检测内容 |
|---|---|
| **TA06** | 未在配置中声明 `captures_creator_identity` 的定时任务(cron)绑定属于违规;如果没有此配置,群组上下文任务将以 `system` 身份触发,而不是真实的创建者身份。对应 goclaw#1129。 |
| **TA12** | 部署级别的检查:如果 `owner_ids` 为空或未声明恢复/重置命令,则属于违规,这有导致操作员被永久锁定的风险。对应 goclaw#954。 |
| **TA13** | 部署级别的检查:如果 `bridge_hmac_enabled` 或 `bridge_context_headers_signed` 未声明为 true,则属于违规;缺失声明默认为未签名并报错,绝不静默通过。对应 goclaw#91。 |
| **TA10** | 尽力而为的静态配置代理:标记那些未显式声明 `has_workspace_restriction_override` 或 `has_sandbox_config_override` 的 agent 条目。对应 goclaw#145。 |
其他已验证的功能:
- **SARIF 2.1.0 输出** (`--format sarif`),schema 有效,包含真实的字节/行位置和消息,可直接用于 `github/codeql-action/upload-sarif` 和 GitHub 代码扫描。
- **临时 HIPAA 引用**附加到每一个发现结果上 (`--control hipaa`),按规则进行映射,并标记为临时(参见 [常见问题解答](#faq))。
- **零配置演示模式** (`--demo`),扫描内置的合成部署,无需目标配置。
- **GitHub Action** (`action/action.yml`),通过 `go install` 安装固定版本并自动上传 SARIF 报告。
## 快速开始
```
tenantguard scan --demo
```
实际捕获的输出:
```
TenantGuard: Tenant-Isolation Audit
Target: /var/folders/m0/5tzdd47n6znb166d4w3m2q0c0000gn/T/tenantguard-demo-2069015265
[FAIL] TA01 sandbox/workspace mount path is not scoped per-tenant (no ${TENANT_ID} placeholder and no explicit scoped_per_tenant declaration)
.../deployment.yaml:11
Maps to: goclaw#1163 | HIPAA Sec164.312(a)(1) Access Control (provisional)
[FAIL] TA02 MCP tool URL targets a private/loopback/reserved address (via real CIDR containment on a literal or DNS-resolved IP) without a verified, IP-pinned SSRF validator or an explicit host allowlist entry. CAVEAT: a PASS trusts the deployment's own pins_resolved_ip/validates_private declaration -- TenantGuard cannot verify the real validator actually pins the resolved IP for the connection itself, so DNS-rebinding/TOCTOU risk persists if that declaration is inaccurate
.../deployment.yaml:21
Maps to: goclaw#1070 | HIPAA Sec164.312(e)(1) Transmission Security (provisional)
[FAIL] TA03 cron binding's target agent does not belong to the declaring tenant
.../deployment.yaml:34
Maps to: goclaw#1217 | HIPAA Sec164.312(a)(1) Access Control (provisional)
[FAIL] TA04 exec tool denies direct env dump but not indirect env reads (e.g. jq $ENV), or allows credential-chain leakage via allow_chain_exec (goclaw#1033)
.../deployment.yaml:24
Maps to: goclaw#1227 | HIPAA Sec164.312(a)(2)(iv) Encryption/Decryption (provisional)
[FAIL] TA05 exec-approval allow-always entry is keyed on basename only, not a full path scope
.../deployment.yaml:29
Maps to: goclaw#1216 | HIPAA Sec164.312(a)(1) Access Control (provisional)
[FAIL] TA09 sandbox fail-closed posture not declared (sandbox.on_unavailable must be "fail_closed")
.../tenantguard-demo-2069015265:0
Maps to: goclaw#246 | HIPAA Sec164.312(a)(1) Access Control (provisional)
[FAIL] TA10 agent does not explicitly declare a per-agent config override (workspace restriction or sandbox config), risking silent inheritance of an undeclared global default
.../deployment.yaml:39
Maps to: goclaw#145 | HIPAA Sec164.312(a)(1) Access Control (provisional)
[FAIL] TA13 MCP/CLI bridge does not declare HMAC-signed context headers (bridge.hmac_enabled and bridge.context_headers_signed)
.../tenantguard-demo-2069015265:0
Maps to: goclaw#91 | HIPAA Sec164.312(e)(1) Transmission Security (provisional)
[FAIL] TA06 cron binding does not declare that its store layer captures/replays the human creator's sender identity at fire time
.../deployment.yaml:34
Maps to: goclaw#1129 | HIPAA Sec164.312(b) Audit Controls (provisional)
[FAIL] TA07 sandbox container privilege is not hardened (root user by default, full host-env passthrough, tmpfs missing noexec/nosuid/nodev, or a dangerous Linux capability added)
.../deployment.yaml:11
Maps to: goclaw#1014 | HIPAA Sec164.312(a)(1) Access Control (provisional)
[FAIL] TA11 channel/session device identity is shared across channel_instances declaring different tenants
.../deployment.yaml:52
Maps to: goclaw#1064 | HIPAA Sec164.312(a)(1) Access Control (provisional)
[FAIL] TA11 channel/session device identity is shared across channel_instances declaring different tenants
.../deployment.yaml:55
Maps to: goclaw#1064 | HIPAA Sec164.312(a)(1) Access Control (provisional)
[PASS] 1 check(s) clear
Summary: 12 FAIL, 1 PASS
Findings map to confirmed open goclaw issues where applicable. HIPAA citations are provisional, see README.
```
内置的测试用例是故意设计的非常嘈杂:它的存在是为了一次性触发几乎所有的规则。TA08(凭证存储加密)和 TA14(每个 agent 的资源配置隔离)是针对每个条目的检查,仅对扫描配置中的 `providers` 和 `resource_profiles` 条目触发,而该测试用例声明了零个此类条目,因此这两条规则没有任何可评估的内容,也不会产生任何发现结果,既不是 PASS 也不是 FAIL。显示为通过的那一行“1 check(s) clear”,是 TA12(owner/sysadmin 恢复),因为该测试用例的 `owner_ids` 和 `has_recovery_command` 值被特意设置为满足条件。退出代码为 `1`,因为存在发现结果;完整的退出代码契约请参见 [CLI 参考](#cli-reference)。
扫描真实的部署并输出用于代码扫描的 SARIF:
```
tenantguard scan --target ./deployment --format sarif --sarif-out tenantguard-report.sarif
```
## CLI 参考
TenantGuard 仅支持 CLI:只有一个单一的子命令 `scan`。没有顶层的 `--help` 或 `--version` 标志;如果在没有参数、使用 `tenantguard --help` 或使用除 `scan` 以外的任何参数运行 `tenantguard`,会将以下用法说明打印到 stderr 并退出 `2`:
```
usage: tenantguard scan [--target DIR | --demo] [--format terminal|sarif] [--control hipaa]
```
`tenantguard scan --help` 输出:
```
Usage of scan:
-control string
compliance framework to cite (hipaa)
-demo
scan a bundled synthetic deployment instead of --target (zero setup)
-format string
output format: terminal or sarif (default "terminal")
-sarif-out string
file to write SARIF output to when --format=sarif (default "tenantguard-report.sarif")
-target string
path to the deployment config directory to scan
```
退出代码(定义在 `cmd/tenantguard/main.go` 中):
| 代码 | 含义 |
|---|---|
| `0` | 干净的扫描,无发现结果 |
| `1` | 扫描成功运行,存在发现结果 |
| `2` | 扫描或使用错误 |
## TenantGuard 的对比
| 工具 | 侧重点 | 感知多租户 AI-agent | SARIF 输出 | 规则数量 | 项目成熟度 |
|---|---|---|---|---|---|
| **TenantGuard** | 针对自托管多 agent 平台的租户隔离配置审计 | 是,专门为这一层面构建 | 是,已验证 (SARIF 2.1.0) | 14 条,全部针对租户隔离 | v0.1.0,单一标签发布 |
| [Checkov](https://github.com/bridgecrewio/checkov) | 通用 IaC/云配置错误扫描器(Terraform、CloudFormation、Kubernetes、Dockerfile 等) | 否,README 未提及多租户 AI-agent 平台或租户隔离检查 | 是,已验证 (`-o sarif`) | 1000+ 条,涵盖通用云/IaC策略 | 8.9k GitHub stars,老牌项目,积极维护中 |
| [Conftest](https://github.com/open-policy-agent/conftest) | 用于结构化配置数据的参考 OPA/Rego 策略测试工具(18+ 种输入格式) | 否,这是其他工具用于构建策略包的通用 Rego 测试框架;没有内置的租户隔离或 AI-agent 规则包 | 是,已验证 (`-o sarif`,SARIF 2.1.0) | 0 条内置(这是一个策略测试引擎,不是规则包) | 老牌的参考 OPA 项目,积极维护中 |
| [PolicyGuard](https://github.com/ToluGIT/policyguard) | Terraform/OpenTofu AWS/Azure 配置错误扫描器(Go + OPA/Rego,Cobra CLI,沙箱化 OPA 引擎) | 否,严格限定于 Terraform/OpenTofu AWS/Azure 资源;未提及多租户系统或 AI-agent 平台 | 是,已验证 (SARIF 2.1.0 带有稳定指纹 + CWE 标签) | 15+ 条 AWS/Azure 资源检查 | 1 star,2 forks,4 个发布版本 (v0.3.1) |
| [AgentShield](https://github.com/affaan-m/agentshield) | AI-agent 安全扫描器(密钥、权限、hooks、MCP server 安全、agent 配置审查) | 否,明确限定于单个 Claude Code 用户的本地 `.claude/` 目录(单用户/团队开发环境),而非多租户 SaaS 隔离 | 是,已验证 (`--format sarif`,SARIF 2.1.0) | 102 条,分为 5 大类 | 在 2026 年 2 月的一次黑客马拉松上创建,处于早期阶段 |
TenantGuard 牺牲广度换取深度:14 条规则只是 Checkov 1000 多条规则的一小部分,而且 TenantGuard 只是一个 v0.1.0 版本,而 Checkov、Conftest 和 PolicyGuard 拥有更长的历史记录。TenantGuard 拥有而其他工具都没有的,是一套专为自托管 AI-agent 部署中的跨租户隔离构建的规则包,这是所有通用 IaC 扫描器都没有覆盖的领域,即使是领域最接近的 AgentShield 也未能触及:它只审计单个开发人员的本地配置,而不是自托管多租户部署中的跨租户隔离。这正是 TenantGuard 狭窄且刻意瞄准的细分市场。
TenantGuard 针对自身规则集与标记测试用例的精确率/召回率基准测试尚未发布;如果上述竞争对手报告了相关数据(例如 PolicyGuard 的精确率/召回率),这些数据均引用自该项目自己的 README,并未在此进行独立重新验证。
## 什么是 TenantGuard 以及它为什么存在
TenantGuard 是一个命令行策略即代码扫描器,使用 Go 编写并基于 OPA/Rego 构建。它主要用于审计自托管多租户 AI-agent 平台的配置是否存在租户隔离缺陷:即某个租户的 agent、沙箱、定时任务或凭证能够触及或影响另一个租户的一类 bug。
TenantGuard 之所以存在,是因为一个真实且已确认的多租户 AI-agent 平台 (goclaw) 在这一类别中一直存在多个未解决的公开问题,包括未按租户划分范围的沙箱挂载、跨 agent 的授权漏洞、通过间接路径泄露机密的 exec 工具、基于文件名而非真实路径范围匹配的审批绕过,以及保存的工具 URL 上的 SSRF 验证不匹配。目前没有现成的通用 IaC 扫描器(Checkov、ConftestPolicyGuard)或 AI-agent 安全扫描器(AgentShield)会检查这种特定的失效类别:自托管多 agent 部署中的跨租户隔离。TenantGuard 用 14 条失败即拒绝的规则填补了这一空白,每条规则都可以追溯到真实且已引用的具体问题。
TenantGuard 不是通用的 Terraform/Kubernetes 扫描器,不能替代 Checkov 或 Conftest 进行通用的云基础设施配置错误扫描。它专门针对自托管多租户 agent 部署的租户隔离层面。
## 常见问题解答
**TenantGuard 与 Checkov 或 Conftest 等通用 IaC 扫描器有何不同?**
Checkov 和 Conftest 扫描通用的基础设施即代码(Terraform、Kubernetes、CloudFormation 等),以发现大类的配置错误。它们都没有为多租户 AI-agent 部署提供规则包。TenantGuard 的 14 条规则是专门为这一层面定制的:沙箱挂载、cron/agent 绑定、MCP 工具注册、exec 审批以及 channel/session 身份,每一条都源于一个真实且已引用的缺陷。
**TenantGuard 会取代 OPA 或 Conftest 吗?**
不会。TenantGuard 的规则是用 Rego 编写的,并且 TenantGuard 打包了自己的评估路径;它是一个专用的策略包和 CLI,而不是通用的 Rego 测试框架。如果你需要针对任意 Rego 策略测试任意结构化配置,Conftest 才是正确的通用工具。TenantGuard 是专门针对多 agent 部署进行租户隔离检查的正确工具。
**每次发现结果上的 HIPAA 引用是什么意思?**
每一个发现结果都附有相关的 HIPAA 安全规则引用(例如 Sec164.312(a)(1) 访问控制),以帮助将技术发现映射到审查人员可能已经在跟踪的合规控制上。这些引用被标记为 **临时**:它们表示技术控制与所引用的 HIPAA 章节之间存在合理的映射关系,而不是法律或审计层面的合规性判定。请将它们视为您自己进行合规性审查的起点,而不是替代品。
**TA02 (SSRF) 通过意味着 MCP 工具 URL 实际上免受 DNS 重绑定的威胁吗?**
并不完全是。TA02 对字面量或 DNS 解析后的 IP(而非字符串匹配)使用了真实的 CIDR 包含检查,但通过测试的前提是信任部署自身声明的 `pins_resolved_ip`/`validates_private`。TenantGuard 无法独立验证真实的验证器是否在实际连接中固定了解析后的 IP,因此如果该声明不准确,DNS 重绑定/TOCTOU 的风险依然存在。这一局限性已直接记录在 TA02 规则中。
**我可以扫描真实的部署,而不是使用内置的演示吗?**
可以:`tenantguard scan --target `。`--demo` 的存在是为了让您在将其指向真实配置之前,能够在零设置的情况下看到工具的运行情况。
**TenantGuard 生成的输出可以被 CI 流水线或 GitHub 代码扫描使用吗?**
可以。`--format sarif --sarif-out ` 会生成一个 schema 有效的 SARIF 2.1.0 文档,其中包含真实的结果位置和消息。内置的 GitHub Action (`action/action.yml`) 会在一个步骤中运行扫描并通过 `github/codeql-action/upload-sarif` 上传 SARIF 报告。
**CLI 退出代码是什么意思?**
`0` 表示扫描干净且没有发现结果,`1` 表示扫描成功运行并发现了违规,`2` 表示扫描或使用错误(包括在没有子命令或使用除 `scan` 以外的任何子命令的情况下运行 `tenantguard`)。
**有 npm 包吗?**
尚未在 npm registry 上发布。有关计划的 `npm`/`npx` 命令,请参见上方的 [安装](#install)。在此之前,请使用 `go install` 或 Homebrew tap。
**TenantGuard 是一个我可以导入到自己 Go 程序中的库吗?**
不,目前不是。`cmd/tenantguard` 之外的所有内容(收集器、合规性映射、演示测试用例、策略引擎和报告格式化)都位于 `internal/` 目录下,Go 自己的工具链使得该目录无法从本模块外部导入。TenantGuard 以 CLI 二进制文件和 GitHub Action 的形式分发,而不是作为可导入的 Go 包。
## 贡献
欢迎贡献。有关如何添加新规则,请参见 [CONTRIBUTING.md](CONTRIBUTING.md);每一条规则在发布前都需要同时具备一个漏洞测试用例和一个干净的测试用例。
## 许可证
Apache License 2.0。参见 [LICENSE](LICENSE)。
标签:EVTX分析, LNA, OPA, SARIF, 日志审计, 暗色界面, 租户隔离, 结构化提示词, 错误基检测, 静态代码分析, 靶场