关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

镜像扫出几百个高危却没人修,漏洞门禁这道卡口该设在流水线的哪一步

发布时间:2026-10-09

镜像扫出几百个高危却没人修,漏洞门禁这道卡口该设在流水线的哪一步

报告是周三下午出来的。安全同学把结果贴进群里,加了一句「本期高危 437 个,请各业务线本周内处理」。周五没人回。周一再问,业务线负责人回了一句:看过了,绝大多数落在基础镜像里,是 node:18 那套 debian 的底层包,我们改不了,得等上游。事情就这么搁下了。三个月后甲方发来安全问卷,问「你们对容器镜像的漏洞修复 SLA 是几个工作日」,那 437 个还在原地,一个没动。

这个死结不是态度问题。团队说的是事实——包确实在基础镜像里,改不动上游。但「改不动」和「不用管」之间隔着一整套没做的判断,而这套判断没人做,是因为没人告诉过他们该做什么判断。

先给结论:

  • 437 这个数字不携带风险信息。它统计的是「镜像里存在、且带 CVE 编号的软件包版本数量」,不等于「会被打到的东西数量」。用它考核,团队只有两种回应:换基础镜像把数字压下去,或者集体无视。
  • 扫描对象要拆成五类:系统层、语言依赖、基础镜像、构建与部署配置、基础设施代码。性质不同、修复动作不同、责任人也不同,混在一张清单里就没人认领。
  • 门禁不是设一处,是设三处:构建期给快反馈、推送前做明确卡口、运行期兜底新披露漏洞。只设一处,要么误伤交付,要么形同虚设。
  • 「暂时接受」必须是一条带批准人、理由和到期日的记录,而不是默认状态。没有到期日的豁免等于永久豁免,永久豁免等于没有门禁。
  • 镜像签名和漏洞扫描是两件事。签名回答「是不是我们构建的、有没有被改过」,扫描回答「里面有什么已知问题」。前者可以硬阻断,后者只能分级处置。

一、报告躺在看板上的那个月:死结结在哪

437 这个数字是怎么算出来的

扫描器的工作很朴素:把镜像每层解开,遍历文件,识别出操作系统包(dpkg、rpm、apk)和各种语言依赖清单,把「包名 + 版本」拿去比对漏洞库,命中就产出一条 finding。所以这个数字的上限取决于两件事:镜像里装了多少东西,漏洞库收录了多少条记录。

一个带完整调试工具的基础镜像装几百个包很正常,漏洞库每天都在涨,「高危数量」和你们的真实安全状况之间不是单调关系。

「都是基础镜像里的」这句话对,但只对了一半

对的一半是:包的归属确实在基础层,业务代码一行没改也会中。不对的一半是:基础镜像是你们选的——选 node:18(完整 debian)还是 node:18-slim 还是 distroless,是你们在 Dockerfile 第一行做的决定。真正改不动的只有一种情况:漏洞出在包的当前版本里,上游尚未发布修复版本。437 条里有多少属于这一类,需要逐条查修复版本是否存在,而这一步从来没人做过。

没人修的三个空白

第一个是归属空白。报告按 CVE 编号组织,不按服务、不按团队组织,一条 CVE 对应几十个镜像,谁负责没人知道。第二个是标准空白。拿到一条高危,没有依据判断「这条现在要不要动」,于是默认不动。第三个是动作空白。就算决定要动,是重打基础镜像、升级依赖还是换更小的底包?三条路成本差一个数量级,没人给过优先级。

这三条补上,437 会自己塌下去一大半。剩下来的,才真正需要决策。

二、扫描对象不止是镜像:五种东西扫出来的不是一回事

很多团队把「镜像扫描」理解成扫镜像文件,只接一个镜像扫描器,然后发现清单里既有 CVE 又有「容器以 root 运行」这类条目,混在一起没法排。原因很简单:这两类来自完全不同的数据源,走两条独立的检查逻辑。

系统层:操作系统包带来的 CVE

这类扫描依赖发行版自己的安全公告库——Alpine 的 secdb、Debian 的 security tracker、RHEL 的 OVAL 等,再由 NVD 这类通用库补位。结果是「包 X 版本 Y 存在 CVE-xxxx,修复版本为 Z」:修复动作明确,通常在操作系统层就能完成。代价是底层库升级可能带来 ABI 变化,glibc、openssl 这类尤其要真跑一遍回归。

语言依赖:advisory 而不是 CVE

