跳转到主要内容

Silo 20260903 正式发布

自 20260806 以来的完整版本:以授权建立复制语义、桶级 CORS、串行化桶元数据、与 AWS 对齐的授权和校验和、更安全的 SSE-C 复制、Go 1.27.1,以及最终的 20260903 mcli 与 SILO 组件线。
自 20260806 以来的完整版本:以授权建立复制语义、桶级 CORS、串行化桶元数据、与 AWS 对齐的授权和校验和、更安全的 SSE-C 复制、Go 1.27.1,以及最终的 20260903 mcli 与 SILO 组件线。

发布日期: 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 完整落地。 PUTGETDELETE ?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 兼容错误;CRC64NVMECOMPOSITE 的无效组合被拒绝。
  • 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 versionIdDeleteObject / 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#32PR #37)。
  • 联邦 UploadPartCopy 在公开响应中保留后端 checksum(PR #72)。
  • 站点复制状态按站点计算 metadata 操作,不再把组级结果重复相乘,并将 CORS 作为独立配置字段校验。

missing-bucket shortcut 的完整记录见 ListObjects 必须先证明桶存在,再做优化

桶级 CORS 与请求信任

桶级 CORS 不是只补 handler,而是端到端实现:

  1. S3 XML 类型与 rule matcher 校验协议 grammar 和多规则 preflight;
  2. bucket metadata 保存原始配置,GET ?cors 原样返回;
  3. 外层 middleware 优先使用桶策略,不存在时才回落全局 origin 配置;
  4. 站点复制用带 tombstone 的 LWW register 单独承载 CORS;
  5. 预鉴权查找不加载 metadata、不创建 cache entry;
  6. 启动、已知桶元数据加载失败、删除、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 合同。
  • SetUserStatusSetGroupStatus 按目标状态授权,不再统一检查 enable action。
  • 新建或更新 named policy 与 service-account policy 时,拒绝空的 S3、S3 Tables、KMS ARN namespace、它们的历史序列化形式,以及同时含 ResourceNotResource 的 statement;已存 policy 仍可加载。
  • 已启用的旧 PostgreSQL/MySQL notification target 必须给出 connection string;启动现在以不含凭据的诊断失败,而不是静默丢掉所有 target。
  • MINIO_CONFIG_ENV_FILE parser 保留 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.110
  • silo-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_pipe lint 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 升级。至少完成:

  1. 给确实需要删除显式版本的身份授予 s3:DeleteObjectVersion;凡是用 Deny s3:DeleteObject 防止永久删除的策略,都要同时 Deny 新 action;
  2. 拆分自定义管理策略中的 enable 与 disable grant;
  3. 重新提交 policy 前修正裸 ARN prefix;
  4. 给启用的旧 PostgreSQL/MySQL notification target 增加 connection string;
  5. 核对显式选择 checksum algorithm/type 的应用;
  6. 站点复制组所有成员全部升级后,再创建或修改桶级 CORS;
  7. 回滚前导出 CORS 配置,因为 20260806 不理解该字段;
  8. 分布式集群在一个维护窗口切换所有节点,混合 Silo 二进制无法成组。

对象与纠删码磁盘格式不变,但这不代表混合版本集群受支持。

已知问题与明确延期

以下事项不在本版本修复范围内

  • 条件删除(#10PR #12)。 DeleteObject 忽略 HTTP If-MatchDeleteObjects 忽略每个 <Object><ETag>,都会执行无条件删除。经复审的单对象修复存在于本版本之外,但批量语义和原 PR 都不完整;发布半套 condition contract 比明确延期风险更大。
  • 非 CORS 的多站点配置删除(#77)。 一个站点删除 policy、SSE、tag 或 quota 后,仍持有配置的对端可能把它恢复。单站点不受影响;CORS 使用 tombstone-aware register,也不受此缺陷影响。依赖这些复制删除的部署必须逐站核对。
  • ListMultipartUploads 过滤(#79)。 prefix 类似精确 key 匹配,max-uploadskey-markerdelimiter 尚未完整生效,详见兼容性分析
  • 旧联邦后端 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

  • 完整 cmdinternal 测试套件;
  • 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

之后只有一行代码修复 84e1580a4GetConfig 按需重载成功后清除 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 选择、计算、响应、校验与错误
#32PR #37 missing-bucket listing shortcut 返回 NoSuchBucket
PR #57 所选 client/server stack 已提供 CompleteMultipartUploadResult.ChecksumType

代表性变更

  • 1c9a2431f13e6458d9:实现桶级 CORS 与站点复制
  • 93860345804b097fd9 及 Snowball follow-up:认证复制语义,消除预鉴权 metadata I/O
  • f9f9fa6c932a1b81e4:复现并串行化跨类型桶元数据更新
  • 3b5de82f521646eebd:保证 Object Lock 的 versioning 不变量,覆盖 retention-rule 文档
  • f8b598f1dd2d47a41f:对齐显式版本删除授权
  • b73581b05474cd580174c97d005:认证 SSE-C 零字节与 attributes 读取
  • 7fea6d5a55d152416d7e079ff05d28885d0e:对齐 multipart checksum 行为
  • c0e715977e73436c99ffb70eb37:修复 CopyObject transform、checksum 与 SSE-C rotation
  • 84e1580a4:metadata 按需重载成功后解除 load-failure guard

致谢

本版本吸收了社区贡献者提交的问题与修复方案,也包含分叉自身的安全与兼容性审计。checksum、missing-bucket listing 与显式版本授权等工作都从公开 issue/PR 开始。最终形态还经过对抗性复审:先复现再修复;把继承限制与本轮回归分开;并在与声明对应的树上重跑验证。

完整作者记录见 CONTRIBUTORS.md