2499 字
约 8 分钟
5
S01-A02 · 制品仓库与供应链安全

适用读者:要对"我们依赖的东西是否可信、出事能否追溯"负责的人。
前置:S01-J07(依赖治理)、S01-J08(制品发布)。
版本基线:Nexus Repository 3(示例)、CycloneDX 1.5+、SLSA 1.0 框架。
覆盖旧文:A-1399(制品库治理视角,duplicate_ref 至 S01-J08)。
新增扩展:E-S01-029(SBOM / 依赖扫描 / 许可证)、E-S01-030(制品晋升与不可变版本)。
上一篇:S01-A01 · 团队工具链标准化与新人 Onboarding
下一篇:S01-A03 · 文档与知识库平台架构。


1. 业务目标:三个必须能回答的问题

问题 出现场景 必须多久答出
"这个 CVE 影响我们哪些服务?" 漏洞公告刷屏 ≤ 2 小时
"线上这个 jar 是哪个 commit 打的?" 线上事故复盘 ≤ 30 分钟
"这个依赖的许可证能不能商用?" 法务尽调 / 客户审计 ≤ 1 天

这三个问题的答案,全部来自"制品元数据",而不是代码本身。 这就是制品仓库治理存在的理由。


2. 制品流向:一张图定边界

 开发者本地                      公司私服(Nexus/Artifactory)                生产
 ┌──────────┐    mvn deploy     ┌───────────────────────────┐   pull   ┌──────────┐
 │ ~/.m2    │ ────────────────► │ hosted-release(内部库)   │ ───────► │ 容器/主机 │
 │ 本地仓库  │                   │ hosted-snapshot(开发库)  │          │          │
 └──────────┘                   │ proxy-central(公网代理)  │          └──────────┘
        ▲                        │ group(聚合入口)         │
        │  pull                  └───────────────────────────┘
        └───────────────────────────────┘
边界 规则 为什么
本地 → 私服 只有 CI 能发 release;人只能发 snapshot 防止"某人的机器"产出生产制品
私服 → 生产 生产只从私服拉,且只拉固定版本 断网可控、可审计
公网 → 私服 只允许通过 proxy 仓库 统一出口,可缓存、可阻断
私服 → 公网 默认禁止(no egress) 防止内部构件泄露

红线:生产构建不能直连公网仓库。生产环境拉不到依赖是"可用性问题",拉到了不可信的依赖是"安全问题"——前者可以修,后者可能修不了。


3. 私服拓扑:三类仓库各管什么

仓库类型 作用 关键配置
proxy 代理公网仓库(central、spring、阿里云) 缓存 TTL、失败重试、白名单
hosted 存内部构件 release 与 snapshot 分开;release 禁覆盖
group 对外聚合入口(proxy + hosted) 顺序:hosted 优先(内部构件不被公网同名覆盖)

mirrorOf 的正确写法(与 S01-B03 §7.4 的坑呼应):

<mirror>
  <id>corp-group</id>
  <url>https://nexus.example.com/repository/maven-group/</url>
  <mirrorOf>*,!internal-snapshots</mirrorOf>
</mirror>

写成 mirrorOf=* 会把内部快照仓库也劫持到 group,导致 snapshot 拉不到。


4. 供应链安全三件套

4.1 SBOM(软件物料清单)

项 说明
标准 CycloneDX(JSON/XML)或 SPDX
粒度 组件 + 版本 + 许可证 + 哈希(purl)
生成 cyclonedx-maven-plugin(构建期生成,随制品一起归档)
<plugin>
  <groupId>org.cyclonedx</groupId>
  <artifactId>cyclonedx-maven-plugin</artifactId>
  <version>2.8.1</version>
  <executions><execution><phase>verify</phase>
    <goals><goal>makeAggregateBom</goal></goals>
  </execution></executions>
</plugin>

判据:SBOM 必须与制品一起存(同一次构建产出)。事后补生成的 SBOM 不可信——它反映的是"现在的依赖树",不是"当时的"。

4.2 漏洞扫描:在哪个环节卡

环节 工具类型 卡点策略
开发本地 IDE 插件 / dependency-check 只提示,不阻断(否则没人写代码)
CI(合并) OWASP Dependency-Check / Trivy CVE 严重度 ≥ 高 → 阻断
制品入库 私服扫描(Nexus IQ / Artifactory Xray) 入库即扫描,结果挂到制品上
运行期 镜像扫描 上线前最后一道

只做 CI 不做入库扫描是不够的:CI 扫描的是"这一次构建",入库扫描才能回答"仓库里躺着的 5000 个制品哪些有问题"。

4.3 许可证合规

许可证 商用 传染性 处置
Apache-2.0 / MIT / BSD ✅ 无 放行
LGPL ✅(动态链接) 弱 记录,法务确认
GPL / AGPL ⚠️ 强(AGPL 含网络服务) 默认阻断,需评审
商业许可 视合同 — 登记授权数量