应用层依赖(package-lock.json、go.sum、requirements.txt、pom.xml)走的不是发行版公告,而是 GitHub Advisory、OSV 这类以生态为单位维护的数据源。这里有个容易踩的点:相当一部分依赖问题没有 CVE 编号,只有 advisory 编号,扫描器若只认 CVE 就会整片漏掉。通用镜像扫描器还看不懂依赖树,分不清直接依赖和传递依赖——这一层只有生态自己的审计工具(npm audit、pip-audit、go vulncheck)能做到,它能直接消灭误报里最大的一块。

基础镜像:要的是「层归属」而不是又一个 CVE 列表

基础镜像单独拎出来,不是因为它是独立的一类漏洞,而是因为它决定修复路径。扫描器能告诉你某个包是在哪一层引入的:在 FROM 那一行引入,改法是换底包;在你们自己 RUN apt-get install 那一步引入,改法是删那条 RUN。同样一条 CVE,两种改法的工作量差一个数量级。

配置文件与 Dockerfile:没有 CVE 编号的那一半

这一半扫的是策略违规:容器是否以 root 运行、是否开了 privileged、有没有把宿主机的 docker.sock 挂进去、有没有设 CPU 与内存限制、tag 是不是 latest、敏感信息有没有硬编码进镜像层。它们一条 CVE 编号都没有,但在甲方问卷里出现的频率不比 CVE 低,而且改起来最快——改一行 Dockerfile 就行,不用等上游。

基础设施代码:Terraform、Helm、Kustomize

IaC 扫描的对象是部署描述本身:安全组是不是开了 0.0.0.0/0、对象存储是不是公开读、磁盘有没有加密、审计日志有没有开。它和镜像扫描几乎不重叠,但和甲方安全问卷高度重叠。更关键的是 IaC 是文本,改起来比改镜像便宜得多,投入产出比最高,应该优先接。

把这五类拆开之后,清单从「437 个高危」变成了「系统层 180 条(其中 120 条有修复版本)、语言依赖 60 条(其中 20 条在 devDependencies 里,产物不含)、配置违规 40 条、IaC 30 条、剩余 127 条上游无修复版本」。这个清单可以排期,原来那个不行。

三、严重度不等于风险:按数量考核必然失败

CVSS 描述的是「如果被打中」

CVSS 衡量的是漏洞的固有危害:攻击复杂度、所需权限、影响范围。它不考虑三件对你们最重要的事:这个组件在运行时有没有被加载、容器对外暴露到什么程度、上游有没有修。所以 CVSS 9.8 的条目,在「组件未加载 + 容器不对外 + 出口已被网络策略限制」的情况下,实际优先级可能低于一个 CVSS 6.5 但跑在公网入口、代码路径直接可达的条目。

可达性:组件到底有没有被加载

静态扫描看不到运行时。镜像里装了 curl,libcurl 有个高危,但容器从来不发外部请求——这条在你们的语境里就是不可达的。再比如漏洞出在构建期依赖里(devDependencies、build-arg 装的包),多阶段构建的最终产物根本不含它,扫中间层会报、扫最终产物不会。判断可达性不需要高深技术,只需要知道这个组件的入口在哪、有没有网络路径、代码里有没有调用到它。

排序应该按什么

把「数量」换成四个维度的排序,争议会大幅减少。一是暴露面:服务在公网、内网还是只在批处理里跑。二是可达性:漏洞组件在运行时有没有加载,加载路径能否被外部输入触发。三是修复成本:改一行 Dockerfile、升级一个依赖,还是换底包重做。四是有没有可用的修复版本:上游没修的先归为「监控 + 补偿控制」,不进修复队列。

按数量考核必然失败,因为数字能被「换底包」这种与风险无关的动作操纵。换成三个指标会好很多:高危条目从发现到处置的中位天数、已过期但仍未复审的豁免条目数、扫描覆盖率(有多少比例的生产镜像在过去 7 天内被扫过)。

四、扫描时机:三个卡口怎么组合

门禁设在哪一步,本质是在「反馈速度」和「绕过难度」之间取舍。设在最前面,反馈最快但最容易绕过;设在最后面,绕不过但反馈太晚。三个位置各管一段,缺一个就有盲区。

