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)。
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
标签:Docker镜像, EVTX分析, Go, Python工具, Ruby工具, TCP SYN 扫描, Web UI, 多模态安全, 子域名突变, 日志审计, 系统内核, 请求拦截, 运维监控