lazybpf/bpf-explorer

GitHub: lazybpf/bpf-explorer

一个集群范围的只读 Web UI,让用户无需逐节点 exec 即可跨 Kubernetes 集群浏览所有节点上的 eBPF maps 和 programs。

Stars: 0 | Forks: 0

# bpf-explorer 一个集群范围、只读的 Web UI,用于跨 Kubernetes 节点浏览 eBPF maps 和 programs,这样你就无需 `kubectl exec` 进入每个节点的 [`bpftool-daemon`](https://github.com/lazybpf/bpftool-daemon) pod 来查看加载了什么。 它作为两个组件运行: - agent (`--role=agent`) - 一个特权 DaemonSet 中的 gRPC server;通过 `cilium/ebpf` 读取 maps 和 programs。 - ui (`--role=ui`) - 一个 Deployment,通过 Kubernetes API 发现 agent 并扇出 gRPC 调用,提供 HTML 服务。仅支持 `ClusterIP`;通过 `kubectl port-forward` 访问。 一个二进制文件同时提供这两种角色;一个镜像运行这两种工作负载。 在一个三节点集群中,每个节点都有一个 agent: ``` flowchart LR op(["Operator"]) subgraph cluster["Kubernetes cluster"] api["Kubernetes API"] ui["ui Deployment
ClusterIP :80 -> :8080"] subgraph n1["node-1"] a1["agent :50051"] k1[("host kernel
maps · progs · links")] end subgraph n2["node-2"] a2["agent :50051"] k2[("host kernel")] end subgraph n3["node-3"] a3["agent :50051"] k3[("host kernel")] end end op -->|"port-forward, HTTP"| ui ui -.->|"list agent pods"| api ui -->|gRPC| a1 ui -->|gRPC| a2 ui -->|gRPC| a3 a1 --> k1 a2 --> k2 a3 --> k3 ``` 镜像发布到 GHCR,支持 `linux/amd64` 和 `linux/arm64`。 ## 快速开始 无需 clone - 为你想要运行 agent 的节点打上标签,并应用附加到最新版本的 manifest: ``` kubectl label node bpf-explorer=true ``` ``` kubectl apply -f https://github.com/lazybpf/bpf-explorer/releases/latest/download/bpf-explorer.yaml ``` 然后 port-forward UI 并浏览 http://localhost:8080: ``` kubectl -n bpf-explorer port-forward svc/bpf-explorer-ui 8080:80 ``` ## 清理 ``` kubectl delete namespace bpf-explorer ``` ``` kubectl label node bpf-explorer- ``` ## 构建 纯 Go - 无 CGO,并且 `gen/` 中的 gRPC stubs 已提交,因此没有 codegen 步骤: ``` go build -o bpf-explorer ./cmd/bpf-explorer ``` Unit tests 不需要集群和特权: ``` go test ./... ``` 镜像。`:dev` 是本仓库中 `bpf-explorer.yaml` 追踪的 tag,因此本地构建可以直接放入 manifest: ``` docker build -t ghcr.io/lazybpf/bpf-explorer:dev . ``` 多架构(交叉编译,无需模拟): ``` docker buildx build --platform linux/amd64,linux/arm64 \ -t ghcr.io/lazybpf/bpf-explorer:dev . ``` ## 使用 `ctr` 加载到 containerd 开发集群 对于运行 containerd 的单节点/开发集群(k3s,kind 的 containerd,裸机 kubeadm 节点),将镜像直接导入 `k8s.io` namespace,以便 kubelet 无需 registry 即可使用它: ``` docker save ghcr.io/lazybpf/bpf-explorer:dev -o /tmp/bpf-explorer.tar sudo ctr -n k8s.io images import /tmp/bpf-explorer.tar && rm /tmp/bpf-explorer.tar ``` 然后应用此仓库的 manifest,它指向带有 `imagePullPolicy: IfNotPresent` 的 `:dev`,因此导入的镜像按原样使用: ``` kubectl apply -f bpf-explorer.yaml ``` ## 在没有集群的情况下本地运行 将 UI 直接指向 agent(静态发现),无需 RBAC。两个终端 - agent 需要 BPF 特权: ``` sudo ./bpf-explorer --role=agent --listen=:50051 ``` ``` ./bpf-explorer --role=ui --agents=local=localhost:50051 ``` 然后浏览 http://localhost:8080。 ## 发布 推送带注释的 tag 是唯一的发布方式。[`release`](.github/workflows/release.yaml) workflow 构建多架构镜像,将其推送到 GHCR 下的 tag 名称下,并打开一个 GitHub release,其说明来自 tag 注释: ``` git tag -a v0.1.0 -m "v0.1.0 - first release" git push origin v0.1.0 ``` 每个版本都附带一份 `bpf-explorer.yaml` 副本,其中的镜像行从 `:dev` 重写为该版本的 tag,因此集群运行的始终是某人打过 tag 的版本。没有 `:latest` 镜像 tag - 没有任何东西是浮动的。 版本是[语义化的](https://semver.org):`vMAJOR.MINOR.PATCH`。修复提升 PATCH,向后兼容的新增提升 MINOR,对 manifest 或 flags 的破坏性变更提升 MAJOR。UI 和 agent 之间的 gRPC 接口是内部的 - 两者都在同一个镜像中发布,因此可以在不提升 MAJOR 的情况下进行更改。 ### 候选版本 连字符会使 tag 成为 pre-release,因此在提升 MINOR 或 MAJOR 之前先做一个候选版本: ``` git tag -a v0.2.0-rc.1 -m "v0.2.0-rc.1 - cursor pagination for DumpMap" git push origin v0.2.0-rc.1 ``` 候选版本特意比正式版本更安静: | Tag | 镜像 | GitHub release | | --- | ----- | -------------- | | `v0.2.0-rc.1` | `:v0.2.0-rc.1` | 标记为 pre-release | | `v0.2.0` | `:v0.2.0` | 最新版本 | 由于 `releases/latest/download/` 会解析到*未*标记为 pre-release 的最新版本,因此 `rc` 永远不会成为快速开始所安装的内容 - 通过显式应用其 manifest 来测试它: ``` kubectl apply -f https://github.com/lazybpf/bpf-explorer/releases/download/v0.2.0-rc.1/bpf-explorer.yaml ``` 使用 `-rc.2`、`-rc.3` 进行迭代……一旦看起来没问题,就从与上一个候选版本相同的 commit 中切出最终的 `v0.2.0`。 ## TODO - `DumpMap` 的游标分页。proto 带有 `cursor` / `next_cursor`,但 server 仅支持 `limit`,因此巨大的 map 是被截断而不是分页的。 - Per-CPU map 值。Per-CPU map 类型的值被渲染为一个不透明的 blob,而不是 Per-CPU slice。 - 基于 Informer 的 agent 发现。UI 在每次页面加载时轮询 Kubernetes API;使用 `SharedInformer` 将降低刷新延迟。 - UI 和 agent 之间的 mTLS。Agent gRPC 在 namespace 内是明文且未经过身份验证的;namespace 隔离加上 NetworkPolicy 是目前的防护栏。 ## License Apache License 2.0 - 见 [LICENSE](LICENSE)。
标签:Docker镜像, EVTX分析, Go, Python工具, Ruby工具, TCP SYN 扫描, Web UI, 多模态安全, 子域名突变, 日志审计, 系统内核, 请求拦截, 运维监控