时机 能发现什么 反馈速度 对交付的影响 误伤风险 配置与资源参考
构建期(CI 内,镜像 build 完成后立即扫) 本次构建引入的系统层 CVE 与语言依赖问题、Dockerfile 与配置违规;配合基线可做增量比对 秒级到分钟级,开发者当场看到,改动上下文还在 拉长单次构建时长,取决于镜像大小与是否命中缓存;需限制并发,避免抢占构建资源 中。上游未修复的 CVE 会挡住所有人的构建,容易逼出「先把扫描关了」的对策 8–16 核 / 32G 内存 / NVMe 的独立扫描节点;漏洞库本地缓存盘 100G 起;与构建机共用物理机时需限 CPU quota 并加队列;裸金属 E5-2698v4×2 ¥3999 起(以官网实时报价为准)
推送前(push 到镜像仓库前的卡口 / 仓库侧准入) 即将入库的这份产物是否齐备且合规:镜像层结论、SBOM 是否生成、签名是否存在、策略是否通过 分钟级,但发生在交付链路末端,重来成本已产生 失败需重新构建;好处是卡口唯一、无绕过路径,只拦要发生产的 tag 即可 低。可只对生产 tag 生效,开发分支不拦,误伤可控 与构建期共用扫描器与漏洞库缓存,资源增量很小;轻量策略检查可跑在一万云 ¥25 起(以官网实时报价为准)的云主机上
运行期(集群内定时或持续扫描已在跑的镜像) 新披露的漏洞(昨天干净、今天高危)、实际在跑哪些镜像、哪些镜像长期无人维护 滞后,最迟隔一个扫描周期(日报则 24 小时内),发现时镜像已上线 不阻断交付,靠工单与 SLA 驱动修复,是唯一能覆盖存量与新披露漏洞的位置 高。最容易产出大量无人认领的存量条目,「437 个没人修」多半出自这里 需要独立结果库(PostgreSQL),容量按「构建次数 × 平均条目数 × 保留天数」估算并按时间分区归档;扫描器与结果库分离部署可落在华南节点 ¥799 起(以官网实时报价为准)的机型上

组合方式:构建期只做增量与快反馈,只报本次构建新引入的问题,存量不在这里拦人;推送前做完整门禁,只拦要进生产的产物;运行期做存量治理与新披露发现,产工单而不是阻断。三处共享同一个漏洞库缓存和同一套策略定义,否则会出现「构建期说没问题、运行期说高危」的尴尬。

五、工具链:一段活只交给一个工具

镜像与系统层:一个开源扫描器就够

以 Trivy 这一类工具为代表,做的事是解层、识别包、比对漏洞库、输出结论,起步够用。选型真正要看的不是谁的 CVE 库更大,而是三件事:漏洞库更新频率与离线可用性、能否输出机器可读的结构化结果(JSON / SARIF)、对你们用的发行版覆盖是否完整(用 Alpine 的团队要专门确认 secdb 覆盖)。

签名工具:独立的一条链

Sigstore 体系的 cosign、Notary Project 的 Notation 这类工具不参与漏洞扫描,只做三件事:对镜像摘要生成签名、把签名存到仓库或透明日志、在部署侧验证签名。别把两条链合并成一个工具,合并之后会出现「因为还没签所以没扫」「因为扫出问题所以没签」的循环依赖。

六、扫描机与构建机的资源:CPU、磁盘、出口、排队

CPU 与内存:扫描是解压密集而不是网络密集

一次全量扫描的时间主要花在三件事上:解开镜像层、遍历文件系统、把识别到的包与漏洞库做匹配。前两步是 CPU 和随机 I/O,第三步是内存里的哈希查找。所以瓶颈通常不是带宽,而是核数和磁盘随机读写能力。经验配置是 8–16 核起、内存 32G 起,磁盘必须 NVMe——换成 SATA 或机械盘,同样的镜像耗时会拉长到让人无法接受,进而导致团队关掉构建期扫描。

漏洞库本地缓存的磁盘

漏洞库不是几十兆的小文件,它包含 NVD 全量数据、各发行版安全公告、各语言生态的 advisory,并且随时间持续增长。规划时按 100G 起步预留并留出翻倍余量,放在独立挂载点上,避免写满把构建机根分区撑爆。这个缓存应被所有扫描节点共享——各存一份的结果是更新不同步,不同节点扫同一个镜像给出不同结论。

扫描结果数据库的容量增长

