timkrebs/custos

GitHub: timkrebs/custos

custos 是用于 HashiCorp Vault ACL 策略的测试与安全分析工具,在问题上线前捕获配置错误与高危权限。

Stars: 0 | Forks: 0

# Custos [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/0090d60829230249.svg)](https://github.com/timkrebs/custos/actions/workflows/ci.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/timkrebs/custos)](https://goreportcard.com/report/github.com/timkrebs/custos) [![Go Version](https://img.shields.io/github/go-mod/go-version/timkrebs/custos)](https://go.dev/doc/devel/release) [![Release](https://img.shields.io/github/v/release/timkrebs/custos)](https://github.com/timkrebs/custos/releases/latest) [![Go Reference](https://pkg.go.dev/badge/github.com/timkrebs/custos.svg)](https://pkg.go.dev/github.com/timkrebs/custos) [![License](https://img.shields.io/github/license/timkrebs/custos)](LICENSE) [![codecov](https://codecov.io/gh/timkrebs/custos/branch/main/graph/badge.svg)](https://codecov.io/gh/timkrebs/custos) **用于 HashiCorp Vault 策略的缺失的 `terraform plan`。** custos(拉丁语意为“守护者”)是一个 CLI 工具,允许你编写 Vault ACL 策略的测试规范,离线或针对运行中的 Vault 实例运行它们,并在问题到达生产环境之前捕获配置错误、权限过高访问和策略冲突。 ![image](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/e8bf14569d230250.svg) ``` $ custos test -f payment-svc.spec.yaml payment-service-policies OK payment service can read its own secrets (secret/data/payment-svc/db-creds) OK payment service cannot read billing secrets (secret/data/billing-svc/api-key) OK payment service cannot delete anything (secret/data/payment-svc/*) OK payment service can issue short-lived certs (pki_int/issue/payment-svc) FAIL no access to sys backend (sys/seal) → expected: deny, got: allow via policy "admin-legacy" (line 14) 4 passed · 1 failed · 0 skipped Security findings: WARN wildcard path "secret/*" grants [create read update delete list] in admin-legacy.hcl:8 WARN sudo capability outside sys/ found in admin-legacy.hcl:14 INFO policy path coverage: 5/12 paths tested (41%) — consider adding more tests ``` ## 为什么 每个 Vault 用户都会遇到相同的瓶颈:策略以 HCL 编写、应用到 Vault,然后手动通过创建令牌并运行 `vault kv get` 进行测试。没有结构化的方法可以回答“如果我应用此策略,实体 X 能否访问路径 Y?”而无需实际部署。 这带来了真实的问题: - **无预合并验证** —— 策略变更经过代码审查,但没人能在应用到 Vault 前验证其正确性 - **无回归测试** —— 策略重构可能无声地授予本应被拒绝的路径访问权限 - **无安全分析** —— 通配符路径、sudo 泄露和策略提升向量隐藏在明处 - **无 CI 集成** —— Terraform 可以规划基础设施变更,但 Vault ACL 策略没有等价物 custos 填补了这一空白。 ## 功能 ### 离线策略评估(无需 Vault) 在本地解析 `.hcl` 策略文件,构建与 Vault 内部相同的评估树,并在无网络访问的情况下运行断言。在 CI 中、隔离环境中或开发期间在笔记本电脑上运行策略测试。 ``` custos test -f myapp.spec.yaml ``` ### 针对运行中 Vault 的在线验证 连接到运行中的 Vault 实例,并使用 `sys/capabilities` 验证实际的令牌和实体权限。捕获离线评估器无法检测的内容:Sentinel 策略效果、身份组继承、命名空间 chroot 行为和响应包装约束。 ``` custos test -f myapp.spec.yaml --vault-addr=$VAULT_ADDR --vault-token=$VAULT_TOKEN ``` ### 安全扫描 在不编写任何测试规范的情况下分析策略中的危险模式。检测权限过高的访问、通配符滥用、策略提升向量以及冲突的拒绝/允许规则。 ``` custos scan policies/*.hcl ``` ### 策略组合 测试附加到单个实体的多个策略的联合效果——这正是 Vault 在生产中的工作方式。权限在策略间合并,拒绝覆盖允许,最具体的路径优先。 ``` policies: - path: policies/base-readonly.hcl - path: policies/payment-svc.hcl - path: policies/team-platform.hcl ``` ### CI/CD 友好输出 适用于 Jenkins/GitLab 的 JUnit XML、自定义工具的 JSON,以及供人类阅读的彩色终端输出。 ``` custos test -f myapp.spec.yaml --format=junit > results.xml custos test -f myapp.spec.yaml --format=json > results.json ``` ## 安装 ### 从源码安装(需要 Go 1.22+) ``` go install github.com/timkrebs/custos/cmd/custos@latest ``` ### 从发布二进制文件安装 从 [Releases](https://github.com/timkrebs/custos/releases) 页面下载适用于你平台的最新版本。 ### Homebrew(macOS/Linux) ``` brew install timkrebs/tap/custos ``` ## 快速开始 ### 1. 编写策略 ``` # policies/payment-svc.hcl path "secret/data/payment-svc/*" { capabilities = ["read", "list"] } path "secret/data/billing-svc/*" { capabilities = ["deny"] } path "pki_int/issue/payment-svc" { capabilities = ["create", "update"] } path "transit/encrypt/payment-key" { capabilities = ["update"] } path "transit/decrypt/payment-key" { capabilities = ["update"] } ``` ### 2. 编写测试规范 ``` # payment-svc.spec.yaml suite: "payment-service-policies" policies: - path: policies/payment-svc.hcl tests: # --- Secrets access --- - name: "can read its own secrets" path: "secret/data/payment-svc/db-creds" capabilities: [read] expect: allow - name: "can list its own secret keys" path: "secret/data/payment-svc/" capabilities: [list] expect: allow - name: "cannot write to its own secrets" path: "secret/data/payment-svc/db-creds" capabilities: [create, update] expect: deny - name: "cannot read billing secrets" path: "secret/data/billing-svc/api-key" capabilities: [read] expect: deny # --- PKI --- - name: "can issue certificates" path: "pki_int/issue/payment-svc" capabilities: [create, update] expect: allow - name: "cannot issue certs for other services" path: "pki_int/issue/billing-svc" capabilities: [create, update] expect: deny # --- Transit --- - name: "can encrypt with payment key" path: "transit/encrypt/payment-key" capabilities: [update] expect: allow - name: "cannot access other transit keys" path: "transit/encrypt/billing-key" capabilities: [update] expect: deny # --- Boundaries --- - name: "no sys access" path: "sys/seal" capabilities: [sudo] expect: deny - name: "no auth method management" path: "auth/token/create" capabilities: [create] expect: deny # 可选:安全分析配置 # 每个条目以检查 ID 作为键。内置的过度权限检查按 # 默认在其基准严重性下运行;使用以下条目禁用、 # 将特定路径列入白名单,或覆盖严重性。 analyze: - check: sudo_capability allow_paths: - database/config/rotate # legitimate sudo use, keep it quiet - check: wildcard_paths disabled: true # this codebase intentionally uses broad wildcards - check: secret_destroy severity: error # bump the default warning to error - check: coverage min_coverage: 80% # planned: percentage of policy paths with test assertions - check: conflicts severity: warning # planned: flag overlapping deny/allow across composed policies ``` ### 3. 运行测试 ``` $ custos test -f payment-svc.spec.yaml ``` ### 4. 添加到 CI 流水线 ``` # .github/workflows/vault-policies.yml name: Vault policy tests on: pull_request: paths: ['policies/**', '*.spec.yaml'] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install custos run: go install github.com/timkrebs/custos/cmd/custos@latest - name: Run policy tests (offline) run: custos test -f payment-svc.spec.yaml --format=junit > results.xml - name: Publish test results uses: dorny/test-reporter@v1 if: always() with: name: Vault policy tests path: results.xml reporter: java-junit ``` ## CLI 参考 ``` custos — test and analyze HashiCorp Vault ACL policies Usage: custos [flags] Commands: test Run test assertions against policies (offline or online) scan Security scan policies for dangerous patterns init Generate a test spec skeleton from existing policy files validate Syntax-check a test spec file version Print version information Flags (test): -f, --file string Path to test spec YAML file (required) --vault-addr string Vault server address (enables online mode) --vault-token string Vault authentication token --vault-namespace str Vault namespace (Enterprise) --format string Output format: terminal (default), junit, json --fail-on-warn Exit non-zero on security warnings (not just test failures) --timeout duration Timeout for online Vault requests (default: 10s) -v, --verbose Show detailed evaluation trace per test Flags (scan): --vault-addr string Scan live Vault policies instead of files --vault-token string Vault authentication token --severity string Minimum severity to report: info, warning, error (default: warning) --format string Output format: terminal (default), json Flags (init): --from string Path to .hcl policy file(s) to generate skeleton from --all-paths Generate a test assertion for every path in the policy ``` ## 工作原理 ### 离线评估引擎 custos 使用 HashiCorp 自己的解析库解析 HCL 策略文件,并构建内存中的策略评估树。对于每个测试断言,它执行以下操作: 1. **解析路径** —— 使用 Vault 的通配符/前缀匹配语义(`*` 匹配单个路径段,`+` 在较新 Vault 版本中匹配路径段)将测试路径与所有策略路径规则进行匹配 2. **选择最匹配项** —— Vault 使用最长前缀匹配算法;精确路径优先于通配符,通配符优先于前缀 3. **评估权限** —— 检查请求的权限是否存在于匹配规则的能力集中 4. **应用拒绝逻辑** —— 任何匹配路径上的 `deny` 权限会覆盖其他所有授权 5. **组合多个策略** —— 当指定多个策略文件时,权限在策略间求并集(合并),然后应用拒绝规则作为覆盖 这反映了 Vault 实际的评估顺序,详见 [Vault ACL 策略文档](https://developer.hashicorp.com/vault/docs/concepts/policies)。 ### 在线验证 当提供 `--vault-addr` 时,custos 切换到在线模式并使用 Vault API: - `POST sys/capabilities` —— 针对路径评估特定令牌的权限 - `POST sys/capabilities-self` —— 评估调用令牌的权限 - `GET sys/policy/{name}` —— 从运行中的 Vault 获取策略定义以进行扫描 在线模式可以捕获离线评估无法建模的效果:Sentinel 策略(企业版)、身份组归属与实体别名、命名空间 chroot 监听器以及 MFA 强制。 ### 安全分析 `scan` 命令(以及测试规范中的 `analyze` 部分)对策略 HCL 执行静态分析: | 检查 | 检测内容 | 严重级别 | |---|---|---| | `wildcard_paths` | 以 `*` 结尾且授予 3 个以上权限的路径 | 警告 | | `sudo_capability` | 在非 `sys/` 或 `auth/token/` 路径上的 `sudo` 权限 | 错误 | | `root_token_create` | 在 `auth/token/create` 上的 `create` 权限(令牌铸造) | 错误 | | `policy_escalation` | 在 `sys/policy/*` 或 `sys/policies/acl/*` 上的 `update` 权限 | 错误 | | `secret_destroy` | 在 `secret/destroy/*` 或 `secret/metadata/*` 上的 `delete` 权限 | 警告 | | `coverage` | 带有测试断言的策略路径规则百分比 | 信息 | | `conflicts` | 组合策略间重叠的允许/拒绝 | 警告 | ## 项目结构 ``` custos/ ├── cmd/ │ └── custos/ │ └── main.go # CLI entrypoint (cobra) ├── pkg/ │ ├── parser/ │ │ ├── hcl.go # HCL policy file parsing │ │ └── hcl_test.go │ ├── evaluator/ │ │ ├── offline.go # Local policy evaluation engine │ │ ├── offline_test.go │ │ ├── online.go # Live Vault sys/capabilities client │ │ ├── online_test.go │ │ └── composer.go # Multi-policy composition logic │ ├── analyzer/ │ │ ├── overprivilege.go # Dangerous pattern detection │ │ ├── coverage.go # Path coverage calculation │ │ ├── conflicts.go # Deny/allow overlap detection │ │ └── analyzer_test.go │ ├── spec/ │ │ ├── loader.go # YAML test spec parsing + validation │ │ └── loader_test.go │ └── reporter/ │ ├── terminal.go # Colored PASS/FAIL terminal output │ ├── junit.go # JUnit XML for CI systems │ └── json.go # Structured JSON report ├── testdata/ │ ├── policies/ # Example HCL policies │ │ ├── admin.hcl │ │ ├── readonly.hcl │ │ ├── payment-svc.hcl │ │ └── overprivileged.hcl │ └── specs/ # Example test specs │ ├── payment-svc.spec.yaml │ ├── admin.spec.yaml │ └── composed.spec.yaml ├── .github/ │ └── workflows/ │ └── ci.yml # custos's own CI ├── .goreleaser.yml # Release automation ├── LICENSE # MPL-2.0 ├── README.md └── go.mod ``` ## 关键依赖 | 依赖 | 用途 | |---|---| | `github.com/hashicorp/vault/sdk` | 策略结构体定义与解析逻辑 | | `github.com/hashicorp/hcl/v2` | HCL 文件解析 | | `github.com/hashicorp/vault/api` | 在线模式下的 Vault API 客户端 | | `github.com/spf13/cobra` | CLI 框架 | | `gopkg.in/yaml.v3` | 测试规范解析 | | `github.com/fatih/color` | 终端彩色输出 | ## 路线图 - [x] 核心 HCL 策略解析与离线评估 - [x] YAML 测试规范格式 - [x] 带彩色输出的终端报告器 - [ ] 通过 `sys/capabilities` 的在线模式 - [ ] JUnit XML 报告器 - [ ] JSON 报告器 - [ ] 安全扫描(`custos scan`) - [ ] 权限过高访问检测 - [ ] 策略冲突检测 - [ ] 路径覆盖率报告 - [ ] `custos init` —— 从现有策略生成测试骨架 - [ ] 命名空间感知评估(Vault 企业版) - [ ] Sentinel 策略集成(Vault 企业版) - [ ] Vault 开发服务器集成,用于混合离线/在线测试 - [ ] GitHub Action(`uses: timkrebs/custos-action@v1`) - [ ] Grafana 仪表板模板,用于随时间分析扫描结果 ## 对比 | 功能 | custos | Ned's vault-policy-testing | 手动 `vault token` 测试 | |---|---|---|| | 离线测试(无需 Vault) | 是 | 否 | 否 | | 在线验证 | 是 | 是 | 是 | | 策略组合 | 是 | 否 | 部分 | | 安全扫描 | 是 | 否 | 否 | | 权限过高访问检测 | 是 | 否 | 否 | | 冲突检测 | 是 | 否 | 否 | | 路径覆盖率 | 是 | 否 | 否 | | CI/CD 输出(JUnit/JSON) | 是 | 否 | 否 | | 隔离环境支持 | 是 | 否 | 否 | | 命名空间支持 | 是 | 否 | 是 | | 从策略生成测试规范 | 是 | 否 | 否 | ## 许可证 MPL-2.0 — 与 HashiCorp 开源工具使用的许可证相同。 *custos 是一个独立的开源项目,与 HashiCorp 或 IBM 无关,也不受其背书。*
标签:admin-legacy, EVTX分析, Go语言, Homebrew安装, JSONLines, Sentinel 替代, Streamlit, sys 权限, Terraform 替代, Vault ACL, 写权限, 删除权限, 安全合规, 安全测试, 密钥策略, 密钥路径分析, 攻击性安全, 日志审计, 最小权限, 权限审查, 权限控制, 生产前检查, 离线测试, 程序破解, 策略冲突, 策略即代码, 策略模拟, 策略测试, 策略验证, 网络代理, 聊天机器人安全, 访问控制, 证书颁发, 误配置检测, 读权限, 过度授权, 运行时测试, 通配符策略, 零信任