rotavori/dasel-melange-apko
GitHub: rotavori/dasel-melange-apko
基于Go语言的dasel工具构建的最小化APK镜像,用于安全测试和评估。
Stars: 0 | Forks: 0
# dasel v3.3.1 — Melange + apko 构建,针对 CVE-2026-33320 补丁
此仓库将 `dasel` CLI(v3.3.1)打包为
APK,使用 **Melange** 构建,使用 **apko** 构建最小化容器镜像,并在保持 v3.3.1 代码库(补丁,不是版本升级)的同时应用针对
**CVE-2026-33320** 的修复。
结果是包含仅静态 `dasel` 二进制的 ~4 MB 镜像——没有 shell,没有包
管理器,没有 libc——以非 root 用户运行。
## 仓库布局
```
melange/
dasel.yaml # melange recipe: fetch v3.3.1, apply the patch, build the .apk
apko/
dasel.yaml # apko recipe: assemble a minimal image from the local .apk
patches/
cve-2026-33320.patch # the CVE fix (minimal backport of upstream 282943b onto v3.3.1)
NOTES.md # what the CVE is, severity, and how the fix works
tests/
test.sh # runs the built IMAGE and asserts real behavior + the CVE fix
README.md
```
## 前置条件
- Linux 或 **WSL2 Ubuntu**(在 Windows 10 的 WSL2 上开发)。
- **Docker**——用作 Melange 的构建沙盒运行者和加载/运行最终镜像。
- `PATH` 上的 **`melange`** 和 **`apko`**。
开发期间使用的版本:
| 工具 | 版本 |
|---|---|
| melange | 0.50.8 |
| apko | 1.2.14 |
| Docker | 29.5.2 |
所有以下命令都在仓库根目录下运行。
## 构建 & 测试 — 精确命令
### 1. 生成签名密钥(一次性)
```
melange keygen
```
生成 `melange.rsa`(私钥)和 `melange.rsa.pub`(公钥)。两者都是 git 忽略的——密钥由
whoever reproduces the build 重新生成,永远不会提交。
### 2. 构建 package
```
melange build melange/dasel.yaml \
--source-dir patches \
--signing-key melange.rsa \
--arch x86_64 \
--runner docker
```
`--source-dir patches` 使 `patches/cve-2026-33320.patch` 在构建沙盒内部可用,
其中 recipe 的 `patch` 步骤应用它。输出:`packages/x86_64/dasel-3.3.1-r0.apk`
(已签名)和 `packages/x86_64/APKINDEX.tar.gz`。
### 3. 测试 package
`melange test` 将新构建的 `.apk` 安装到干净的环境中,并运行 recipe 的
`test:` 块。它需要 Wolfi 仓库(用于 `busybox`)和我们的本地 `packages/` 仓库(用于
`dasel`),每个仓库都有自己的签名密钥:
```
melange test melange/dasel.yaml dasel \
--arch x86_64 --runner docker \
--repository-append https://packages.wolfi.dev/os \
--keyring-append https://packages.wolfi.dev/os/wolfi-signing.rsa.pub \
--repository-append "$(pwd)/packages" \
--keyring-append melange.rsa.pub
```
断言:`dasel version` 报告 3.3.1;一个真实的 JSON 查询;一个 JSON→YAML 转换;以及一个
billion-laughs YAML bomb 被扩展保护器 **拒绝**(CVE-2026-33320 已修复)。
### 4. 构建 image
```
apko build apko/dasel.yaml dasel:test dasel.tar --arch x86_64
docker load < dasel.tar
```
输出:`dasel.tar`(一个可加载的 OCI 镜像)以及一个 SBOM(SPDX JSON)。apko 将架构添加到标签中,因此加载的镜像为 **`dasel:test-amd64`**。
**如何使 image 消耗本地构建的 package(关键约束)。** `apko/dasel.yaml`
将 `./packages` 列为仓库,将 `./melange.rsa.pub` 列为密钥环。因此 apko 安装了
`melange build` 写入 `packages/x86_64/` 的确切 `dasel` APK——与我们的签名密钥进行验证——而不是
预构建的上游 package。(从仓库根目录运行 `apko build`,以便这些相对路径解析。)这是将 package 构建
与 image 构建连接起来的方式。
### 5. 运行 image 测试
```
./tests/test.sh
```
通过 `docker run` 运行 image 并断言(5 个检查):dasel 存在并报告 v3.3.1,一个嵌套的 JSON 查询,一个 JSON→YAML 转换,一个数组索引查询,以及 YAML bomb 被拒绝。如果任何检查失败,脚本将以非零退出(因此可以控制 CI)。使用 `IMAGE= ./tests/test.sh` 覆盖标签。
## CVE-2026-33320 修复
`CVE-2026-33320` 是 dasel YAML 读取器中的拒绝服务(CWE-674,未受控递归):
通过无界 YAML **别名扩展** 的 "billion laughs" 攻击。dasel 实现了自己的
`UnmarshalYAML` 并递归地解决别名节点,没有限制,绕过了底层库的内置保护。
我们仅将上游修复(提交 `282943b`,包含在 v3.3.2 中)回滚到 v3.3.1 源代码作为 `patches/cve-2026-33320.patch`。它使用 **深度限制(32**)和共享的 **预算(1000**)来限制扩展,在无限制扩展时返回错误。我们故意排除与 v3.3.2 中一起发货的无关的 bug 修复,以保持更改最小化和可审计。有关完整详细信息,请参阅 `patches/NOTES.md`。
## 设计决策
- **固定源。** `git-checkout` 将 `expected-commit` 固定到 v3.3.1 的提交 SHA,因此如果标签
重新指向不同的代码,构建将失败(供应链安全)。
- **最小补丁。** 仅应用 CVE 修复——没有其他内容——以提高可审计性。
- **静态二进制。** 使用 `CGO_ENABLED=0`(在 recipe 的构建环境中设置)构建,因此二进制文件没有 cgo 和共享库依赖项——这是使 image 能够不包含 libc/shell/package-manager 的原因。
- **最小 image。** apko 的 `packages:` 列表仅包含 `dasel`;image 仅安装我们
本地构建的 package(使用我们的 `melange.rsa.pub` 进行验证)。
- **非 root。** image 以 uid 65532 (`nonroot`) 运行,以进行深度防御。
- **签名。** package 和 package 索引都进行了签名;apko 验证签名。
## 假设
- 仅针对 `x86_64` 构建(开发机器的架构)。
- 使用 `docker` 作为 Melange 的运行者(在原生 Linux 上 `bubblewrap` 也可以工作)。
- image 不携带基础布局 package(因此没有 `/etc/os-release`);image
中没有任何内容需要它。这是一个故意的最小化选择,可以通过添加
`wolfi-baselayout` 轻易地逆转。
- 构建拉取 Wolfi 的滚动 `go` 和 `busybox` 而不是固定的快照,因此它假设
Wolfi 一直提供 Go ≥ 1.25(dasel 的 `go.mod` 要求)。dasel 的 *source* 通过提交进行固定;固定构建工具链
会使构建完全密封(见下文)。
## 我会利用更多时间改进的内容
- 将上游的精确边界单元测试(深度 32 vs 33,预算 1000 vs 1001,多文档
预算重置)移植,以获得比我们的黑盒预算/深度炸弹测试更细的覆盖范围。
- 固定构建工具链(特定的 Wolfi `go`/`busybox` 快照)和固定的构建日期,以实现完全密封、位对位的可重复构建(源代码已经通过提交进行固定)。
- 多架构构建(`aarch64`)用于 ARM 机器。
- 使用 cosign 对 image 进行签名,并验证 melange/apko 发布二进制文件的签名。
- 一个 CI 工作流程(GitHub Actions)以在每次推送时重新构建和运行两个测试套件。
## 提交说明
- 所有上述命令都在 WSL2 Ubuntu 上使用 Docker Desktop 运行并通过 **pass**。
- `melange build` + `melange test`:package 构建,补丁干净地应用(所有 7 个 hunks——1 个在
`parsing/yaml/yaml.go` 中,6 个在 `parsing/yaml/yaml_reader.go` 中),所有 package 测试绿色,包括
CVE 炸弹测试。
- `apko build` + `tests/test.sh`:image 构建(~4 MB 内容),所有 5 个 image 测试绿色。
- 上面的 "我会利用更多时间改进" 部分列出了我会有更多时间时将采取的下一步行动。
标签:APK, apko, CVE-2026-33320, Dasel, Docker, GitHub Advanced Security, Melange, WSL2, 云安全监控, 安全加固, 安全防御评估, 容器镜像, 日志审计, 最小化镜像, 漏洞修复, 网络安全培训, 请求拦截, 静态分析, 非root用户