Geogboe/boxy

GitHub: Geogboe/boxy

Boxy 是一个资源池化与沙盒编排工具,通过预先预热 VM 和容器资源池实现按需秒级沙盒环境交付。

Stars: 1 | Forks: 0

# Boxy Boxy 是一个资源池化和沙盒编排工具。它预先配置 VM、容器和其他资源池,然后将它们组装成按需提供的沙盒,用于实验室、培训、渗透测试和开发环境。 ## 安装 Windows PowerShell、Linux 和 macOS 均提供了发布版安装程序。它们会下载最新发布的 GitHub 版本,根据已发布的 `checksums.txt` 对其进行验证,并将其安装到用户本地的 bin 目录中。 Windows PowerShell: ``` irm https://raw.githubusercontent.com/Geogboe/boxy/main/scripts/install.ps1 | iex ``` Linux / macOS: ``` curl -fsSL https://raw.githubusercontent.com/Geogboe/boxy/main/scripts/install.sh | sh ``` 有关支持的平台、版本固定、环境覆盖、PATH 行为和验证的详细信息,请参阅 [docs/install.md](docs/install.md)。 ## 工作原理 Boxy 会提前保持通用且即用型资源池处于热备用状态。当用户请求沙盒时,会从池中抽取资源,并通过 hooks 进行个性化设置——设置凭据、配置网络并返回连接信息。用户使用其原生客户端(SSH、RDP、SMB 等)进行连接。Boxy 不是代理。 ``` ┌──────────────────────────────────────────┐ │ boxy serve │ │ │ │ REST API (CLI) gRPC server (agents) │ │ │ │ │ │ ┌────▼───────────────────▼────────────┐ │ │ │ Core: Pool Manager, Sandbox Mgr │ │ │ │ PolicyController (reconciler) │ │ │ └─────────────────┬───────────────────┘ │ │ │ │ │ ┌─────────────────▼───────────────────┐ │ │ │ Embedded local agent │ │ │ │ (Docker, Hyper-V drivers) │ │ │ └─────────────────────────────────────┘ │ └──────────────────────────────────────────┘ Remote host: ┌──────────────────────────────────────────┐ │ boxy agent │ │ gRPC → server | auto-discovered │ │ | provider drivers │ └──────────────────────────────────────────┘ ``` ## 核心领域模型 **Resource** — 已配置实例(VM、容器、共享、网络等)的运行时记录。具有 ID、类型、状态、提供者句柄和属性。资源是一次性的:一旦分配给沙盒,它们就永远不会返回到池中 (ADR-0002)。资源还保留不可变的池来源,以便 daemon 即使在分配将它们从就绪清单中移除后也能对容量进行评估。 **Pool** — 命名的、同质的、预配置的资源清单。在配置中声明。每个池都带有自己的配置(`type` 标识提供者/驱动程序,`config` 是由驱动程序解释的不透明数据块)和策略(预热、回收)。池即是规范——没有单独的“蓝图”、“模板”或“规范”实体。 **Sandbox** — 一个面向用户的环境,包含从池中提取的 1..N 个资源。沙盒创建在服务器端是异步的:API 在 `pending` 状态下持久化沙盒请求,reconcile 循环履行该请求,并且沙盒转换为 `ready` 或 `failed`。当资源从池转移到沙盒时,会运行分配后 hooks 以对其进行个性化设置(设置凭据、配置网络等)。Boxy 向用户返回连接信息;它不是代理。 **Provider** — 提供资源的外部系统(Docker、Hyper-V、Podman、VMware 等)。提供者具有映射到驱动程序的类型。提供者连接详细信息(socket、host、certs)由 agent 拥有,而不是服务器。驱动程序会尽可能自动发现其环境。 **Driver** — 知道如何与特定提供者类型通信的代码。解释池的预配配置。位于 `pkg/providersdk/drivers/` 中。驱动程序会自动发现其环境(例如,Docker 检查本地 socket,Hyper-V 通过 PowerShell 发现)。池的 `type` 字段直接映射到驱动程序(例如,`type: docker` → Docker 驱动程序,`type: hyperv` → Hyper-V 驱动程序)。Docker 池在首次预配时会自动拉取缺失的镜像,而无需手动执行 `docker pull`。 **Agent** — 使用驱动程序执行提供者操作的运行时实体。可以是: - **Embedded (local):** 在 `boxy serve` 内部运行,处理在 `server.providers` 中声明的提供者。 - **Remote (distributed):** 在单独的主机上运行,通过 TLS 上的 gRPC 连接到服务器,自动发现本地提供者。在 `agents:` 配置部分中声明,以便服务器知道预期内容。 Agent 是执行层——Boxy 核心通过 agent 委托所有提供者 IO,从不直接委托给驱动程序。`Provisioner` 接口是 agent 的接缝。 **PolicyController** — 协调器。在 `boxy serve` 内以 tick 为周期运行。将期望的池状态(来自策略)与实际状态进行比较,并通过 agent 触发预配/销毁。无状态且幂等——每个 tick 都会从头重新推导所需内容。一个控制器协调所有池。 **Hooks** — 在事件发生后运行的副作用通知。不属于控制流——hooks 用于“资源已预配 -> 发送 webhook”或“沙盒已分配 -> 设置凭据”,而不是用于触发预配本身。位于 `pkg/hooks/` 中。 ## 架构 ### Server、CLI 和 Agent(类 Vault 模型) 单个二进制文件 (`boxy`),三种模式: ``` boxy serve — daemon: pool reconciler, REST API, gRPC agent server boxy — CLI client: talks to daemon via REST boxy agent — distributed agent: connects to server via gRPC ``` **REST API** — 用于 CLI 到服务器的通信。标准 HTTP REST。 **gRPC over TLS** — 用于 agent 到服务器的通信。双向流:agent 拨号连接到服务器(对 NAT/防火墙友好),服务器通过流推送工作。 ### 池路由 池的 `type` 字段标识提供者类型(例如,`docker`、`hyperv`、`podman`、`vmware`)。系统将工作路由到具有匹配提供者的任何 agent(嵌入式或远程)。抽象资源类别(容器、VM)是从驱动程序的功能中派生的,而不是在池上声明的。 如果多个 agent 支持相同的提供者类型,系统会选择一个有能力的 agent。池上的可选 `agent:` 字段可以在需要时将其固定到特定的 agent。 ### 协调流 ``` serveLoop ticker └─ PolicyController.Reconcile(pool) observes: pool has 1 ready, policy says min_ready=3 gap: need 2 more └─ pool.Manager.EnsureReady(pool, count=2) └─ Provisioner.Provision(pool) ← agent impl └─ driver.CreateVM / CreateContainer ``` ### 池构建缓存(跨池资源复用) 预配器可以从其他池中“窃取”多余的资源,当它们共享兼容的配置时,而不是从头开始构建。兼容性在运行时自动发现——池之间不需要显式的 `base:` 引用。 **匹配规则:** - 相同类型,配置是子集 → 缓存命中 - 仅限盈余:仅当 `X.ready > X.policy.preheat.min_ready` 时才从池 X 窃取 - 如果找到匹配项,则提取资源并应用增量(安装包、配置等) - 如果没有匹配项,则从头开始构建 配置比较是结构性的——Boxy 核心比较不透明的配置数据块,而不理解其内容。YAML 锚点 (`&`/`*`) 可用于配置文件中的 DRY(不要重复自己),而不会创建 Boxy 级别的耦合。 ### 分配后 Hooks 当资源从池转移到沙盒时,会运行 hooks 进行个性化设置: - 设置用户凭据 - 配置主机名/网络 - 应用沙盒特定策略 池中的资源是有意保持通用的(没有特定用户,没有凭据)。Hooks 在分配时使它们变得具体。这意味着凭据在分配之前不存在——它们由 hook 生成/设置,并作为连接信息返回。 ### 异步沙盒 API 流程 沙盒创建是一个服务器端的异步工作流: 1. 客户端 `POST` 沙盒请求到 `/api/v1/sandboxes` 2. 服务器持久化沙盒并返回 `202 Accepted` 和 `status: "pending"` 3. Daemon reconcile 循环预配并分配资源 4. 客户端轮询 `GET /api/v1/sandboxes/{id}`,直到状态变为 `ready` 或 `failed` 创建 API 使用资源请求而不是已分配的资源 ID: ``` { "name": "pentest-lab", "requests": [ {"type": "container", "profile": "kali", "count": 3}, {"type": "container", "profile": "ubuntu-targets", "count": 1} ] } ``` ### 沙盒访问模型 Boxy 不是代理。当沙盒达到 `ready` 状态时,Boxy 返回每个资源的连接信息: - Linux VM 的 SSH 主机/端口/密钥 - Windows VM 的 RDP 地址 - 文件共享的 SMB 路径 - 容器 exec/attach 详细信息 - 等等 用户使用其原生客户端进行连接。连接信息由分配后 hooks 生成。 ## 配置 ### 服务器配置 (`boxy.yaml`) 三个顶级部分:`server`(嵌入式 agent 和服务器设置)、`agents`(服务器期望的远程 agent)和 `pools`(应该运行的内容)。 ``` server: listen: ":9090" providers: [docker, hyperv] agents: - name: build-host providers: [docker] pools: - name: win2022-base type: hyperv config: &win2022 template: "Windows Server 2022 Standard" generation: 2 cpu: 4 memory_mb: 8192 disk_gb: 80 network_switch: "LabSwitch" policy: preheat: min_ready: 5 max_total: 10 recycle: max_age: 168h - name: kali type: docker config: image: kalilinux/kali-rolling command: ["/bin/bash"] policy: preheat: min_ready: 3 max_total: 8 ``` **关键设计决策:** - `server.providers` 声明嵌入式本地 agent 处理的内容。驱动程序自动发现连接详细信息(socket 路径、PowerShell 等)——不需要连接配置。 - `agents:` 声明服务器应期望的远程 agent。如果已声明的 agent 未连接,服务器可以发出警告/警报。远程 agent 通过 GitHub issue 跟踪器中跟踪的 token 引导流程进行身份验证。 - 池 `type` 是提供者类型(`docker`、`hyperv`、`podman`、`vmware`)。它直接映射到驱动程序并确定路由。抽象资源类别(容器、VM)派生自驱动程序的功能。 - 池 `config:` 是由驱动程序解释的不透明数据块。不同的提供者公开不同的配置选项。 - 规范/蓝图不是一个单独的实体。池以内联方式拥有其预配配置。 - 配置是无状态且声明式的。运行时状态(资源、沙盒)位于状态存储 中。配置在启动时读取。 ### 池策略结构 ``` policy: preheat: min_ready: N # target number of ready resources max_total: N # hard cap across ready + allocated resources from this pool recycle: max_age: "168h" # destroy and replace unused resources older than this ``` 实现说明:预热/回收规划逻辑有意保留在 `internal/pool` 中(不作为公共 `pkg/` API 公开),因为此策略 是 Boxy 特定的领域行为,而不是通用的可重用 SDK 契约。 ### 沙盒定义 (`.sandbox.yaml`) 沙盒类在单独的文件中定义,而不是在服务器配置中。沙盒定义指定从哪些池提取资源以及提取多少: ``` # pentest-lab.sandbox.yaml name: pentest-lab resources: - pool: kali count: 3 - pool: ubuntu-targets count: 1 ``` 沙盒通过 CLI 实例化: ``` # 从文件 (主路径) boxy sandbox create -f pentest-lab.sandbox.yaml # 在 daemon 接受请求后返回,而不是等待 ready/failed boxy sandbox create -f pentest-lab.sandbox.yaml --no-wait ``` 基于文件的路径是主要的、可重复的、版本控制的方式。CLI 将规范中的池引用编译为 daemon API 请求,将它们提交给 `boxy serve`,并默认等待终端沙盒状态。如果匹配的池已耗尽其 `max_total` 硬上限,沙盒请求将以 `status: "failed"` 失败,而不是超出上限进行预配。 有关完整配置,请参见 [examples/](examples/)。 ## 状态存储 **bbolt**(纯 Go 嵌入式 K/V)用于运行时状态:资源、沙盒、agent 注册。配置(服务器、agent、池)不存储在数据库中——它在启动时从 `boxy.yaml` 读取。 ## CLI 接口 有关带有标志和示例输出的权威 CLI 参考,请参见 [`docs/cli-wireframe.md`](docs/cli-wireframe.md)。 ``` boxy init — create starter boxy.yaml in current directory boxy serve — start the daemon (API server + reconcile loop) boxy status — check server health and summary boxy config validate — validate config file and exit boxy sandbox create -f — create sandbox from a spec file (waits by default; use --no-wait to return after acceptance) boxy sandbox list — list sandboxes boxy sandbox get — get sandbox details boxy sandbox delete — delete a sandbox ``` **计划中(尚未实现):** ``` boxy agent list — list agents and connection status boxy agent token create — create registration token boxy agent revoke — revoke an agent ``` 池是配置驱动的——没有 `boxy pool create` 命令。池状态可通过 API 和 Web 仪表板观察。 ## 项目布局 ``` cmd/boxy/ — entry point internal/ cli/ — CLI command wiring (cobra) config/ — config loading model/ — core domain types pool/ — pool manager + Provisioner interface sandbox/ — sandbox manager store/ — store interface + bbolt impl agent/ — agent types and runner pkg/ hooks/ — hook runner (public, self-contained) policycontroller/ — reconciler (public, self-contained) providersdk/ — driver interface + capabilities (public API for driver authors) drivers/ docker/ hyperv/ process/ resourcepool/ — generic pool data structure (public utility) ``` `internal/` = Boxy 的私有业务逻辑。 `pkg/` = 自包含,没有 `internal/` 依赖。编译器强制执行此边界。 ## 待解决问题 - **配置重载:** 配置更改时需要重启,还是 `boxy serve` 应该监视更改并进行协调?重启更简单;热重载更好。 - **构建缓存的子集匹配:** 对不透明配置数据块进行结构比较,以确定一个是否是另一个的“子集”。确切的语义是什么?浅层键比较是否足够,还是我们需要深度的结构比较? - **CLI 用户身份验证:** 谁被允许请求沙盒?基于 Token?OIDC?目前超出范围? - **多 agent 路由:** 当多个 agent 支持相同的提供者类型时,服务器如何选择?轮询?基于负载?标签?目前,池上的 `agent:` 固定是逃生出口。 ## 状态 早期开发阶段。有关即将开展的工作的设计细节,请参见 GitHub issue 跟踪器。 ## 许可证 TODO
标签:EVTX分析, gRPC, OpenCanary, pocsuite3, Python工具, RDP, REST API, SMB, SSH, 安全测试, 实验环境搭建, 容器管理, 开发环境, 批量测试, 攻击性安全, 日志审计, 沙箱化工具, 虚拟化技术, 虚拟机编排, 请求拦截, 资源池化, 资源预热, 跨平台工具, 软件测试, 错误配置检测, 隔离环境, 靶场环境