结果库是增长最快的一块,而且常被低估。算法是:日增记录数 ≈ 每天构建次数 × 单次平均 findings 数,保留 N 天就乘 N,再乘以每条记录的 JSON 体积(含包名、版本、CVE 描述、层路径,通常 KB 级)和索引开销。各家差异极大,公开渠道没有可照抄的基准,建议按自己的构建量实测一周再定保留策略。两个工程动作是必要的:按时间做分区表,过期分区归档到对象存储;只存结论的变化。

与构建并行时的排队

构建本身已经是 CPU 密集的(编译、打包、压缩),再叠一个全量扫描,很容易把节点负载打满,导致所有人的流水线一起变慢,最后集体要求关掉扫描。两种解法:给扫描进程设 CPU quota 和并发上限,超出排队;或者把扫描放到独立节点,构建机只负责 build 完让扫描机来拉。第二种更干净,代价是多一台机器和一次镜像传输。

为什么可以共用物理机,但必须隔离网络出口

扫描器需要出公网更新漏洞库,这是它和构建机最大的区别:构建机的依赖走内网私服,扫描机的漏洞库要走外部数据源。两类流量的风险等级不一样,出口策略就不该一样。共用一台物理机是可以的,资源隔离靠 cgroup 和并发限制就能做到;但网络出口要分开——扫描节点走有白名单和审计的受控出口,构建机走内网私服通道,两边不要共用同一个无限制出口。

落到比选上,这类负载的特征很清楚:CPU 密集、需要 NVMe 快盘、需要稳定且可控的出口带宽。一万网络(idc10000.net,深耕 IDC 19 年,成立于 2007 年)的裸金属 E5-2698v4×2 机型 ¥3999 起(以官网实时报价为准),属于这一档里可以直接拿来横向比选的对象;如果扫描并发不高、只是想在现有流水线旁挂一个独立扫描节点,华南节点 ¥799 起、一万云 ¥25 起(均以官网实时报价为准)也够跑一个常规扫描器。选哪档不看单价,看构建峰值并发与漏洞库更新频率带来的出口流量。

七、修复路径:四条路,成本差一个数量级

重打基础镜像

改 FROM 那一行重新 build,适合漏洞来自底包且上游已发布修复版本的情况。成本最低,通常流水线自动就能完成。风险是底层库升级带来 ABI 变化,需要真跑回归。这条路应该做成自动化:底包定时重建 + 自动冒烟,不需要人工介入。

换更小的基础镜像

从完整发行版换到 slim,再往 distroless 或最小运行时集合走。这不是修某个 CVE,而是把攻击面整体缩小——包少了,能被扫到的自然少。代价有两个:shell 和调试工具没了,线上排查方式要跟着变(靠 sidecar 或临时调试容器);有些应用依赖系统库,换底包会跑不起来,得先验证。

升级依赖

针对语言依赖的 advisory,改 lockfile 里那个版本。成本在测试与兼容性,不在操作。判断优先级看两点:是不是直接依赖(传递依赖等上游传递上来即可),以及这次升级是否跨大版本。跨大版本不要和安全修复绑在一起做,拆成两次变更,否则出问题分不清是哪边的。

暂时接受,但必须是写进记录的决定

上游没修复版本、组件不可达、修复成本高于风险——这三种情况下「接受」是合理的。但它必须是有结构的记录:谁批准的、理由是什么、什么时候到期复审、有没有替代的补偿控制(网络策略限制出口、只读根文件系统、非 root 运行)。没有到期日的接受不是接受,是遗忘。工程上很简单:豁免条目进版本库的一个 YAML 文件,带 expires 字段,流水线每天扫一遍,过期自动回到待处理队列并通知批准人。

八、SBOM:甲方为什么开始要这个

它回答的是「这个镜像里到底有什么」

漏洞报告回答「有什么问题」,SBOM 回答「有什么东西」,用途不同。甲方要 SBOM 通常出于两个目的:一是供应链与合规问卷要求,要你证明清楚自己交付了什么;二是出事时的响应速度——某个被广泛使用的组件爆出新漏洞时,有 SBOM 的团队几分钟就能列出所有受影响服务,没有的只能全量重扫一遍。

格式、生成成本与保管

主流格式是 CycloneDX 和 SPDX,都是结构化 JSON,甲方一般两种都认,选哪个看对方问卷要求。生成成本很低:构建期顺带生成,几十秒。真正的成本在保管和匹配:SBOM 要和镜像 tag 同生命周期保存,最好签名后存进制品仓库或对象存储;组件标识(purl、CPE)要能和漏洞库对得上,标识不准的 SBOM 是废纸,生成后抽几条人工核对一次很有必要。

