refactor: remove the runtime binary binding; every release registration path verifies the CI signature [CI]
ci/woodpecker/push/main-amd64-build Pipeline was successful
ci/woodpecker/push/main-amd64-build Pipeline was successful
The hash a node reports about itself cannot be trusted (a swapped binary can copy the old hash), so the runtime binding only caught files that were replaced by something that did not lie. Provenance stays where it can be verified: the signed release manifest (digest) and the signed SHA256SUMS. - Remove BinaryBindingService, the node_bindings table (schema v15 drops it), BinaryPolicy, the handshake hash/manifest fields and the admin binary column. - Drop the per-platform "binaries" list from the release manifest, the hash scripts and the updater's installed.manifest copy. - ReleaseService.PublishAsync now verifies the release signature, so the admin POST /releases route is no longer an unsigned path; tests sign with a test key. - Docs: section 16 explains why the runtime check is gone.
This commit is contained in:
1 parent
a4f3d1892a
commit
904ea2b0ae
49 files changed
+115
-1143
No files matched your search
+12
-23
@@ -10,7 +10,7 @@
|
||||
|
||||
```text
|
||||
两个根,各管一摊
|
||||
根 A:CI(代码) 发布公钥写在安装脚本和节点二进制里
|
||||
根 A:CI(代码) 发布公钥写在安装脚本、宿主机更新器的本机配置和 Backend 里
|
||||
└─ CI 签名的发布清单 → 镜像 digest → 节点跑的二进制;安装脚本的 SHA-256 也记在清单里,并公布在发布页
|
||||
假设:CI(Woodpecker、Gitea、镜像仓库、发布密钥)可信;CI 被攻破等于能给所有节点签恶意更新
|
||||
根 B:你的 passkey(运维)
|
||||
@@ -32,9 +32,9 @@
|
||||
|
||||
**发布密钥可以换**:见 `docs/deployment.md` 的「换发布密钥」;回滚已经由清单的 `seq` 防住(更新器只收比已安装更大的)。
|
||||
|
||||
**节点二进制绑定**(第 16 节):节点第一次握手成功的那一刻,Backend 把它正在运行的二进制的 SHA-256 绑定到这个节点;之后哈希对不上、又不在 CI 签名的更新清单里,就拒绝连接。
|
||||
**运行中的二进制不做校验**(第 16 节):节点自报的哈希不可信,来源证明在安装时(签名的清单和 `SHA256SUMS`)。
|
||||
|
||||
**还没有的**:吊销表;任务和配置内容的操作员签名;节点向别人**证明**自己没有撒谎(二进制绑定抓的是文件被换、降级、起了不对的二进制,抓不到故意照抄哈希的恶意二进制,见第 16 节);extension 本身和属主的 `controllers`、接收者的实际加密(只是被固定在节点本地,没有行为)。
|
||||
**还没有的**:吊销表;任务和配置内容的操作员签名;节点向别人**证明**自己运行的就是官方二进制(需要容器之外的背书,见第 16 节);extension 本身和属主的 `controllers`、接收者的实际加密(只是被固定在节点本地,没有行为)。
|
||||
|
||||
## 1. 名词
|
||||
|
||||
@@ -428,8 +428,6 @@ curl -fsSL https://panel/install -o /tmp/moshiro-install.sh && echo "<sha256> /
|
||||
|
||||
**② 镜像按 digest 拉取,二进制按 SHA-256 校验**
|
||||
- 脚本向面板取已签名的清单(和更新用的是同一份,发布密钥签名、`seq` 防回滚),用**脚本里内置的发布公钥**验签,再按清单里的 digest 拉镜像(`repo@sha256:…`);原生二进制则核对清单里的 SHA-256 再安装。Backend 改不了 digest,最多让节点装到一个旧的合法版本。
|
||||
- 发布公钥因此既在脚本里,也编进 Agent 和 Probe 二进制(一个常量,来自 `packaging/update/release-key.pub.pem`),节点之后的更新由节点自己验,不依赖宿主机更新器和 Backend 转发的内容。发布密钥轮换时,新公钥必须由旧密钥签名的清单带下来,否则节点不认。
|
||||
- 更新建议要求**双签**:CI 的发布签名,加操作员 passkey 对清单摘要的批准签名。只攻破 CI 或只攻破 Backend 都不够。
|
||||
|
||||
**③ 其余**
|
||||
- 角色(Agent 还是 Probe)、镜像仓库地址仍由代码决定,但镜像身份由签名清单决定。
|
||||
@@ -486,25 +484,16 @@ curl -fsSL https://panel/install -o /tmp/moshiro-install.sh && echo "<sha256> /
|
||||
11. 节点预算的数字(常驻内存 ≤ 1 MB、二进制 ≤ 150 KB、每个成员验证 ≤ 100 毫秒、成员上限 256)是否合适;超出预算时优先砍什么(比如先去掉操作员集合的 64 个凭证上限换成更小的)。
|
||||
12. webhook 和数据拉取的配额默认值(每分钟请求数、每天行数)和事件清单。
|
||||
|
||||
## 16. 节点二进制绑定
|
||||
## 16. 运行中的二进制不做校验
|
||||
|
||||
目的:被换掉的、版本被改的、降级的二进制,不能继续当这个节点运行。
|
||||
曾经做过「节点二进制绑定」:节点握手时自报正在运行的二进制的 SHA-256,Backend 在第一次握手时绑定,之后对不上就标红或拒绝。**已经移除。**
|
||||
|
||||
```text
|
||||
CI 构建:算出镜像里节点二进制的 SHA-256,写进签名的清单(binaries)
|
||||
宿主机更新器:把验过的清单和签名写进节点只读挂载的 update-status/(installed.manifest、installed.sig)
|
||||
节点握手(auth 里):binary = 正在运行的二进制的哈希(Linux 读 /proc/self/exe,是进程启动时映射的那个映像)
|
||||
release、release_sig = 上面那份清单和签名
|
||||
Backend:
|
||||
① 第一次握手成功 → 绑定 (节点, 哈希, 清单 seq)
|
||||
② 以后每次握手:哈希和绑定一致 → 放行
|
||||
③ 不一致 → 必须是一份 CI 签名清单(用内嵌的发布公钥验)里列出的官方二进制,并且清单 seq 不低于绑定时的(合法升级,改绑);
|
||||
否则拒绝连接,节点页标红「不符」。不许降级。
|
||||
```
|
||||
原因:哈希和清单都是节点自己报的。一个被换进来、故意撒谎的二进制可以照抄原来的哈希和清单,Backend 分辨不出——上报者就是被怀疑的对象。这一层只能抓到「文件被换了、但程序本身没撒谎」的情形,却让人误以为有保障,还要求运维宿主机更新器、状态卷和每个节点的清单。得不偿失。
|
||||
|
||||
- **清单是节点带来的**,Backend 自己验签,所以不依赖面板有没有收到过这次发布;被攻破的 Backend 也加不进「官方」哈希(没有 CI 私钥)。
|
||||
- **旧节点**(不上报哈希):没绑定过就放行(显示未绑定);绑定过的不许退回不上报。
|
||||
- **没有更新器的节点**(二进制安装)没有清单,首次握手按上报的哈希绑定(显示「首次绑定」);手工升级之后哈希变了,会被拒绝,管理员在「系统 → 版本」点「接受当前二进制」清除绑定,下一次连接重新绑定。
|
||||
- **策略** `MoShiro__BinaryPolicy`:`enforce`(默认)拒绝;`warn` 只记录不拒绝;`off` 不检查。
|
||||
- **边界**:哈希是节点自己报的。一个被换进来、故意撒谎的恶意二进制可以照抄原来的哈希,Backend 分辨不出——上报者就是被怀疑的对象。要堵这一点,必须让容器之外的东西背书:宿主机更新器用安装时绑定的密钥对「当前运行的镜像 digest + 挑战」签名,由 agent 转发;容器里的进程被换掉也伪造不了。这一步还没做。
|
||||
「这个资产是我们的」靠**安装时的来源证明**,那里的哈希来自另一个信道,伪造不了:
|
||||
|
||||
- 安装脚本(SHA-256 记在签名的清单里,并公布在发布页),按清单里的 digest 拉镜像(`repo@sha256:…`);
|
||||
- 下载压缩包的人用签名的 `SHA256SUMS` 核对(验签用 `packaging/update/release-key.pub.pem`);
|
||||
- 节点的更新由宿主机更新器用本机公钥验签,只认本机配置的镜像仓库。
|
||||
|
||||
要让运行中的二进制真的无法伪造,必须有容器之外的东西背书:宿主机更新器持有一把节点进程读不到的密钥,对「当前运行的镜像 digest + Backend 的挑战」签名,由节点转发;容器里的进程被换掉也伪造不了,除非攻破宿主机。这一步没有做(一键容器安装的节点也没有宿主机更新器)。
|
||||
Reference in new issue
Block a user