实践:把许可证清单纳入 SBOM,CI 里配一份"禁止清单"(license-maven-plugin 可做)。AGPL 在服务端软件里尤其危险——你提供网络服务,就触发开源义务。


5. "某个 CVE 影响我们哪些服务"——可执行路径

① SBOM 库(所有制品 × 组件 × 版本)
   ▼ 查受影响的 groupId:artifactId:version 范围
② 制品 → 服务映射(部署清单 / 镜像 label / 服务目录)
   ▼
③ 受影响服务清单 + 负责人 + 当前版本
   ▼
④ 修复路径:升级到哪个版本 / 是否有替代库 / 能否临时隔离

这套路径能不能在 2 小时内跑完,取决于两件事:

前提 没有会怎样
SBOM 与制品同存 只能靠 mvn dependency:tree 逐个服务跑(几十个服务 = 一天)
制品↔服务映射 知道"哪个 jar 有洞",但不知道"哪个线上服务在用"

这两件事都属于"平时没人做、出事时最想要"的投入。


6. 制品晋升与不可变版本(E-S01-030)

6.1 晋升(promotion)而不是重建

做法 风险
重建(每个环境各打一次包) 每次构建都可能引入差异(依赖漂移、时间戳、插件版本)→ "测试通过的包"和"上线的包"不是同一个
晋升(同一个制品从 test 仓库晋级到 prod 仓库) 无差异;可追溯

原则:一次构建,多处晋升。同一份 sha256 从 dev → test → prod。

6.2 不可变版本

规则 实现
release 制品禁覆盖 Nexus:hosted-release 关闭 redeploy
制品带哈希校验 私服客户端校验 sha256
签名链 GPG 签名(S01-J08)+ 构建证明(SLSA)

SLSA 分级(简版):

级别 要求 现实起点
L1 有构建脚本、有来源说明 大部分团队在这里
L2 托管 CI + 生成来源证明 主流目标
L3 加固构建环境(隔离、不可篡改) 大型组织

建议:先做到 L2(CI 构建 + 生成 provenance),不要一上来追 L3。


7. 故障域与可观测

故障 影响 缓解
私服宕机 全员/全线构建失败 本地仓库预热、group 兜底、只读副本
proxy 缓存污染(拉到被篡改的包) 供应链攻击 哈希校验 + 白名单 + 定期校验
证书过期(私服 HTTPS) 突然全线失败 到期监控 + 双证书轮换
磁盘写满(制品堆积) 私服不可写 保留策略(每库保留 N 个版本)、监控
权限过宽(人人可发 release) 未审制品入生产 RBAC + CI 专用账号

观测项:私服探活(mvn dependency:get 定时)、制品入库量、扫描阻断率、许可证阻断清单变化。


8. 迁移与回滚

阶段 动作 回滚
现状盘点 列出所有依赖来源(含直连公网的漏网之鱼) —
收口 强制 settings.xml 走 group 仓库 保留直连配置 1 个月
扫描接入 先"只报告不阻断" 关掉阻断开关即可
阻断 高危 CVE 与禁止许可证阻断构建 降级为警告(需评审)
晋升制 一次构建多处晋升 回退到"每环境重建"

回滚原则:每一层都要有"开关"(开关放在配置里,不要写死在 CI 脚本里)。


9. 验收条件

# 验收项 判据
1 生产构建无公网出站 网络策略证明 + 一次断网构建通过
2 SBOM 与制品同存 随机抽 10 个制品,SBOM 齐全且版本一致
3 CVE 追溯 给定一个 CVE,2 小时内产出受影响服务清单
4 release 不可覆盖 尝试重发同版本 → 被私服拒绝
5 许可证阻断 引入 AGPL 依赖 → 构建失败并给出说明

10. 自测(架构师版)

  1. 为什么"生产构建直连公网仓库"是安全问题而不是可用性问题?
  2. SBOM 为什么必须与制品同时生成、同时存放?
  3. "重建"与"晋升"的差别,会在什么场景下暴露成线上事故?
  4. CI 扫描与私服入库扫描,各解决什么问题?只做一个会漏什么?
  5. 团队现在处于 SLSA 的哪一级?升到 L2 的最小动作是什么?

11. 下一篇

S01-A03 · 文档与知识库平台架构

依赖可信之后,下一个"长期资产"是文档。下一篇基于旧文 A-1867(docsify + Git + 码云 Pages + 自建服务器)的真实迁移史,比较 docsify / VitePress / Docusaurus / Astro 四种方案在搜索、权限、成本、构建时长上的取舍,并给出 URL 迁移与 SEO 回滚方案。


本篇属于系列《S01 · 开发环境与工具链》,架构师层第 2 篇。旧文关联:A-1399(duplicate_ref);扩展点 E-S01-029/030。

S01-A02 · 制品仓库与供应链安全
https://www.clxhxhhr.top/posts/5177/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。