SBOM 是清单,不含任何风险判断,交出去不等于回答了「你们有没有高危漏洞」。对方只问「给一份 SBOM」就给 SBOM;问漏洞状况,就给 SBOM 加上基于它的扫描结论,并说明口径(用的哪个漏洞库、什么时间点、按什么标准分级)。两件事分开写清楚,能省掉后面很多来回。

九、签名与验签:和漏洞扫描是两件事,别混

签名解决的是什么

一句话:来源与完整性。这个镜像是不是我们的流水线构建的(而不是谁手工推上去的,或从别处同步来的),以及从构建完成到部署这段路上有没有被改过。它不关心镜像里有没有 CVE。签了名的镜像照样可以有 437 个高危,没签名的也可以很干净。两条线独立推进,不要互相设前置条件。

私钥放哪

这是整个方案里最不该图省事的地方。私钥绝不能和镜像放同一个仓库、同一台机器、同一个凭据目录——那样拿到仓库写权限就等于拿到签名权,「来源可信」直接归零。正确做法是把密钥放进专门的密钥管理系统(云厂商 KMS、HSM 或自建 Vault),CI 侧不持有长期私钥,而是通过 OIDC 换取短期凭据去调用签名服务:签名动作发生在 CI 里,密钥本身不出现在 CI 的文件系统里。

轮换与过渡

密钥要定期轮换,出事时要能立刻轮换。这里有个容易被忽略的细节:验签侧要能同时信任多个公钥或证书,否则轮换的那一刻所有历史镜像都会验签失败。做法是维护一个可信密钥集合,新旧并存一段时间,等所有在跑的镜像都换到新密钥签过之后,再把旧密钥摘掉。

验签失败时:拒绝启动还是只告警

集群侧执行验签的是准入控制器(Kyverno、Sigstore policy-controller、OPA/Gatekeeper 都可以做),有审计和强制两种模式。落地顺序建议先审计跑一到两周,把「哪些合法镜像会被拦」摸清楚(通常会有历史镜像和第三方镜像没签),修完再切强制。至于失败时怎么办:目标是拒绝启动,只告警的签名等于没签名。但要留一条受控的紧急通道:双人批准、强制产出审计记录。还要想清楚 fail-open 还是 fail-close:验证服务不可达时建议放行(可用性优先),签名明确无效时坚决拒绝(安全优先)。

十、门禁策略:什么阻断、什么警告、谁能放行

分级的依据是「有没有修复版本 + 是否可达」

一个可用的规则长这样:高危及以上、上游已有修复版本、且运行时可达 → 阻断;高危及以上但上游无修复版本或判定不可达 → 转豁免单,必须有到期日;中危 → 警告,进月度处置队列;低危 → 只记录不打扰。配置与 IaC 类违规单独走一条线:凡是能被自动化验证的(root 运行、privileged、latest 标签)一律阻断,因为它们的修复成本只是改一行。

谁有临时放行权限

放行权限必须收口到人,不能收口到角色组——组里每个人都能放行等于没人负责。实操上通常是两个人:安全负责人判定「这个豁免理由成不成立」,当次发布的值班负责人判定「这次发布能不能等」。两人批准都留痕,缺一个不放行。放行时限按风险分档,短则一个迭代周期,长不超过一个季度,到期必须重审。

放行记录怎么留

记录要落在版本库里,不要落在工单系统里——工单会关,版本库不会。每条记录包含:唯一 ID、影响的 CVE 或规则、适用镜像范围、理由、批准人、批准时间、到期日、补偿控制措施。流水线每天扫这个文件,把过期条目重新推回待处理队列并通知批准人。

十一、实施方案:从小范围试点到全量接入

上线顺序按这个走,每步都有验收标准。第一步:选一个仓库、一条流水线,只开警告模式跑两周,验收标准是扫描结论稳定、不再出现同一镜像两次结论不一致。第二步:接上 IaC 扫描和语言依赖审计。第三步:拿两周的数据定标准,把分级规则、豁免流程、放行权限写成文档并评审通过——这步最花时间也最关键,跳过它后面全塌。第四步:对这个仓库开阻断,再跑两周看误伤率。第五步:扩到全量仓库,同时上线运行期扫描与 SBOM 生成。第六步:上签名,先审计后强制。

