Silo 20260903 正式发布
发布日期: 2026-09-03 · 版本: RELEASE.2026-09-03T00-00-00Z · 上一版本: RELEASE.2026-08-06T00-00-00Z
SILO 20260903 是首个完整使用 Silo 品牌的版本之后的一次安全与正确性发布。它的主线不是新的交付外观,而是一组更严格的服务端不变量:客户端 header 不能凭空获得复制权限;浏览器 Origin 不能在鉴权前触发桶元数据 I/O;并发桶配置写入不能彼此静默覆盖;授权与校验和行为进一步对齐 AWS S3。
本文有意只把 20260806 作为发布基线。中间组件构建仍可在各源码仓库中辨认,但下面的公开文档统一汇总 2026-09-03 交付的服务端、Console、共享包与客户端最终结果。
亮点
- 复制信任来自授权。
X-Minio-Source-Replication-Request与相关内部字段只有在签名验证、精确 marker 校验以及s3:ReplicateObject/s3:ReplicateDelete授权后才获得复制语义。不可信字段在鉴权后清洗,因此不会破坏 SigV4。 - 桶级 CORS 完整落地。
PUT、GET、DELETE ?cors持久化真实桶策略,覆盖服务端全局 fallback,并通过站点复制收敛。预鉴权查找只读驻留元数据;启动期与已知元数据加载失败状态都保持 fail-closed。 - 桶元数据更新串行化。 共享
metadata.lock覆盖所有整记录配置写入、迁移、导入、站点 adoption 与 healing。ForceCreate不再擦除既有配置;存在 Object Lock 文档的桶始终使用纯Enabled版本控制。 - 授权与请求动作一致。 显式删除版本需要
s3:DeleteObjectVersion;用户和组的启用/禁用按目标状态检查对应 action;策略写入拒绝空的 ARN namespace。 - 校验和进一步对齐 AWS S3。 UploadPart 可由服务端计算校验和;联邦
UploadPartCopy返回校验和;multipart completion 返回ChecksumType;非法断言使用 AWS 兼容错误;CRC64NVME与COMPOSITE的无效组合被拒绝。 - SSE-C 读取与复制统一校验密钥。 零字节对象和
GetObjectAttributes不再绕过密钥认证;null-version 改写与原地换钥不会再留下不可读密文或不一致的 checksum metadata。 - 发布前主动减法。 删除死代码与过期 lint 例外;兼容快照只追踪真实对外服务面;依赖锁定到已审 revision;timeout 测试改用私有随机源。
- 客户端版本归入同一基线。 mcli 20260903 新增只读 checksum verify,完成 fail-closed 凭据脱敏,修复 Metrics JSON 与 S3 Select,严格校验策略写入,并提供签名软件包、溯源证明与验证过的 amd64/arm64 镜像。
安全修复
仓库安全台账为五个没有 CVE 的发现分配了稳定的本地编号。SN- 不是 CVE。完整威胁模型、兼容影响与运维动作集中记录在 SILO 20260903 安全说明。
| 编号 | 影响面 | 修复后的不变量 | 运维影响 |
|---|---|---|---|
SN-2026-006 |
SSE-C 零字节对象的读取与复制 | 即使没有 payload block 可解密,也必须认证客户密钥 | 错误密钥返回 403 AccessDenied;正确密钥不变 |
SN-2026-007 |
SSE-C 对象的 GetObjectAttributes |
获取属性需要客户密钥,除非请求确实来自已授权复制对端 | 裸 replication marker 不能跳过密钥认证 |
SN-2026-008 |
读、写、multipart、删除、Snowball、事件中的内部复制字段 | 复制语义需要鉴权与对应复制权限 | 普通客户端携带内部样式 header 时仍按普通 S3 语义处理 |
SN-2026-009 |
管理 API 的用户与组状态变更 | 启用与禁用分别校验不同 action | 过去只授予一个 action 却依赖双向操作的自定义管理策略需要拆分 |
SN-2026-010 |
带 versionId 的 DeleteObject / DeleteObjects |
显式删除版本需要 s3:DeleteObjectVersion |
检查 grant;原本用 Deny s3:DeleteObject 阻止永久删除的策略还需显式 Deny 新 action |
五个缺陷都继承自已归档的上游服务端代码,影响此前所有 SILO 版本。SN-2026-008 是对 CVE-2026-34204 接收端全链路修复的补全。
内嵌 Console v2.3.0 线还包含可信代理边界、TLS 校验修复、响应与日志脱敏、WebSocket 转发上限。Console 独立发布与服务端内嵌仍是可分别核验的制品。
S3 正确性与互操作
Multipart 校验和
本版本关闭了 #46、#47、#48、#50 报告的 multipart 互操作问题组:
- 客户端在创建上传时选择算法、但没有为每个 part 提供 checksum header 时,
UploadPart由服务端计算所选校验和; - 旧版联邦后端的
UploadPartCopy不再丢掉远端返回的 checksum; CompleteMultipartUpload返回ChecksumType,缺失、畸形、矛盾或不支持的 checksum 使用 AWS 兼容错误;- 未知算法以及无效的
CRC64NVME+COMPOSITE组合直接拒绝,不再静默 canonicalize。
实现刻意分层:wire parser 拒绝非法声明,multipart state 记录所选算法和类型,完成阶段再将最终断言与状态比对。没有显式启用额外 checksum 的普通客户端不受影响。
独立证据记录见服务端计算 UploadPart 校验和、multipart completion 错误语义与 ChecksumType 传递。
CopyObject 与 SSE-C
CopyObject 现在会:
- 在可选压缩前对逻辑对象计算 checksum;
- 在响应中返回 checksum 字段;
- metadata-only copy 保留 transform state;
- 用源密钥解密源 checksum metadata,并为目标密钥重写;
- null-version 在任意 pool 方向复制时都不会丢失 current-version metadata;
- 对象层必须改写数据时,正确完成原地 SSE-C 换钥与重加密。
零字节对象与 attributes 修复消除了两个彼此独立的错误假设:“没有数据被解密”曾被等同于“密钥已经认证”。新规则是显式的:访问 SSE-C metadata 或 ciphertext 必须成功解封对象密钥,除非请求已经跨过授权 replica 边界。
CopyObject 状态矩阵与真实互操作证据记录在 CopyObject 的 SSE-C、checksum 与响应正确性。
列举与联邦
- ListObjects 快捷路径在 bucket 不存在且带 prefix 时也返回
NoSuchBucket(#32、PR #37)。 - 联邦
UploadPartCopy在公开响应中保留后端 checksum(PR #72)。 - 站点复制状态按站点计算 metadata 操作,不再把组级结果重复相乘,并将 CORS 作为独立配置字段校验。
missing-bucket shortcut 的完整记录见 ListObjects 必须先证明桶存在,再做优化。
桶级 CORS 与请求信任
桶级 CORS 不是只补 handler,而是端到端实现:
- S3 XML 类型与 rule matcher 校验协议 grammar 和多规则 preflight;
- bucket metadata 保存原始配置,
GET ?cors原样返回; - 外层 middleware 优先使用桶策略,不存在时才回落全局 origin 配置;
- 站点复制用带 tombstone 的 LWW register 单独承载 CORS;
- 预鉴权查找不加载 metadata、不创建 cache entry;
- 启动、已知桶元数据加载失败、删除、refresh 与按需重载都会显式维护 fail-closed 状态。
load-failure 状态是必要复杂度。预签名 URL 用自身签名完成鉴权,不需要 bucket policy;如果服务器忘记“真实桶的 CORS 文档加载失败”这一位信息,再回落宽松全局策略,就会丢掉这个已授权浏览器请求唯一的 origin 边界。
复制请求加固遵循同一原则。服务端先认证原始请求——内部 header 可能属于 SigV4 签名内容——再根据身份与权限得到一个私有 trust decision,最后清洗不可信的 request clone。clone 与原请求共享 trailer map,streaming checksum 不会丢失。Snowball worker 按 entry 推导信任,不继承 request-wide privilege bit。
完整设计与被否决方案记录在 鉴权前不做 I/O,Header 不产生权限。
桶元数据与 Object Lock
桶配置存放在同一个 .metadata.bin 记录中,但此前 policy、lifecycle、encryption、tags、quota、replication、Object Lock 与 CORS 使用彼此独立的锁更新。两个正确的 read-modify-write 因此可能都返回成功,后保存的一方却静默覆盖先前字段。
本版本用一个有界的 metadata.lock transaction 串行化所有整记录 mutation,同一把锁覆盖:
- 常规配置保存与删除;
- 旧元数据 migration 与 import;
- bucket 创建、
ForceCreate与站点 adoption; - healing 与 inconsistent-version repair;
- 只合并变化字段的 replication receive path。
实现没有把元数据系统改造成通用事务框架:既有 record 与 parser 保持不变,只集中 serialization boundary,并将复制导入限制为真正发生变化的字段。
Object Lock 还有第二条不变量:有效 lock 配置解析为 enabled 后,versioning 一律归一化为纯 Enabled;prefix exclusion 与 suspended 状态不能保留。判定依据是解析后的配置,不是与最小 XML 文档做字节比较,因此带 Default Retention Rule 的合法文档也无法绕过。测试覆盖 Update、读回、磁盘重载,以及两种畸形旧 versioning 状态。
IAM、策略与配置行为
- 显式版本删除按 AWS 的
s3:DeleteObjectVersion授权;复制删除保留s3:ReplicateDelete合同。 SetUserStatus与SetGroupStatus按目标状态授权,不再统一检查 enable action。- 新建或更新 named policy 与 service-account policy 时,拒绝空的 S3、S3 Tables、KMS ARN namespace、它们的历史序列化形式,以及同时含
Resource与NotResource的 statement;已存 policy 仍可加载。 - 已启用的旧 PostgreSQL/MySQL notification target 必须给出 connection string;启动现在以不含凭据的诊断失败,而不是静默丢掉所有 target。
MINIO_CONFIG_ENV_FILEparser 保留 named target、引号值与受支持的 shell-like assignment,但不会把文件当 shell 执行。
这些属于兼容性收紧,不是格式迁移。部署前必须阅读升级检查。
详细记录分别覆盖按目标状态授权用户/组操作、安全解析配置环境文件与旧数据库通知迁移的 fail-fast 设计。
组件
20260903 的依赖与配套发布线固定如下:
- Go 1.27.1
minio-go/v7: 上游兼容 pseudo-version,revision 结尾为0e78d3f18efe;临时silo-go分叉从服务端依赖图退役madmin-go/v3:v3.0.110silo-pkg/v3:v3.13.2,使用自有github.com/pgsty/silo-pkg/v3模块路径- 内嵌 Console:
v2.3.0,包含可信代理、TLS、脱敏与 WebSocket 安全修复 - 捆绑 mcli:
RELEASE.2026-09-03T07-13-05Z,保留mc兼容 alias - Helm Chart:
7.0.2,Server 默认使用pgsty/silo:RELEASE.2026-09-03T00-00-00Z,post-install Job 使用pgsty/mc:RELEASE.2026-09-03T07-13-05Z
服务端有意保留 MinIO 兼容的 Go module 与 wire identifier。替换 import target 不会改名公开 S3/Admin API、MINIO_* 配置、x-minio-* header、/minio/* route 或磁盘 metadata。
工程清理
最终发布审查删除了不保护兼容性或正确性边界的复杂度:
- 删除废弃 encryption helper、旧 handler path 与未使用 event-target function;
- 用更小的真实服务 route 兼容基线替代源码级 exported-symbol inventory;
- 删除
wait_pipelint exclusion,迁移到gomodguard_v2; - 用两个 helper 收口 CORS load-failure 生命周期,不在六条路径里分别 open-code set 操作;
- 站点复制 import 只更新发生变化的 metadata 字段;
- dynamic-timeout 测试使用私有随机源,不再修改 package-global seed;
- 保留共享 metadata lock、CORS tombstone、两级 replication trust 与对抗性测试,因为每一项都保护了已复现故障,而不是假设性的抽象。
完整对抗性复审——包括第一次“已就绪”结论之后继续发现并修复的问题——记录在 SILO Server 20260903 发布前复审。
升级检查
生产切换前请阅读从 RELEASE.2026-08-06 升级。至少完成:
- 给确实需要删除显式版本的身份授予
s3:DeleteObjectVersion;凡是用Deny s3:DeleteObject防止永久删除的策略,都要同时 Deny 新 action; - 拆分自定义管理策略中的 enable 与 disable grant;
- 重新提交 policy 前修正裸 ARN prefix;
- 给启用的旧 PostgreSQL/MySQL notification target 增加 connection string;
- 核对显式选择 checksum algorithm/type 的应用;
- 站点复制组所有成员全部升级后,再创建或修改桶级 CORS;
- 回滚前导出 CORS 配置,因为 20260806 不理解该字段;
- 分布式集群在一个维护窗口切换所有节点,混合 Silo 二进制无法成组。
对象与纠删码磁盘格式不变,但这不代表混合版本集群受支持。
已知问题与明确延期
以下事项不在本版本修复范围内:
- 条件删除(#10、PR #12)。
DeleteObject忽略 HTTPIf-Match,DeleteObjects忽略每个<Object><ETag>,都会执行无条件删除。经复审的单对象修复存在于本版本之外,但批量语义和原 PR 都不完整;发布半套 condition contract 比明确延期风险更大。 - 非 CORS 的多站点配置删除(#77)。 一个站点删除 policy、SSE、tag 或 quota 后,仍持有配置的对端可能把它恢复。单站点不受影响;CORS 使用 tombstone-aware register,也不受此缺陷影响。依赖这些复制删除的部署必须逐站核对。
ListMultipartUploads过滤(#79)。prefix类似精确 key 匹配,max-uploads、key-marker与delimiter尚未完整生效,详见兼容性分析。- 旧联邦后端
CopyObject(#99、#100)。 旧联邦后端可能忽略请求的 checksum algorithm,并拒绝 inline source object;不使用该后端的部署不受影响。 - 混合版本站点复制。 20260806 对端会接受但忽略桶级 CORS,并持续报告 mismatch;所有站点升级前不要配置 CORS。
- 回滚桶级 CORS。 20260806 重写 bucket record 时会丢掉未知 CORS 字段;先导出,重新升级后再恢复。
ILM relocation(PR #60)、更广泛的 SSE 支持(#61)、operator 发现(#30)、NATS target 热重载(#40)、Renovate(#20)等开放 enhancement 不属于本版本的生产安全边界。
验证与证据边界
完整本地验收运行在 ebac0ca73bbf251b070bb6df4d8005015841f901:
- 完整
cmd与internal测试套件; go test -race ./cmd,365.448 秒通过;- lint 0 issue、rebrand/compatibility guard、生成文件检查与
govulncheck; make verify覆盖 FS、erasure、分布式 erasure、erasure sets、多池、IPv6 多池:174 PASS / 0 FAIL。
之后只有一行代码修复 84e1580a4:GetConfig 按需重载成功后清除 CORS load-failure bit。后续依赖工作把工具链推进到 Go 1.27.1、把 x/crypto 推进到 0.56.0。在审查过的服务端线上,git diff --check、CORS/Object Lock 定向 race、rebrand guard、生成文件检查、lint、Helm lint/render/package,以及七资源旧版升级身份守卫全部通过;最终发布前 main 线的远端 Go CI 与 VulnCheck 均为绿色。
交付证据保持独立可核验,而不是从这些源码测试推断。服务端 GitHub Release 标识精确标签源码与软件包资产。独立发布的 mcli Release 不可变,包含 19 个已验证资产,并发布一致的 amd64/arm64 版本镜像与 latest;共享包 v3.13.2 与 Console v2.3.0 各自保留独立发布证据。
已解决事项台账
发布准备期间已经完成 tracker 收口:核心问题关闭,刻意排除的工作留在独立 open issue 中:
| 跟踪项 | 解决方案 |
|---|---|
| #102 | 已由合并的 PR #103 关闭:共享 metadata.lock,完整覆盖 writer、migration、adoption;需要先复现的残余审计拆到 #105 |
| #58 | 已由合并的 PR #104 关闭:显式版本授权、multi-delete auth/audit context 与 least-privilege replication;PR #59 作为被替代实现关闭 |
| #46、#47、#48、#50 | Multipart checksum 选择、计算、响应、校验与错误 |
| #32、PR #37 | missing-bucket listing shortcut 返回 NoSuchBucket |
| PR #57 | 所选 client/server stack 已提供 CompleteMultipartUploadResult.ChecksumType |
代表性变更
1c9a2431f至13e6458d9:实现桶级 CORS 与站点复制938603458至04b097fd9及 Snowball follow-up:认证复制语义,消除预鉴权 metadata I/Of9f9fa6c9至32a1b81e4:复现并串行化跨类型桶元数据更新3b5de82f5、21646eebd:保证 Object Lock 的 versioning 不变量,覆盖 retention-rule 文档f8b598f1d至d2d47a41f:对齐显式版本删除授权b73581b05、474cd5801、74c97d005:认证 SSE-C 零字节与 attributes 读取7fea6d5a5、5d152416d、7e079ff05、d28885d0e:对齐 multipart checksum 行为c0e715977、e73436c99、ffb70eb37:修复 CopyObject transform、checksum 与 SSE-C rotation84e1580a4:metadata 按需重载成功后解除 load-failure guard
致谢
本版本吸收了社区贡献者提交的问题与修复方案,也包含分叉自身的安全与兼容性审计。checksum、missing-bucket listing 与显式版本授权等工作都从公开 issue/PR 开始。最终形态还经过对抗性复审:先复现再修复;把继承限制与本轮回归分开;并在与声明对应的树上重跑验证。
完整作者记录见 CONTRIBUTORS.md。