SILO 20260916 发布注记
旧版分片列举设计已被覆盖 · Earlier multipart-listing designs superseded (2026-10-17)
中文: 本文关于 #79 分片上传列举的旧方案、启用建议与当时进度仅保留为历史记录;后续设计已由最新设计决策(中文)覆盖,请参考新版。新实现已合入主干、尚未随 Server 版本发布;这里记载的旧版本行为和其他主题结论不因此改变。
English: The #79 multipart-listing proposals, enablement advice and status in this article are historical. Subsequent design work is governed by the latest design decision (English), which supersedes those earlier proposals. The new implementation is merged into main and remains unreleased; this does not change the documented behavior of older releases or conclusions on other topics.
版本日期: 2026-09-16 · 正式发布: 2026-09-17(UTC 2026-09-16) · 标签: RELEASE.2026-09-16T00-00-00Z · 软件包版本: 20260916000000.0.0。安装入口见下载页。
源码范围为已发布提交 9b11dc9469e6 到本版 2a4d51406b7e,共 210 个提交,其中 140 个非合并提交。本文覆盖该范围内的最终行为,包含 #214 之后的列表 quorum、版本 purge 和迁移标签修复。Go 1.27.1 等已进入上一正式版的变更不重复列作新增;期间撤回的功能按最终状态说明。
本版重点
- 更完整的请求认证边界: 关闭普通签名与预签名请求的未签名操作头缺口,校验预签名正文摘要,使签名年龄及载荷哈希策略使用可信输入。
- 可持久恢复的 IAM 撤销: 保留删除版本、父身份撤销边界与成员授权时间,防止延迟事件、重建同名身份和重启恢复重新激活旧授权。
- 多池操作针对同一个逻辑对象: 条件 PUT、分片完成、条件 DELETE、指定版本删除及元数据协调使用一致的对象选择和锁边界。
- 池迁移保留标签: rebalance 和 decommission 的普通对象及分片迁移恢复完整标签写入,保留原修订和有序清空状态。
- 修复加密及联邦复制: 保留 SSE-C 原始副本、明文分段大小、独立 Object Lock/标签修订,以及远端实际写入的校验和、版本和时间。
- 复制和配置最终状态更可靠: 修复标签删除复活、删除标记 purge/MRF、resync 计数与取消、桶配置来源时间和删除状态收敛。
- 可选的严格分片发现: 新增持久化扫描、全局分页和只读预检;默认仍为 legacy,容量和迟到创建写入的限制明确保留。
- 更新整套管理工具: 内嵌 Console 2.4.1,捆绑 mcli 20260916,采用 pkg 3.14.1;补齐浏览分页、流式 ZIP、错误退出码和策略正确性。
- 两项必须提前安排的升级变化: 密码权限拆分会改变已有策略的含义;持久 IAM 撤销要求协调升级和完整后端备份。
版本与组件
| 组件 | Server 20260903 | Server 20260916 |
|---|---|---|
| Server | RELEASE.2026-09-03T13-18-01Z |
RELEASE.2026-09-16T00-00-00Z;源码核对点 2a4d51406b7e |
| 内嵌 Console | 源码 464a59d73ada,版本标识 v2.3.0 |
已发布 v2.4.1,源码 1360e26d976d |
| MC 模块 / 镜像内 mcli | 20260903 | 已发布 20260916,源码 e952aa78f10a |
| 共享包 | github.com/pgsty/silo-pkg/v3 v3.13.2 |
v3.14.1,包含 v3.13.3 和 v3.14.0 的累计修复 |
| 上游 S3 SDK | minio-go/v7,revision 0e78d3f18efe |
v7.3.1-0.20260915093545-32e1f32cb176 |
| Go / madmin-go | Go 1.27.1 / v3.0.110 | 保持 Go 1.27.1 / v3.0.110 |
| Helm | 7.0.2 | tag 源码内 Chart 7.0.3;未单独发布 Chart 包或 Helm 仓库 |
本版的 Console 和 MC replacement 分别为 v0.0.0-20260916075814-1360e26d976d、v0.0.0-20260916070421-e952aa78f10a。Go 不继承依赖模块的 replacement,因此 Server 显式选择两者。pkg 直接使用 PGSTY 模块路径;Server、Console、MC 保留现有历史模块身份和协议名称。minio-go/v7 继续使用经过核验的上游版本。
此依赖图由 Server 20260916 明确选用。 单独安装新版 Console、mcli 或 pkg 不会更新已编译进 Server 的组件。正式维护和发布验收面向 SILO + Console + mcli + silo-pkg;与未修改的上游 MinIO/MC 保持尽最大努力兼容。
安全与授权
本轮包含四个本地安全编号;SN- 是项目台账编号,不是 CVE。完整说明见签名头边界及九月安全说明。
| 编号 | 修复与实际边界 | 依据 |
|---|---|---|
| SN-2026-011 | 普通 Authorization 与预签名 SigV4 拒绝未签名的 x-amz-* 操作头,防止签名 PUT 被改造成使用签名者权限的 CopyObject;空首值的多值头也不能绕过 |
#173、#177 |
| SN-2026-012 | 通用认证路径验证仅由 header 提供哈希的预签名正文;摘要不符返回 XAmzContentSHA256Mismatch。这是对持有相应写入 URL 的调用者的约束,不意味着匿名者可任意改桶策略 |
#177 |
| SN-2026-013 | 持久 IAM 撤销和父身份边界防止旧事件、旧子凭据及旧授权跨越保留的撤销历史 | #191、#192 |
| SN-2026-014 | Console 匿名分享代理只接受配置 S3 origin 的对象内容 GET,拒绝跳转、系统路径和选择其他操作的 query | Console #56、Server #209 |
签名配套修复还包括:消除重复复制源头的取值歧义;从签名日期计算 s3:signatureAge,移除请求头中的临时缓存值;统一预签名 query/header 的有效载荷哈希优先级;将 PutObjectTagging 的服务端合成头放到验签之后、授权之前。X-Amz-Content-Sha256 仍可不列入 SignedHeaders,但其有效值和正文校验必须一致;明确签入的 UNSIGNED-PAYLOAD 保留原含义。
本轮不宣称完整覆盖 streaming SigV4 seed 的未签名头。未签名头仍使用既有 400 AccessDenied,没有顺带改成 AWS 的 403。Console 分享修复没有新增“关闭全部分享”的环境变量;它不绕过 S3 授权,也不应被描述为已证明的任意主机 SSRF。
密码权限拆分:兼容性变更
Server #175、pkg #6 和 Console #51 将自助修改密码与用户管理分开:
- 内置用户修改自身密码检查
admin:ChangeMyPassword;无显式 Deny 时允许自助操作。 - 创建用户、重置他人密码仍要求
admin:CreateUser;root、STS、服务账号原有身份限制继续生效。 - 单独
Deny admin:CreateUser不再锁住调用者自己的密码;原有Deny admin:ChangeMyPassword开始实际约束这一入口。 - 更新的内置
readonly不再以 CreateUser Deny 覆盖其他策略给予的用户管理权限,并支持独立的consolereadonly能力;已有保存的策略覆盖不会自动重写。
若要保留旧的组合限制,升级前就在同一条 Deny 语句中列出两个 action,保留原 Resource 和 Condition。 回滚旧 Server 时也保留这对 Deny,因为旧实现不能单独执行密码专用 Deny。详见密码权限迁移。
共享策略实现
pkg #4 修复 NotResource 未进入去重哈希、不同字符串条件集合表示碰撞而丢失 Deny 的问题;直接构造的 policy 也能在建立索引前报告 Deny。多星号通配匹配移除指数级递归,保留原有字节匹配与 MatchSimple 边界语义。
因此,过去依赖错误丢弃 Deny 才成功的请求可能开始被拒绝。若错误语句已经从保存的 JSON 中消失,升级无法还原,必须与原策略源比对后重新提交。这些修复是本次 Server 从 pkg v3.13.2 升级获得的实际行为,不能只记为依赖版本变化。
IAM 复制、撤销与恢复
删除版本保留在原 IAM 配置路径,覆盖用户、服务账号、组、策略及各类策略映射;普通列表与授权隐藏删除记录。对象存储和 etcd 后端均串行化版本比较和写入,接收端保存来源时间,相同时间删除胜过活记录。
- 延迟的同后端删除通知重新读取已提交状态,避免删除随后重建的身份。
- 同名父身份重建保留
RevokedBefore;新服务账号和内置 STS 携带签名的siloParentRevocation边界。旧子凭据即使被重放或更新,也不能重新获得效力。 - 每个组成员保留自己的授权时间,编辑另一成员或组状态不会顺便给全部成员重新授权。
- 较新的服务账号快照可替换同 key 的旧副本,保留 secret、disabled、绝对过期时间和撤销边界;身份类型冲突报错,过期快照不能延长旧凭据寿命。
- Healing 在失去和重新取得领导权后能恢复;保留已确认版本并以有界批次重试。自然过期的普通 STS 不被无条件转成永久删除记录,服务账号 key 的复用仍保留版本历史。
- 新增 IAM 撤销数量、healing 失败数、耗时和最近成功时间指标,见设计与指标。
这些机制不构成跨站点即时撤销事务。父身份撤销可能已经提交,后续清理失败仍使 API 返回 500;不能由错误响应推断旧凭据有效。墓碑没有 TTL 或自动压缩;存储和启动成本随保留历史增长。删除后组成员的独立增删、同时间活记录冲突、任意时钟偏差和跨站点逐 token 撤销仍有明确边界。
S3 条件操作与多池一致性
跨池协调层先在共享命名空间锁内选择逻辑对象,再判断条件或合并同版本状态。正在退役、排空的池也参与相关状态检查;保留期、legal hold、标签分别按自己的修订排序,不能用对象修改时间代替所有字段的版本。
| 操作 | 本次变化 | 依据 |
|---|---|---|
| 单对象 DELETE | 非空 If-Match 在删除前比较客户端可见 ETag;不匹配返回 412。* 要求选中表示存在且不是删除标记;显式 versionId 比较该版本 |
#145、#178 |
| 普通条件 PUT | If-Match / If-None-Match 针对各池逻辑当前对象判断,避免目标池旧副本接受旧 ETag 或拒绝当前 ETag;当前删除标记视为缺失 |
#207,修复 #199 |
| 条件分片完成 | CompleteMultipartUpload 在同一对象锁下跨池判一次条件,而非仅检查上传所在池 | #190 |
| 普通指定版本 DELETE | 协调所有池的同版本副本,涵盖 UUID、null version、delete marker 和适用的目录标记删除,减少删除后旧副本重新可见 | #188 |
| 对象与元数据修改 | 对象写入、元数据、healing、复制和迁移复用协调锁;保留独立的 Object Lock、标签修订和共享远端 tier 引用 | #178、#189 |
可用性取舍: 任一相关池元数据无法确认时,条件 PUT/分片完成及协调删除可能失败,即使另一池仍可提供 GET/HEAD。读仲裁不足返回 503;恢复可读性后重试。清理失败可能发生在部分磁盘修改之后,没有分布式回滚保证。出站删除复制未完成时会保留等待 purge 的版本;成功响应不是每盘立即物理清除的证明。
普通条件 PUT 带目标 versionId 时仍比较当前对象,同时保留指定写入版本。该修复不清理其他池旧副本、不撤销历史错误覆盖,也不新增全局时钟顺序保证。#190 的分片修复与 #207 的普通 PUT 修复是两个独立问题。
未支持的边界: 批量 DeleteObjects 的 XML <ETag> 仍不提供条件保护;空 If-Match 按普通删除处理,内部递归前缀删除不走对象条件。尚无 s3:if-match 策略键,也没有额外的 GetObject 权限检查。需要条件保护时使用支持的单对象路径。详见条件删除与多池一致性。
池迁移保留对象标签
fced8630365f 修复 rebalance/decommission 迁移时丢失对象标签的问题:读取表示把标签放在 ObjectInfo.UserTags,迁移过去直接转交 UserDefined,可能漏掉目标写入所需的规范标签字段。
普通 PUT 与 multipart 初始化四个入口现在从独立的 metadata 副本重建标签字段,保留标签原修订,包括缺失、空值和已有的有序清空状态;迁移不生成新的标签修订,也不修改 reader 的 map。写入与分片完成继续使用现有锁内重读协调,避免旧 reader 越过后来的标签更新或清空。
此补丁不自动恢复历史已丢标签;请单独核对过去迁移过的对象及依赖标签的策略和生命周期规则。
null 版本列表 quorum
8d06424b1 修复新版本少数派掩盖旧版本多数派的列表选择问题。只有原选择未达到 quorum、每条非空磁盘流恰好只有一个普通 null 版本且纠删布局相同时,才按 header 重新计数;不扩大到混合版本历史。
仍有限制: #218 记录并发覆盖期间逐节点重启时,HTTP 200 列表仍可能遗漏可读取对象。不要用该阶段的列表驱动会删除目标多余对象的同步工具;集群稳定后重新列举。
加密对象、校验和与属性
- 原始 SSE-C 副本正确落盘: 已授权复制携带的密文按原样保存,避免目标默认加密或压缩再次变换,造成双重加密或不可读对象(#109、#122)。
- 保存明文分段大小: SSE-C multipart 副本记录逻辑长度,修复 part-number/range 读取、覆盖后对象大小和属性结果(#119、#124)。
- 排除 SSE-C 压缩: 普通 PUT、多段初始化、COPY、Snowball 不再新建压缩 SSE-C 对象,避免解密得到压缩流而非原文;SSE-S3/SSE-KMS 保留相应压缩选项(#118、#126)。
- 支持重传修复: 已存在或不可解码的 SSE-C 副本通过对象重传更新,不误用普通 metadata COPY;保留目标较新的保留期与 legal hold(#120、#134)。
- 密钥轮换遵守显式 checksum: 请求算法时执行必要的完整重写,包含与现有算法相同的请求;多段源可能变为单段目标,ETag 可能变化(#113、#123)。
- 属性返回逻辑结果: GetObjectAttributes 对压缩/加密分段返回明文尺寸,稀疏 part number 的末页正确结束(#114、#115、#128)。
- 不可读对象不冒充成功: 解密或存储完整性失败返回 500,不再以 206 被客户端当作有效读取(#110、#121)。
- 兼容 chunked checksum: 非 trailer 模式的 chunked PUT 即使声明
x-amz-trailer,实际放在普通 header 中的 checksum 仍被采用与验证(#107、#143)。
这些是预防新错误和提供受支持修复路径,不是自动重写历史加密数据。历史压缩 SSE-C、错分段尺寸及不可读副本须保留密钥和精确版本身份,另行读取验证。SSE-C 完整性说明列出恢复边界。
联邦 CopyObject
本节针对旧 etcd 桶联邦的远端转发,区别于桶/站点复制。累计修复来自 #157、#159、#163、#172、#177、#179。
| 过去的问题 | 修复后的行为 |
|---|---|
| 显式 checksum 算法被忽略,空对象或多段源结果错误 | 计算/转发逻辑完整对象 checksum,正确处理空流、trailer、继承摘要;拒绝缺失、畸形或仍带 multipart 后缀的必需远端摘要 |
| inline 源因内部 metadata 被目标拒绝 | 大小写不敏感地移除整类保留内部字段,公共元数据和标签使用正确的公开字段 |
| 加密源的字节或长度错误,可能重复加密 | 读取并转发逻辑明文与长度,由目标按显式 SSE 请求或自己的默认规则加密;SSE-KMS context 作为 JSON 对象传递 |
| 代理的自动加密覆盖目标桶默认值 | 未显式指定 SSE 时保留目标选择 |
| legal hold 被写成用户 metadata 或丢失 | 使用真正的 Object Lock header,保留完整精度的 retention 时间 |
| 返回零 LastModified、缺少目标 version ID,事件对象身份为空 | 响应和事件绑定目标实际提交的写入;不以代理时间或不带版本的后续 HEAD 猜测 |
| 原始 SSE-C replica COPY 的含义不明确 | 在创建目标前明确返回 501 NotImplemented;正常持源密钥的 SSE-C COPY 不受此拒绝规则影响 |
对应问题:#99、#100、#158、#166–#171。远端已提交写入之后仍可能因响应校验失败返回错误;版本化重试前先核对目标实际版本。详见联邦复制契约。
Object Lock、标签和复制恢复
保留与标签独立排序
- 只有 legal hold 的普通写入不再跳过桶默认 retention;ON/OFF 都不能替代保留期选择,显式时间精度保留(#165、#177)。
- 空值与只有时间戳的 retention/legal-hold 删除参与顺序比较,不抹掉更晚的目标状态,也不导致无穷重发(#111、#117、#129、#131)。
- 多池副本写入选择跨池权威 Object Lock 状态,关闭原先只在单个 erasure set 内成立的边界(#133、#178)。
- 副本协调时将标签值与修订一起带回,避免现有标签被空值覆盖;SSE-KMS metadata COPY、SSE-C 轮换保留标签时间;本地 PUT/DELETE tagging 单调推进修订,空标签作为有序删除抵御延迟重放(#189、#193、#196)。
复制双方须更新才能尊重空标签墓碑。带已记录标签修订的对象在显式 resync/heal 时每对象增加一次 metadata COPY;目标按桶默认 KMS 加密时可能重写数据。带标签过滤的复制规则仍按删除后的空标签决定目标资格。历史缺失或畸形修订不会被自动重建。详见Object Lock 排序和复制标签排序。
删除标记、MRF 与 resync
- 单对象删除标记 purge 正确分类,并在 worker、scanner/heal 和持久 MRF 恢复中保留标记身份及重试状态;只在 bucket、key、version、修改时间与任务匹配时接受相应 405 标记响应。审计状态由
COMPLETE统一为COMPLETED(#153、#162、#196)。 - 有界 MRF 队列的丢弃通过管理信息、指标与去重日志可见,并统一对象/删除 worker 分配;这不把有界队列变成永不丢弃的无限队列(#152)。
- resync 在发布 Completed 前应用最后的计数;以实际复制结果而非“目标已存在”判断成功(#136、#139)。
- 按正在同步的目标 ARN 派发;每个 resync ID 使用独立取消上下文,阻塞派发、walker 和 worker 能收尾,旧任务不能覆盖新终态(#141、#137)。
精确版本 purge 与排队创建
eb4f5e5b3 使纯版本 purge 不再向原本没有标记的磁盘创建标记;不存在版本的重试须由写 quorum 多数确认缺失,汇总已删除和可靠缺失的回复。接收端跨池解析指定版本,标记 healing 保留复制和 purge 元数据。
254b19ac0 在复制锁内重新读取排队的标记创建任务:版本已不存在、已非标记或正在 purge 时丢弃旧任务;读结果不能确认时通过 MRF 重试。该检查覆盖 DELETE handler、GET/HEAD/LIST heal、scanner 和 MRF 排队的任务。
358ab38fb 只把实际存储的标记报告为 delete marker,避免将等待 purge 的数据版本错误返回为 x-amz-delete-marker: true 并产生错误事件。
仍有限制: 已发出的创建请求、其他站点的重放,以及多数确认 purge 后崩溃留下的少数磁盘残留,仍由 #217 跟踪。该修复不构成接收端持久删除屏障。
副本元数据正常化
普通元数据提取之后只恢复六项复制专用字段,不再把传输用 aws-chunked 重新持久化为对象 Content-Encoding;可信 Snowball 条目也不继承外层归档的普通对象元数据(#185、#194)。
上述变更不会扫描或重写历史对象,不会凭空恢复丢失标签、Object Lock 历史或所有未收敛 purge。只读审计工具与手册覆盖精确版本、混合 Content-Encoding、歧义分类和受控恢复;普通批量 self-COPY 不是通用修复方案。
桶配置、缓存与启动
PR #180 完成 #77 的来源状态收敛:Policy、Tags、SSE、Quota、Versioning、Object Lock 的读取、比较、修改和保存处于同一 metadata.lock 中。peer 保存来源时间,本地更新在已有时间之后单调推进;同时间删除优先,其余冲突用稳定内容键裁决。
- 专用事件、bulk、import、初次同步和 heal 使用一致规则,省略字段不等于删除;Versioning/Object Lock 的空事件仍不提供删除能力。
- Policy JSON 规范化,已接受的
NotAction/NotResource策略能正确 GET/export;Statement/集合顺序可能变化,授权语义不因此改变。 - 空 Policy 继续按删除处理;零 Quota 保留有值文档,容量不受限制,不能把它悄悄转成不同的删除状态。
- 旧桶缺少 Created 时从物理信息恢复并落盘;接管不把默认空状态误认作删除,未知/无效/不可达来源有有界诊断。
MINIO_SITE_REPLICATION_METADATA_TOMBSTONES默认 off。升级所有参与站点后才统一设为 on 并重启,使 Tags/SSE/Quota 的缺省载荷删除时间对 heal/初次同步可见。关闭期间遗漏删除的收敛仍有边界。
这不是因果时钟,也不会自动修复被旧接收时间污染的历史。字段级开关的兼容设计不代表整个包含 IAM 新状态的版本支持滚动降级。桶配置收敛说明给出更细的恢复与取舍。
同一版本还修复:桶删除/更新/生命周期读取与缓存发布的剩余竞态;移除把“各字段最大时间”误当整记录版本的 reload guard,使等最大时间下的新字段仍能更新;桶 metadata 导入导出保留 per-bucket CORS(#105、#112、#127、#156、#164)。
#116 补全启动就绪窗口说明及 Linux 重启验证:健康端点成功或显示 online,不能代替每个协调节点的实际签名 PUT/GET。没有把健康端点改成全数据路径屏障。OIDC 修复和健康含义见下节。
分片上传发现、分页与取消
PR #198 增加持久化发现,#213 随后恢复保守的默认及回滚兼容性。最终默认是 legacy,不是 #198 初稿中的 strict。
| 项目 | 默认 legacy | 显式 strict |
|---|---|---|
| 列表来源 | 已发布行为:精确 key / 节点缓存,原有缺陷仍在 | 跨 pool/set/drive 扫描持久上传状态并验证 quorum |
| S3 列表语义 | 不承诺修复 prefix、delimiter 和跨页发现 | 全局 prefix、delimiter、排序及 marker 分页;原 marker 上传完成/取消后仍可续页 |
| 旧上传 | 保留原有可用行为 | 缺少持久 bucket/key 身份时返回诊断 503,不伪造成功的空页 |
| 取消 | 既有读仲裁、尽力清理和池顺序 | 各相关 set 多数删除确认,支持低于读仲裁的残片重试;已观察残片删除失败不能被空盘掩盖 |
新 writer 在现有 quorum 写入的 xl.meta 中保存保留的 bucket/key 身份,完成上传时删除这些临时字段;没有二级索引或目录格式迁移。两种模式共用的 maxUploadsList 上限从 10,000 降至 1,000,但不能因此假定 legacy 已获得完整分页语义。
只通过进程环境 MINIO_API_MULTIPART_LISTING=strict 启用并重启;不支持 mcli admin config set 动态设置。非法值诊断后回落 legacy,不丢弃其他 API 设置。启用前升级所有 writer、排空旧上传、执行需要 admin:StorageInfo 的只读 GET /minio/admin/v3/multipart-preflight,再验证部署容量。旧上传缺失身份可能阻断 strict 下其他桶的列表;预检 ready 也不能证明以后不会有旧 writer 再写入。
每进程最多两个扫描;每扫描 16 个身份 worker、4 个 metadata worker、30 秒 context,合计目录条目预算 100,000,包含跨盘重复,不是 100,000 个唯一上传。每页重新扫描持久状态,预算耗尽或不确定覆盖返回 503,而非成功的局部页。临时 10,000 上传、四 APFS 卷试验的一页耗时 18.7 秒,未达到暂定五秒目标;没有生产规模性能认证。
两种模式都修复错 bucket/key 的 Abort 误清有效缓存,以及解锁后 peer 通知失效的问题。HTTP 层不存在上传仍返回幂等 204;这不证明物理排空。迟到的创建写入仍可能在取消成功后恢复上传,未加入持久创建屏障。 因此 #79 保持开放,不能标为全面解决。完整启用及回滚契约优先于历史提案。
Console 2.4.1 的累计改进
除分享代理和密码权限修复,本次内嵌选择还包含从 20260903 之后积累的浏览器、管理 API 和交付改进:
- 对象游标分页: 使用 ListObjectsV2,支持每页 50/100/250/500/1000 项;排序、过滤、选择明确限定当前页,不为总数扫描整个桶;翻页失败保留当前列表,取消后释放列举 worker,rewind 明示行数和时间范围;空或 null versioning 响应不再使列表崩溃。
- 精确操作对象身份: 删除保留 bucket/key/version,目录删除限制在带尾斜线的前缀内;生命周期编辑保留 current/noncurrent、按日期和未展示字段,正确读取旧 prefix 并移除过期 filter 表示;删除复制规则保留共享目标,最后一条规则使用配置删除 API。Governance bypass 对有权用户显式提供、默认关闭,包括仅对象级设置保留期的情况。
- 权限和会话: Create Bucket 按
s3:CreateBucket显示;后台请求传输失败不无条件注销;Watch 参数正确 URL 编码,Inspect 保留结构化错误、不重复读取响应体。 - 嵌入兼容: 修复回环 TLS 登录;只对 Server 明确初始化的 TCP loopback peer 应用嵌入代理信任,独立默认仍为不信任;恢复四个 WebSocket 连接限制配置,避免所有公共浏览被错误压在单源八连接内(Server #108、#147、#148)。
- 流式 ZIP: 有文件 writer 的浏览器以背压写入并支持取消;其余交给原生下载管理器,不在 JavaScript 内存中缓存整个归档。原生交接后的取消由浏览器负责;只在可靠长度可用时显示百分比,大于 5 GiB 或未知大小推荐 mcli。
- 恢复、翻译与无障碍: 畸形路由、持久偏好和渲染异常提供恢复入口,补齐中英文字段、图标控件名称、退出文字和键盘提示;共享下拉框修复快速点击/触摸选到旧悬停项,禁用项不再误选其他值。
- 独立软件包: 增强可复现构建、固定工具及浏览器依赖、SBOM/签名/来源验证。systemd 保留
minio-console.service、console-user、/etc/default/console;证书目录改为/etc/silo-console/certs,需按指南处理旧证书和权限,升级不自动重启服务。
来源:Console #47、#50、#57、2.4.1 注记。独立 Console 发布和公共镜像验收与 Server 嵌入交付分别记账。
mcli 20260916 的累计改进
镜像捆绑的新客户端包含 20260913 与 20260916 两批变化:
pipe使用已应用的全局 quiet/JSON 设置,重定向输出不混入进度条;空输入保留显式 checksum,非空输入持续流式处理。MC_*布尔量接受on/off/enabled/disabled。- S3 Select
sql、传输、mirror 权限失败、legalhold、递归 retention 部分失败及mv源删除失败返回非零;mv等待删除结果,成功复制的目标不回滚。 - mirror 的逐对象权限错误不会阻止后续对象;有限任务有失败返回 1,失败任务不输出普通成功结尾。显式 summary 的 JSON 标为 failure,极短传输速度保持有限数值;列举/监听的取消重试策略仍有原有边界。
mirror --remove --watch不因源历史版本删除而误删目标;管理重启 dry run 不退化成真正重启,非 TTY 结果可靠。- 空 retention 时长、无效
find --regex正常报错,不再 panic;JSON usage error 不混入不合法格式。 - SDK 识别 HTTP 200 内嵌的 CopyObject 错误,避免
mv误认复制成功后删除源。此修复适用于客户端选用 CopyObject 的路径,通常小于 64 MiB 或显式--disable-multipart;不能替代默认大对象 ComposeObject 的独立验证。
脚本应检查最终退出码,而非开始时的 success 消息或进度字节。--skip-errors 不把已经发生的失败恢复成退出码 0;部分 retention JSON 错误文字可能为空。命令、别名、MC_*、配置格式与包名保持兼容。
HTTP、TLS 与可观测性
- 绝对请求头期限: #196 使
--read-header-timeout/MINIO_READ_HEADER_TIMEOUT真正进入 HTTP Server,连接包装器不再让持续小读无限延长 HTTP/1 请求头期限。默认 30 秒;正文保留滚动空闲超时,不新增整个上传/下载的总时长上限。缩短值也收紧 TLS 握手读取窗口;HTTP/2 保留其独立行为,TLS 写入侧和 handler CPU/存储等待不因此获得新总期限。负值关闭头部专用上限,不推荐作为常规绕过。设计说明回应 #183。 - 恢复 Go TLS 默认值: 移除 Server 八处显式曲线覆盖,使 listener、节点、身份提供方、复制和 etcd transport 尊重 Go 1.27 的默认密钥交换及相应 GODEBUG 控制;证书、主机名验证保持严格(#164)。这会改变 SILO 在线上发送与接受的内容: 不设 GODEBUG 时,提供的 group 列表变为 Go 当前默认值,额外包含
SecP256r1MLKEM768与SecP384r1MLKEM1024;设了GODEBUG=tlsmlkem=0时,该开关现在真正生效——作用于整个进程,出站与入站监听器同样适用。#154 已关闭,但项目的修复和合成 OIDC 验证不等于已复测报告人的隐藏部署,且报告人 2026-09-17 在本版本上的复测仍然失败;discovery/JWKS 总期限仍为独立事项。参见 TLS/OIDC 说明 与《写死 TLS 参数与握手兼容性》,后者记录了机制、上游同款案例、全部解法空间,以及本次修复覆盖不到的部分。 - CPU 指标竞态:
loadCPUMetrics对外层和嵌套 map 加读锁,防止 Prometheus 抓取与资源更新并发导致整个进程退出。修复已随 #214 进入 main;独立 #215 以替代方式关闭,问题 #210 也已关闭,不将 #215 本身记作合并。 - 配额和日志指标: 使用生效的 BucketQuota 字段;
AddSystemTarget幂等,串行化 logger 初始化和 console target 发布,防止日志订阅后重复 collector 破坏/logger/webhook指标(#106、#150、#132、#151)。
依赖、构建与工程维护
amqp091-go从 1.10.0 升至 1.14.0,包含恶意 AMQP frame 过量分配修复;SILO 中可达性需要配置 AMQP 通知目标(#176、#177)。- JWX 3.3.0 修复自定义 JSON 字段名转义;strfmt 0.27.2 修复 Go 1.27 主机名验证;LZ4 4.1.30 修复 reader、部分读取及并发行为,本版增加 Snowball/S3 Select 集成回归。JWX 依赖关系本身不证明某条应用路径可被利用。
- 上游 SDK 累计包含可配置上传限制、streaming Content-Type 签名、RDMA 使用调用方 TLS 信任、列表 checksum 与可选 restore status 一致性,以及前述 HTTP-200 CopyObject 错误处理。它们是采用的 SDK 能力,不代表 Server 新增 RDMA 服务。见上游采纳记录。Console 同时更新 React Router 7.18.4,并保留 js-yaml 与 smol-toml 的拒绝服务修复及重建后的嵌入资源。
- Go x/* 依赖刷新;保持 Go 1.27.1、NetBSD 所需的 go-systemd 22.6.0 replacement 和现有 tablewriter 兼容选择。Go 1.27.1 已属于上一正式版,不在本版重复计算为工具链升级。
- 容器基础镜像 digest 更新,双 Linux 架构从校验源码构建静态 curl 8.22.0;客户端安装器和镜像固定 mcli 20260916 的实际已发布归档及 SHA-256。
- 本版固定 GoReleaser 2.18.1 与 Action v7.2.3 的完整 commit;依赖文件改动也触发 Test Release Pipeline。tag 源码附带 Helm Chart 7.0.3 和新 Server/mcli 默认标签;没有单独的 Chart 发布。
- 修复条件 PUT 与标签复制测试夹具竞态,恢复集成脚本有效凭据;将相应 CPU、标签、multipart 和 S3 Select race 回归纳入 CI。这些测试修改不应另算成生产数据修复。
- 持续校正 rebrand guard,明确 AGPL-3.0-or-later、DCO 和无 CLA 的贡献规则,保留实际人类贡献记录;README 仓库卡片增加每日更新流程。
- 正式产品、升级、安全和设计文档集中在本站;源码仓库保留入口、必要兼容文档和测试材料。迁走临时调查与旧安全工作资料,历史证据以固定提交链接保留。
9 月 4 日的 Helm 正式镜像标签校正、mcli 归档 pin 和容器恢复发布属于上一版交付补完,也在扫描范围内,但不作为 20260916 新 S3 能力。
撤回的实验功能
GET 访问频率驱动的池间 ILM 分层 #60 于本周期合入,随后由 #188 移除。它从未进入正式 Server 20260903,也不属于本版的新增功能。 移除 tracker、mover、scanner hook、专用配置/XML action 和指标;十个旧 ILM 键兼容接受但忽略,读取 v8/v9 usage cache 并写回不带退役字段的 v8。
使用过中间开发构建的部署应移除 access-only 规则,编辑混合规则时保留普通动作。普通过期、远端 tier、rebalance、decommission 继续存在;独立的多池 Object Lock、条件删除、写入协调和共享远端引用保护保留。迁移说明解释具体范围。
升级与恢复要求
- 固定最终组件和制品。 本文发布 SHA 通过的检查不能自动转移到后续源码;实际 Server、Console、mcli、包、镜像和 Chart 应逐一核验身份。官方镜像名称统一使用
docker.io/pgsty/silo、docker.io/pgsty/mc和docker.io/pgsty/silo-console。 - 提前迁移密码策略并核对原始 Deny。 要维持旧组合限制,在同一 Deny 中保留 CreateUser 与 ChangeMyPassword。对曾丢失语句的策略从原始来源恢复。
- 安排协调维护窗口。 暂停 IAM 修改,隔离未知离线站点;升级所有参与节点/站点,包括共享 IAM 后端但未启用站点复制的节点。不支持同后端新旧混跑或滚动降级。
- 保存完整恢复点。 备份 IAM 后端及加密材料;
mcli admin cluster iam export只包含活记录,不能备份删除历史。恢复前停止相关进程,防止继续使用旧缓存/peer 确认。 - 逐入口验证身份与数据。 旧撤销凭据应拒绝,新用户、服务账号和新签发 STS 应在每个节点有效;验证签名 PUT/GET、对象字节、版本、标签、保留期和复制收敛。不能仅凭健康端点放流量。
- 回滚须调和备份后的撤销。 恢复旧快照会丢失后续撤销;在每个恢复站点逐一调和并检查全部端点,必要时改用不同名称的新身份、重新签发凭据。一次单站成功的禁用命令不证明全站生效;不承诺恢复前 STS 会话连续性。禁止在线删除 tombstone 或只转换活记录来强行启动旧版。
- 分别启用两个可选行为。 桶配置 tombstone export 只有全员升级后才打开;strict multipart 还要求所有 writer 更新、旧上传排空、预检和容量验证。正常升级可继续使用默认 legacy。
- 处理开发版本残留。 若运行过写入共享
api multipart_listing的中间构建,备份后用mcli admin config reset ALIAS api multipart_listing定向清除,保留其他 API 设置;不要重置整个子系统,也不要重放含旧键的历史。使用过访问频率分层的部署按撤回指南清理。 - 检查出站链路上的 TLS 检查设备。 握手内容在 20260903 随 Go 1.27 工具链变过一次,本次再次变化。SSL 检查 NGFW、SASE 网关、IDS/IPS,或按 JA3/JA4 客户端指纹做白名单的环境,都可能让身份提供方、webhook、远端分层或复制连接以
connection reset by peer被重置,而同一容器里的curl却正常。升级后请验证 OIDC discovery 与 JWKS、审计与通知目标、远端分层和复制端点。处置办法与代价见《写死 TLS 参数与握手兼容性》。 - 单独审计历史对象。 盘点不可读 SSE-C、错误分段尺寸、标签/锁状态、
aws-chunked污染、错误覆盖和待 purge 版本。修复二进制不证明历史数据已恢复;经批准的恢复清单应在副本环境验证。
操作依据:IAM 升级与恢复、历史副本审计、密码迁移、分片列表契约。对象数据与纠删码布局没有整体迁移,但新增 IAM 持久状态使“旧版能读对象”不足以证明整栈可以直接降级。
已知限制与未完成事项
| 项目 | 本版边界 / 当前处置 |
|---|---|
| #79 分片列表 | 已有可选 strict 实现,legacy 仍默认;生产容量、迟到创建写入屏障和完整交付验收未完成 |
| 批量条件删除 | XML ETag 仍无保护;空头、递归扩展和策略强制不属于已实现契约 |
| Streaming SigV4 | 普通/预签名头修复不等于 streaming seed 全部操作头已覆盖 |
| IAM 与桶配置历史 | 丢失修订/撤销不能自动重建;时钟、组成员局限和历史增长成本仍需运维管理 |
| #197 两盘 EC 文档 | 仍开放;不把这次发布注记当作新的生产拓扑支持承诺 |
| 其他开放提案 | #20 Renovate、#30 Operator、#40 通知目标热加载、#61 KES/OpenBao 规划、#160 图片处理,不作为本版新增功能 |
| 历史迁移标签 | 先前迁移已丢失的标签不会自动恢复,需单独核对依赖标签的策略和生命周期规则 |
| #217 / #218 | 在途/跨站点创建、崩溃残留与重启期间列表遗漏仍未解决;范围见上文 |
验证与发布状态
发布源码 2a4d51406b7e 的 Go CI 和 Test Release Pipeline 已通过。Release 构建和 Finalize 已完成。GitHub Release 提供 36 个资产,包括六平台归档、Linux 软件包、SBOM、校验和与证明材料。此前构建的本地升级与恢复记录保留各自的 SHA 和验证范围,不能替代最终制品验收;实际生产升级也须独立验证。
Console v2.4.1、mcli 20260916 和 pkg v3.14.1 已分别发布。2026-09-17 复核时,独立 docker.io/pgsty/silo-console 的匿名 token 请求返回 HTTP 401,尚不能确认公开拉取;可使用 Console 的 GitHub 二进制或软件包。Server 内嵌 Console 的源码选择不受此独立镜像分发状态影响。
问题索引与贡献
本版已修复或在明确范围内完成的问题组为:条件操作 #10/#133/#144/#199;联邦复制 #99/#100/#158/#165–#171;桶元数据 #77/#105/#112;加密与属性 #107/#109–#115/#117–#120;嵌入 Console #108/#147/#148;复制调度恢复 #136/#137/#139/#141/#152/#153/#185;运行与指标 #106/#116/#150/#154/#176/#183/#210。池迁移标签补丁以直接 main 提交列示;#79 保持部分实现而非关闭。编号详情和限制见上文各节链接。
感谢报告、补丁与复核参与者,尤其是 @mrjavadseydi(配额、分片列表与分层探索)、@nikitapogromsky(logger 幂等)、@Aeirx(联邦 legal hold)、@magicxor(条件 DELETE 早期方案)、@julienlau(purge/MRF)、@chodorenko(复制编码)、@orenyomtov(签名头报告)、@jiri-pejchal(Console 分享)、@AEGEGE(HTTP 报告)、@aschyolkin(CPU 竞态),以及 @vampywiz17、@kh0mka 等复现和反馈参与者。
PR #12、#125、#155、#184、#187、#195 等原始提交的关闭/替代状态保持原记录;成果经后续实现吸收,不改写为原 PR 本身已合并。完整署名见贡献记录。