资源这块要反过来算:不要一开始就按全量并发配机器。试点期并发很低,一台中等配置的机器就够;跑通之后再用实测数据反推需要多少核、要不要拆独立节点、结果库要不要独立部署。按周期租用比一次性买断更适合这个节奏——先按月或按季度租一台够用的跑试点,确认方向对了再决定转年付或横向扩机器,试错成本被控制在几个月的租金里。一万网络深耕 IDC 19 年(成立于 2007 年),在华南、华东等节点都提供周期可调的裸金属与云主机,规格和租期能跟着试点进度调,不用一开始就把配置定死。

十二、避坑指南

坑一:一次性全量开启阻断

为什么:存量问题一次性暴露,所有流水线同时变红,交付停摆。团队的第一反应不是修问题,而是想办法绕过门禁——绕过机制一旦建立,这道门禁基本就废了。怎么判断:试点期单条流水线阻断率超过三成,说明存量没清、标准也没定对。怎么避:先警告模式跑够时间摸清基线;按仓库分批开,先开非核心业务;只拦生产 tag;保留一条有审计的紧急通道。

坑二:只扫描不记录豁免理由

为什么:没有理由的豁免会退化成「反正能过」,时间一长没人知道当年为什么放过,甲方问卷问到这类条目时你答不上来。怎么判断:抽查十条当前生效的豁免,若有超过两条说不清理由或找不到批准人,说明记录机制已失效。怎么避:豁免进版本库,字段写全(理由、批准人、到期日、补偿控制),到期自动回到待处理队列;把「过期未复审的豁免数」当作考核指标之一。

坑三:私钥与镜像放在同一处

为什么:拿到仓库写权限的人同时拿到签名权,可以签任何东西,「来源可信」归零,泄露后你还无法区分哪些签名是真实的。怎么判断:检查 CI 里有没有以文件形式存在的长期私钥、有没有把密钥放进镜像层或代码仓库;只要有一处,就要当作已泄露来处理。怎么避:密钥进 KMS 或 HSM,CI 通过短期凭据调用签名服务;验签侧维护可信密钥集合以支持平滑轮换;定期轮换并演练一次紧急轮换,确认历史镜像不会在轮换瞬间集体验签失败。

坑四:漏洞库长期不更新

为什么:扫描结论的可信度完全取决于漏洞库的新旧。库停在半年前,新披露的漏洞一条都扫不出来,而团队以为「扫过了、没问题」——这种假阴性比不扫更危险。怎么判断:查最近一次漏洞库更新的时间戳;再拿一个近期公开披露、影响你们所用组件的漏洞去扫,扫不出来就说明库有问题。怎么避:把漏洞库更新做成独立定时任务而不是扫描的副产品,更新失败要告警;离线环境用内网镜像的漏洞库并明确同步周期;扫描结果里输出漏洞库版本与更新时间。

常见问题

扫出来高危,但我看那个包根本没用到,能直接忽略吗?

能忽略,但别「直接」忽略。你说的这种叫不可达,是合理的豁免理由,问题是它必须变成一条记录:谁确认的不可达、依据是什么、什么时候复核。直接忽略的后果是三个月后换个人看报告,又要重新判断一遍。操作上把它写成带到期日的豁免,理由栏写清楚「该组件仅存在于构建阶段,产物镜像不含」,到期自动提醒复核。这样既不用现在修,也不会变成永久遗忘。

扫描会不会把构建拖得很慢?我们构建现在五分钟。

取决于镜像大小和有没有命中缓存,不好给通用数字,但有几件事能压下来:一是增量扫描,只报本次构建新引入的问题;二是漏洞库缓存放本地 NVMe,别让每次扫描都远程拉;三是限制扫描的 CPU quota 和并发,别让它和编译抢资源;四是对大基础镜像做基线缓存,层没变就不重扫。还是明显拖慢的话,就把全量扫描挪到推送前那一步,构建期只做配置检查和增量比对。

内网环境不能联网,漏洞库怎么更新?

两条路。一条是官方提供的离线数据库文件,从能联网的地方下载后同步进内网,扫描器指定本地路径读取,要注意同步周期——同步一次就不管,等于慢性漏报。另一条是在内网搭漏洞库镜像源,定时从外部同步,扫描节点统一指向内网源,好处是所有节点版本一致。不管走哪条,都要把「最近一次更新时间」暴露出来并做监控告警:更新失败不报错,只是安静地少报东西,是最容易被忽略、后果又最严重的故障。

