greenCircuit/network-policy-visualizer

GitHub: greenCircuit/network-policy-visualizer

一个用于可视化Kubernetes NetworkPolicy覆盖范围的工具,帮助识别未受保护的工作负载和潜在网络暴露。

Stars: 0 | Forks: 0

# 网络策略可视化器 一个用于可视化 Kubernetes NetworkPolicy 覆盖范围的只读工具。将其指向集群,即可获得哪些工作负载可以相互通信的图表——更重要的是,哪些工作负载**完全没有策略**,处于完全开放状态。 ![完整图表](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/e286864aad061757.png) ## 显示内容 一个从您的集群的 pod、服务和 NetworkPolicy 实时渲染的图表。包含两层信息: **状态徽章**标记每个工作负载的有效安全状态。所有徽章均根据选择该工作负载的所有策略的并集计算得出——评估的是规则本身,而不仅仅是列出的规则。 | 徽章 | 状态键 | 触发条件 | |---|---|---| | `WAN⇆` | `internet-full` | 互联网双向可达。**在没有策略的工作负载上也会触发** — 默认开放意味着 pod 可以双向访问 `0.0.0.0/0`。这是“未受保护”的情况。 | | `WAN↑` | `internet-egress` | 入站流量被锁定,但出站流量可访问 `0.0.0.0/0` | | `WAN↓` | `internet-ingress` | 出站流量被锁定,但入站流量允许来自 `0.0.0.0/0` 的流量 | | `LAN⇆` / `LAN↑` / `LAN↓` | `lan-*` | 显式的 `ipBlock` 对等目标指向集群外的私有局域网(非 `0.0.0.0/0`,非 pod/服务 CIDR,非 API 服务器) | | `API↑` | `api-server-egress` | 显式的 `ipBlock` 对等目标匹配已配置的 Kubernetes API 服务器 CIDR | | `⊘` | `air-gapped` | 入站和出站流量均被锁定,**并且**没有互联网/局域网/API 服务器的“逃生通道”存在 | | `⇆` | `cross-namespace` | 对等方的 `namespaceSelector` 指向工作负载自身命名空间以外的命名空间 | | `NS⇆` / `NS↑` / `NS↓` | `ns-full-access` / `ns-egress-access` / `ns-ingress-access` | 策略对等方是一个匹配同一命名空间中所有 pod 的通配符(空的 `podSelector`,没有 `namespaceSelector` 或相同命名空间选择器) | 一个**完全没有徽章**的工作负载是退化情况——它拥有锁定双向流量的策略,但没有检测到“逃生通道”,同时 air-gapped 检查也未触发。通常意味着分类器无法识别的自定义 IP 规则。实践中需要关注的徽章是那些您原本不认为是公开的工作负载上的 `WAN⇆`。 **边** 显示了每个策略实际允许的通信: - 工作负载 → 工作负载(两端都有特定的 pod 选择器) - 工作负载 → 命名空间(对等方通配符折叠为命名空间节点) - 工作负载 → CIDR(`ipBlock` 对等方) - 具有方向性的箭头(入站 / 出站 / 双向) - 同一对工作负载之间的多个策略会合并显示并带有计数 ![选中节点](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/1b2cc81e06061758.png) ## 为什么它很重要 NetworkPolicy 是 Kubernetes 中锁定 pod 间流量的唯一内置方式,但阅读 YAML 很少能告诉你实际暴露了什么: - 策略是**累加的** — 多个规则会叠加,因此单个文件很少能讲述完整的故事。 - 一个**没有策略的工作负载默认是完全开放的**。`kubectl get networkpolicies` 只列出策略,从不列出缺少策略的工作负载。这个差距是不可见的。 - 对等方混合了 podSelector、namespaceSelector、ipBlock 和带有 `except` 列表的 `0.0.0.0/0`。很容易将“看起来已锁定”误认为“实际上已锁定”。 - 跨命名空间的意图不透明——一个在 ns-A 中允许 ns-B 流量的策略,只有在您同时打开两个命名空间的标签时才有意义。 此工具将整个画面呈现在一个屏幕上。 ### 它揭示的潜在风险 任何运行过超过一个集群的人都至少遇到过其中一半问题。此可视化器旨在使每个问题一目了然。 - **默认开放是反向的。** 一个没有策略的 pod 可以与任何地方通信 — 没有警告,没有审计事件,任何仪表板中都没有。图表用 `WAN⇆`(互联网完全访问)徽章标记每个此类工作负载 — 这是首要信号。 - **`podSelector: {}` 意味着匹配*所有*,而不是无。** 人们编写空的选择器意图是“不匹配任何”,却意外允许了整个命名空间。这会显示为从命名空间框发出的粗边。 - **`0.0.0.0/0` 出站流量不能隔离集群内流量。** 每个命名空间中的每个 pod 都在该 CIDR 内 — “允许互联网”在未设置 `except` 列表的情况下静默意味着“允许一切”。互联网徽章仅在规则明确针对外部时才触发。 - **DNS 是出站流量锁定的无声杀手。** 锁定出站流量而不允许 `kube-system` 的 UDP 53 端口,所有出站主机名解析都会失败。图表显示了缺失的边。 - **有效可达性是所有选择器的 OR 结果。** 一个工作负载可能被三个策略选中,每个贡献部分规则。仅靠阅读 YAML 无法可靠地解析此问题。该工具完成了解析并渲染结果。 ## 何时实际使用它 **“我继承了这个集群——什么暴露了?”** 您是团队新人。通过 Helm 安装的一切在 `kubectl get pods` 中看起来都没问题。打开可视化器,切换到一个工作负载命名空间,每个带有 `WAN⇆` 徽章的 pod 都可以从公共互联网访问 — 或者,更常见的是,根本没有策略并默认如此。这些是需要首先询问的工作负载。 **“Helm chart 说它有网络策略——真的有吗?”** 大多数上游 chart 仅为少数组件提供策略。可视化器显示了 chart 命名空间中哪些工作负载最终被覆盖,哪些被 chart 静默跳过。“Loki 有入站策略,Grafana 没有”,无需阅读单个 YAML。 **“安全团队在问哪些可以访问互联网。”** 筛选 `WAN⇆` / `WAN↑` 徽章。每个可以访问 `0.0.0.0/0` 出站流量的工作负载都会亮起。截图,发送。无需跨命名空间 grep 策略 YAML。 **“一个 pod 被入侵了——它本可以访问什么?”** 单击该工作负载。详情面板列出了每条出站边:哪些 pod、哪些命名空间、哪些 CIDR、在哪些端口上。比在事件期间从策略文件重构它更快。 **“我即将添加一个默认拒绝策略——会不会破坏什么?”** 首先针对当前集群运行此工具。任何当前显示 `WAN⇆` 且没有明显原因(即依赖默认开放)的工作负载,就是将要被破坏的东西。在切换默认策略之前,先显式地锁定它们。 **“我想验证租户之间无法相互访问。”** 按命名空间聚合视图将每个命名空间折叠为一个节点。租户命名空间之间的跨命名空间边立即可见 — 或者,理想情况下,不存在。 **“我更改了一个策略——它是否按预期工作?”** 刷新。比较更改前后的徽章和边。无需在脑海中模拟选择器解析。 ## 快速开始 针对您的实时集群: ``` go build -o graph . KUBECONFIG=~/.kube/config ./graph # UI → http://localhost:8080 ``` 该二进制文件内嵌了 UI — 单个静态二进制文件,无需单独部署前端。对集群为只读(它只 `LIST` pod、服务和 NetworkPolicy)。 演示模式(无需集群): ``` DEMO_MODE=true ./graph ``` 从内嵌的 `test-data/` 加载示例数据 — 包含一个真实的 `observability` 命名空间转储,展示了生产环境中实际出现的部分 NetworkPolicy 覆盖情况。 ## RBAC (基于角色的访问控制) 最低权限: ``` rules: - apiGroups: [""] resources: ["pods", "namespaces"] verbs: ["get", "list"] - apiGroups: ["networking.k8s.io"] resources: ["networkpolicies"] verbs: ["get", "list"] - apiGroups: ["batch"] resources: ["cronjobs"] verbs: ["get", "list"] ``` ## 开发 ``` go test ./... # unit tests for graph logic (no cluster needed) cd ui && npm install && npm run dev # Vite dev server on :5173, proxies /api → :8080 ``` 前端发送 `?namespaces=a,b`,后端仅查询这些命名空间。每个命名空间的获取是并发运行的。没有监视,没有缓存层 — 每个请求都直接访问 API 服务器,因此画面始终是实时的。 更多详细信息,请参阅 [`docs/architecture.md`](docs/architecture.md) 和 [`docs/status-key-computation.md`](docs/status-key-computation.md)。开发容器设置位于 [`CLAUDE.md`](CLAUDE.md)。
标签:API服务器暴露, EVTX分析, LAN暴露, Mutation, Web截图, 互联网暴露, 可视化, 命名空间策略, 图形渲染, 子域名突变, 容器安全, 容器编排, 工作负载分析, 微服务安全, 数据可视化, 日志审计, 暴露检测, 策略评估, 网络策略, 读取模式工具