0hardik1/kubesplaining
GitHub: 0hardik1/kubesplaining
一款 Kubernetes 安全评估 CLI 工具,通过图搜索构建从每个 Subject 到高价值目标的完整提权路径,并生成按风险优先级排序的多格式报告。
Stars: 76 | Forks: 7
# Kubesplaining
[](https://github.com/0hardik1/kubesplaining/releases)
[](LICENSE)
[](https://github.com/0hardik1/kubesplaining/actions/workflows/lint.yml)
[](go.mod)
[](https://goreportcard.com/report/github.com/0hardik1/kubesplaining)
一个 Kubernetes 安全评估 CLI 工具,能够映射每个 RBAC subject 到 cluster-admin、host root 和 kube-system secrets 的提权路径,然后将这些链条生成为按风险优先级排序的 HTML / JSON / CSV / SARIF 报告。
* [实时示例报告](https://0hardik1.github.io/kubesplaining/)
灵感来源于 BeyondTrust Phantom Labs 的 [Kinnaird McQuade](https://www.linkedin.com/in/kmcquade3/) 及其为 AWS IAM 提供相同功能的 [Cloudsplaining](https://github.com/salesforce/cloudsplaining)。Kubesplaining 会读取运行中的集群或之前捕获的快照,根据技术库对其进行分析,并生成按优先级排序的发现结果列表:提供的是解释,而不仅仅是检测。
## 为什么选择 kubesplaining
大多数 Kubernetes 扫描器只停留在“此资源配置不当”。Kubesplaining 回答了一个不同的问题:**攻击者实际上将如何穿透您的集群?** 根据您现有的 RBAC 绑定和 pod,它会从每个非系统 subject 开始遍历提权图,并告知您哪些 subject 可以到达 `cluster-admin`、host root 或 `kube-system` secrets,同时附带完整的跳板链。
它专注于攻击者实际利用的阵地:
- **提权路径**:基于图的“subject A 可以变成 subject B 从而到达终点 X”的链条,通过 BFS 搜索指向四个终点(`cluster-admin`、`system:masters`、`node-escape`、`kube-system-secrets`)。
- **过度宽松的 RBAC**:通配符、模拟、bind/escalate、secret 读取、pod 创建、token 签发。
- **Pod 逃逸攻击面**:特权容器、host 命名空间、敏感的 hostPath 挂载、容器 socket 挂载。
- **网络隔离缺口**:缺少 NetworkPolicy 的命名空间、允许广泛互联网外流 的策略。
- **准入控制 绕过**:fail-open 的 webhook、objectSelector 绕过、敏感命名空间豁免。
- **Secrets 和 ServiceAccount 卫生**:传统 token secret、ConfigMap 中的凭据、默认 SA 挂载、DaemonSet token 爆炸半径。
每一项发现都指明了所使用的技术、展示了证据,并包含了修复建议。
**使用场景:**
- **渗透测试 / 红队演练**:提权路径*即是*攻击计划。
- **新绑定添加前的安全审查**:查看它是否阻断了从不可信来源到终点的图路径。
- **CI 中的持续保障**:带有严重性预算的 `--ci-mode` 会在高危发现超过阈值时使流水线失败。
- **事件后重演**:捕获快照,离线分析,解释攻击者可能如何进行移动。
## 快速开始
安装后(见下方 [安装](#installation)),将 Kubesplaining 指向您当前的 `kubectl` 上下文:
```
kubesplaining scan # writes ./kubesplaining-report/
open kubesplaining-report/report.html # macOS; xdg-open on Linux
```
已经克隆了仓库?`make scan` 会构建二进制文件(Hermit 会自动下载固定的 Go 工具链)并一步到位地针对您当前的 `kubectl` 上下文运行它——无需单独安装。可以通过 `ARGS` 传递额外的标志,例如 `make scan ARGS="--severity-threshold high --only-modules privesc"`。
对于气隙环境 或审计工作流,请先捕获快照然后离线分析:
```
kubesplaining download --output-file snapshot.json
kubesplaining scan --input-file snapshot.json
```
对于无需集群访问权限的单次 manifest 检查:
```
kubesplaining scan-resource --input-file deployment.yaml
```
## 安装
选择适合您的方式。这三种方式都会生成相同的 `kubesplaining` 二进制文件。
### Go install
```
go install github.com/0hardik1/kubesplaining/cmd/kubesplaining@latest
```
### 预构建二进制文件
从 [发布页面](https://github.com/0hardik1/kubesplaining/releases/latest) 获取与您的操作系统/架构匹配的压缩包,解压后将 `kubesplaining` 放入您的 `PATH` 中。每个版本附带:
- `kubesplaining__Linux_x86_64.tar.gz` / `Linux_arm64.tar.gz`
- `kubesplaining__Darwin_x86_64.tar.gz` / `Darwin_arm64.tar.gz`
- `kubesplaining__Windows_x86_64.zip`
- `kubesplaining__checksums.txt` (SHA-256)
校验 checksum 后,将二进制文件移至相应位置:
```
shasum -a 256 -c kubesplaining__checksums.txt
sudo install kubesplaining /usr/local/bin/
```
### Homebrew
将在版本发布后作为快速跟进提供:`brew install 0hardik1/tap/kubesplaining` 将在 v1.0.0 之后不久上线。
## 检查内容
目前跨 7 个模块有 41 个稳定的规则 ID,外加将它们串联起来的提权图。完整的逐条规则的严重性、检测逻辑和修复建议:[docs/findings.md](docs/findings.md)。
| 模块 | 规则数 | 关注点 |
| --- | --- | --- |
| **rbac** | 10 | 通配符 / 模拟 / bind-escalate / secret 读取 / pod 创建 / nodes-proxy / token 创建 |
| **podsec** | 13 | 特权、host 命名空间、hostPath、容器 socket、runAsRoot、可变标签 |
| **network** | 5 | 缺少 NetworkPolicy 的命名空间、广泛的互联网外流、未被选中的工作负载 |
| **admission** | 3 | failurePolicy: Ignore、objectSelector 绕过、敏感命名空间豁免 |
| **secrets** | 4 | 传统 SA token secret、类似凭据的 ConfigMap 键、CoreDNS 篡改 |
| **serviceaccount** | 4 | 特权 SA、default-SA RBAC、DaemonSet token 爆炸半径 |
| **privesc** | 4 个终点 | 指向 cluster-admin / system:masters / node-escape / kube-system-secrets 的图链条 |
每项发现都带有 `RiskCategory`(`privilege_escalation`、`data_exfiltration`、`lateral_movement`、`infrastructure_modification`、`defense_evasion`)标签,以便 HTML 报告可以按影响车道分组。
规则 ID 是一个**公共接口**:它们在各个版本中保持稳定,并在 `findings.json`、SARIF 输出以及 `scripts/kind-e2e.sh` 中的端到端断言中被引用。
## 工作原理
四阶段流水线:
```
┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Connection │ → │ Collection │ → │ Analysis │ → │ Report │
│ kubeconfig │ │ snapshot.json │ │ 7 modules ∥ │ │ html/json/ │
│ / in-cluster │ │ RBAC+workload │ │ findings[] │ │ csv/sarif │
└───────────────┘ └───────────────┘ └───────────────┘ └───────────────┘
```
最重要的边界:**收集器是唯一与 Kubernetes API 通信的部分**;分析器只消费 `Snapshot` 且从不进行网络调用。这正是 `download` → `scan --input-file` 能够用于离线分析的原因。只读访问就足够了:无需准入 webhook,无需代理,无需安装 CRD。
如需了解每个阶段的演练、提权图机制、数据模型和评分公式:[docs/architecture.md](docs/architecture.md)。
## 样本发现
输出的实际样子。每条规则都会生成一个带有稳定 `RuleID`、严重性、证据和修复建议的 `Finding`;提权规则额外包含一个 `EscalationPath` 数组。
完整的规则目录(每条规则的严重性、检测、修复):[docs/findings.md](docs/findings.md)。
## 离线分析
收集器和分析器是解耦的:快照是一个普通的 JSON 文件。捕获一次,反复分析,适用于凭据不应保存在分析人员机器上的环境:
```
# 在带有 cluster credentials 的 jumphost 上:
kubesplaining download --output-file snapshot.json
# 将 snapshot.json 移动到你的笔记本电脑 / audit machine,然后:
kubesplaining scan --input-file snapshot.json
```
适用于:
- **审计轨迹**:快照就是证据;重复运行会产生完全一致的发现。
- **气隙审查**:分析生产集群而无需将 kubeconfig 带离跳板机。
- **Manifest 扫描**:`kubesplaining scan-resource --input-file deployment.yaml` 针对单个 YAML 运行相同的分析器,无需集群。
## CI 集成
SARIF 输出可与 [GitHub 代码扫描](https://docs.github.com/en/code-security/code-scanning) 集成,因此发现结果将显示为 PR 注释。在专用的 GitHub Action 发布之前(版本发布后的快速跟进),`docker run` 形式可直接运行:
```
# .github/workflows/kubesplaining.yml
name: Kubesplaining
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- uses: actions/checkout@v6
- name: Scan manifests
run: |
docker run --rm \
-v "${{ github.workspace }}:/work" -w /work \
ghcr.io/0hardik1/kubesplaining:latest \
scan-resource --input-file manifests/ --output-format sarif \
--output-dir /work/kubesplaining-report
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: kubesplaining-report/results.sarif
```
或者使用 `--ci-mode` 让超出预算的发现导致构建失败:
```
kubesplaining scan --ci-mode --ci-max-critical 0 --ci-max-high 0
```
当 critical / high(严重/高)级别的发现数量超过配置的阈值时,`--ci-mode` 会以非零状态退出;可结合 `--severity-threshold` 来限定计数范围。
## 排除项
`scan`、`scan-resource` 和 `report` **默认自动应用 `standard` 排除项预设**,因此关于内置 Kubernetes 底层设施的发现会被预先抑制。这涵盖了 kube-system / kube-public / kube-node-lease 命名空间、kube-controller-manager service account(`clusterrole-aggregation-controller`、`generic-garbage-collector` 等)、`system:*` 用户/组/角色,以及 `kubeadm:*` 组和 bootstrap 角色。所有这些都不是操作员在不破坏集群的情况下可以更改的,因此将它们显示为风险只会掩盖那些真正可操作的内容。
使用 `--exclusions-preset` 选择不同的基线:
| 预设 | 行为 |
| --- | --- |
| `standard`(默认) | 自动应用。过滤 kube-system / system:* / kubeadm:* 噪音。 |
| `minimal` | 仅过滤 `kube-public`、`kube-node-lease` 和 `system:*`。 |
| `none`(别名 `strict`) | 无内置过滤:所有发现浮出水面,包括控制平面噪音。 |
使用 `--exclusions-file path.yml` 在此基础上叠加自定义规则。用户文件与预设**合并**,因此您会保留默认设置并添加您自己的抑制项(特定的 service account、预期的工作负载、自定义 rule-ID 模式)。生成一个初始文件:
```
kubesplaining create-exclusions-file --preset standard --output-file exclusions.yml
```
完整的 YAML 架构(Global / RBAC / PodSecurity / NetworkPolicy 部分,所有匹配器均支持 shell 风格的 glob)请参见 [docs/exclusions.md](docs/exclusions.md)。
要审查默认设置隐藏了什么,请使用 `--exclusions-preset=none` 重新运行并进行 diff 对比。
## 备忘录
### 命令
| 命令 | 用途 |
| --- | --- |
| `kubesplaining scan` | 分析(实时或 `--input-file`)并写入报告。 |
| `kubesplaining download` | 从实时集群捕获 `snapshot.json`。只读。 |
| `kubesplaining scan-resource` | 扫描单个资源 manifest 以进行快速检查。 |
| `kubesplaining report` | 从现有的 findings JSON 重新渲染报告。 |
| `kubesplaining create-exclusions-file` | 生成一个初始 exclusions YAML。 |
| `kubesplaining version` | 打印构建信息。 |
### 常用标志
| 标志 | 默认值 | 用途 |
| --- | --- | --- |
| `--severity-threshold` | `low` | 隐藏低于此严重级别的发现(`critical` / `high` / `medium` / `low` / `info`)。 |
| `--output-format` | `html,json` | 以逗号分隔的列表:`html`、`json`、`csv`、`sarif`。 |
| `--output-dir` | `./kubesplaining-report` | 报告写入位置。 |
| `--only-modules` / `--skip-modules` | — | 限定分析器范围(`rbac`、`podsec`、`network`、`admission`、`secrets`、`serviceaccount`、`privesc`)。 |
| `--max-privesc-depth` | `5` | 提权图的 BFS 深度上限。 |
| `--ci-mode` | off | 超过阈值时以非零状态退出。 |
| `--ci-max-critical` / `--ci-max-high` | `0` / `0` | CI 模式下允许的各严重级别的最大数量。 |
| `--exclusions-preset` | `standard` | `standard` / `minimal` / `none`。 |
| `--exclusions-file` | — | 用户提供的 YAML,在预设之上合并。 |
| `--input-file` | — | 使用快照 JSON 代替实时收集。 |
| `--namespaces` / `--exclude-namespaces` | — | 按命名空间过滤实时收集。 |
| `--parallelism` | `10` | 实时收集期间的最大并行 API 请求数。 |
### 输出格式
| 格式 | 使用场景 |
| --- | --- |
| HTML | 人工审查;自成一体,可离线工作,包含针对各项发现的教育性说明 |
| JSON | 编程式消费,快照 diff |
| CSV | 分类电子表格 |
| SARIF | GitHub 代码扫描,IDE 集成 |
## 常见问题解答
**为什么 `system:masters` 在某些集群中被标记而在另一些中没有?**
提权分析器跳过 `system:*` 主体作为*可遍历的中间节点*(这样路径就不会通过控制平面进行洗钱),但如果您可以模拟或以其他方式提权至 `system:*`,它*确实会*将 `system:*` 报告为可达终点目标。如果分析器没有看到任何人具备这种能力,该规则将保持静默。
**提权路径有多准确?**
每一次跳板都根据快照的 RBAC 和 pod 状态进行了验证。分析器不会推测。误报来源于那些在*结构上*可能但在操作上被抑制的链条(例如,一个 SA 绑定到一个从未实际使用过的角色)。严重性会根据链条长度进行衰减(跳板数 ≥ 3 时下降一个等级);使用 `--max-privesc-depth` 来限制 BFS 的激进程度。
**我可以针对我的生产集群运行它吗?**
可以。只读访问就足够了。不会安装任何 webhook、CRD、agent 或 pod。被禁止的列表请求会被降级为警告而不是致命错误,因此被锁定的集群依然能产生有用的输出。
**为什么没有准入 webhook?**
超出了范围。其意图是*评估*,而不是*强制执行*。如果您想要强制执行,请根据发现结果生成 Kyverno / Gatekeeper 策略,并将其移交给您的策略引擎。
**为什么发现默认被排除?**
`standard` 预设抑制了控制平面的噪音(kube-system、system:*、kubeadm:*),操作员在不破坏集群的情况下无法更改这些内容。使用 `--exclusions-preset=none` 重新运行可查看所有内容。
## 接下来去哪
- **完整规则目录**(已实现 + 计划中):[docs/findings.md](docs/findings.md)
- **架构深入探讨**(分阶段演练、评分、数据模型):[docs/architecture.md](docs/architecture.md)
- **排除项 YAML 架构**(预设、部分、glob 语义):[docs/exclusions.md](docs/exclusions.md)
- **路线图与状态**:[PLAN.md](PLAN.md)
- **发布与更新日志**:[CHANGELOG.md](CHANGELOG.md) / [GitHub Releases](https://github.com/0hardik1/kubesplaining/releases)
- **贡献**:[CONTRIBUTING.md](CONTRIBUTING.md)
- **安全披露**:[SECURITY.md](SECURITY.md)(仅限 GitHub 私有漏洞报告)
- **许可证**:[Apache-2.0](LICENSE)
- **端到端验证**:`make e2e` 使用 `testdata/` 中故意带有风险的 manifest 配置一个本地 kind 集群,并断言预期的发现结果
KUBE-PRIVESC-PATH-CLUSTER-ADMIN:Service Account 在 2 次跳板内达到 cluster-admin
``` { "id": "KUBE-PRIVESC-PATH-CLUSTER-ADMIN:foo:builder-bot", "rule_id": "KUBE-PRIVESC-PATH-CLUSTER-ADMIN", "severity": "CRITICAL", "score": 9.3, "category": "privilege_escalation", "subject": { "kind": "ServiceAccount", "namespace": "foo", "name": "builder-bot" }, "title": "ServiceAccount foo/builder-bot can reach cluster-admin equivalent in 2 hop(s)", "escalation_path": [ { "from_subject": "ServiceAccount/foo/builder-bot", "to_subject": "ServiceAccount/kube-system/replicaset-controller", "action": "pod_create", "permission": "create on pods", "gains": "run a pod that mounts the kube-system replicaset-controller token" }, { "from_subject": "ServiceAccount/kube-system/replicaset-controller", "to_subject": "ClusterRole/cluster-admin", "action": "wildcard_holder", "permission": "*/*/*", "gains": "this SA already holds cluster-admin equivalence" } ], "remediation": "Drop `create pods` from foo/builder-bot's role, OR move that workload off kube-system." } ``` HTML 报告将其渲染为一张包含每条边技术解释的逐跳卡片;SARIF 输出将链条保留在 `properties.escalationPath` 字段中,以便进行 IDE 集成。KUBE-ESCAPE-001:带有 hostPath 挂载的特权容器
``` { "id": "KUBE-ESCAPE-001:default:debug-shell", "rule_id": "KUBE-ESCAPE-001", "severity": "CRITICAL", "score": 9.5, "category": "privilege_escalation", "resource": { "kind": "Pod", "namespace": "default", "name": "debug-shell" }, "title": "Privileged container in default/debug-shell", "evidence": { "container": "debug", "securityContext": { "privileged": true }, "volumeMounts": [{ "name": "host-root", "mountPath": "/host", "hostPath": "/" }] }, "remediation": "Drop `privileged: true`; replace hostPath `/` with the specific files via ConfigMap / Secret / CSI." } ```KUBE-RBAC-OVERBROAD-001:组直接绑定到 cluster-admin
``` { "id": "KUBE-RBAC-OVERBROAD-001::ops-team-admin", "rule_id": "KUBE-RBAC-OVERBROAD-001", "severity": "CRITICAL", "score": 9.0, "category": "privilege_escalation", "subject": { "kind": "Group", "name": "ops-team" }, "title": "Group ops-team is bound to cluster-admin", "evidence": { "clusterRoleBinding": "ops-team-admin", "roleRef": "cluster-admin" }, "remediation": "Replace cluster-admin with a least-privilege role scoped to what ops-team actually needs." } ```标签:CLI, CSV导出, EVTX分析, Go, HTML报告, Kubesplaining, Pod逃逸, RBAC, Red Teaming, Ruby工具, SARIF, WiFi技术, 协议分析, 反取证, 图谱分析, 子域名突变, 安全扫描, 安全评估, 容器逃逸, 恶意样本开发, 日志审计, 时序注入, 权限提升, 特权升级分析, 请求拦截