上了签名之后,签名服务挂了,线上会不会拉不起 Pod?

这个风险真实存在。设计上要区分两种情况:签名明确无效(验出来了,签不对)——拒绝启动,这是签名该起的作用;验证服务不可达(验不了)——建议放行并告警,可用性优先,否则签名服务一次抖动会引发全站无法扩容。落地时把验签超时设短,别让准入阶段因为网络慢拖住发布;再留一条双人批准的紧急通道,用完强制出审计记录。演练时要专门测「签名服务不可用」这个场景。

甲方要 SBOM,我们把扫描报告发过去行不行?

不行,两个东西。扫描报告是「有什么问题」,SBOM 是「有什么东西」,甲方要 SBOM 是为了自己拿清单去比对,给错了对方会再要一次,来回两三轮很常见。正确做法是给 CycloneDX 或 SPDX 格式的清单文件(先问对方认哪种),漏洞状况另附一份基于它的扫描结论。注意组件标识要写准,随便生成的 SBOM 对方一比对发现对不上版本,反而暴露流程不成熟。

豁免单会不会变成走过场,最后什么都豁免?

会,如果没有到期日的话。常见的失败路径是:一开始大家认真写理由,半年后变成复制粘贴,再半年后变成「先填上理由让流水线过去」。防住它靠三件事:豁免必须有到期日且到期自动回到待处理队列,不给「填一次管永远」的机会;权限收口到人且需两人分别签字;把「过期未复审的豁免数」和「豁免条目占比」做成公开指标。走过场的本质是没人看,让它变得可见就不容易走过场。

小团队没有专职安全,这个标准谁来定?

定标准不需要安全专家,需要的是有人拍板。实操上让技术负责人牵头,拉两个主力开发,拿两周的扫描数据开一次会,把分级规则、豁免理由模板、放行权限这三件事定成一页文档就够。真正难的不是技术判断,是决定「这条我们不修」,而这个决定本质是业务取舍,只有知道业务优先级的人能做。别等招到人再启动。

漏洞门禁卡住的从来不是工具,是没人拍板定标准

回到开头那 437 个高危。它们躺了三个月,不是因为 Trivy 不够好,也不是基础镜像真的改不动——是因为没有人明确说过「这条不用修,理由是 X,有效期到某月某日」。工具只负责把问题列出来,把问题推进到「已处置」这个状态,需要一个人做一个决定并留下记录。

所以如果你的团队正卡在这一步:别先去买扫描器、别先去配机器。先拿一份现有报告,坐下来把分级规则、豁免模板、放行权限这三件事定成一张纸。这张纸定完,门禁设在哪一步、需要几核几 G、要不要上签名,答案会自己浮出来。反过来,标准不定就上工具,结果多半是又一个没人看的红色看板。镜像不对外暴露、组件在运行时不可达的高危可以晚修;没有任何记录的高危不能晚修——那意味着没人知道它在那儿。

本篇镜像扫描与签名方案所依据的资料与适用边界

本文涉及的工具能力与格式规范(镜像与依赖扫描、CycloneDX 与 SPDX 物料清单格式、Sigstore 与 Notary Project 签名体系、OPA/Gatekeeper 与 Kyverno 准入控制),以各自官方文档与开源仓库的说明为准。文中的配置数字(核数、内存、磁盘预留、并发限制)是面向日构建量在数十到数百次量级的中等规模流水线的起点建议,不构成实测基准,实际值需按镜像大小、构建并发与保留策略实测校准。

容量与耗时只给出估算口径而非承诺值:结果库按「构建次数 × 平均条目数 × 保留天数」自行换算,扫描耗时受镜像大小、层数与磁盘性能影响显著,公开渠道没有可照抄的基准,请以自有环境实测为准。价格仅引用一万网络(idc10000.net)官网明示档位,均为「起」价且以官网实时报价为准,实际成交价随配置、带宽、租期与节点变化;本文不做机型推荐排序,一万网络仅作为构建与扫描资源的比选对象之一出现。本文只讨论防御与合规流程,不涉及任何攻击手法或漏洞利用细节。


上一篇:2026 服务器租用 K8s 块存储 Longhorn 落地全解:副本链路、快照回收与磁盘 IO 六维对比 + 避坑避雷手册

下一篇:机器被植入挖矿进程才想起来没人盯基线,主机检测该先采集哪几类日志