在 CI 中自动扫描 Windows 镜像的 KB 补丁

解读

国内金融、政企类甲方在容器化 Windows 服务(如 ASP.NET、IIS 组件)时,合规基线要求镜像必须包含指定月度补丁,且需在 CI 阶段输出可审计的 KB 清单。面试官想确认两点:

  1. 你能否在 Linux 构建节点上无图形界面地解析 Windows 容器层;
  2. 能否把扫描结果转化为 Jenkins/GitLab CI 可识别的质量门禁(Quality Gate)。
    失败场景包括:把 3 GB 的 Windows Server Core 完整拉取到 CI 节点导致流水线超时;或扫描脚本在 ltsc2019/ltsc2022 版本间兼容性差,产生误报。

知识点

  • Windows 更新元数据位置:离线镜像中补丁信息保存在 Windows\Servicing\Packages 目录下的 .mum 文件与 Windows\System32\WinSxS\Manifests 中,可通过 dism /online /get-packages 或 PowerShell Get-WindowsPackage 读取。
  • 多阶段构建与最小扫描层:利用 mcr.microsoft.com/windows/servercore:ltsc2022 作为运行时,但扫描阶段仅复制必要文件到临时 Nano Server 容器,减少 70% 拉取时间。
  • Linux CI 节点兼容方案:使用 mcr.microsoft.com/windows/servercore 镜像时,CI 必须运行在 Windows 容器支持的 runner(如 GitLab Windows Runner on VM 或 Jenkins 的 Windows 节点);若坚持 Linux 节点,需把镜像导出为 tar,通过 wimlib7z 解压后正则解析 .mum 文件,但微软许可条款禁止在非 Windows 平台运行完整系统文件,因此合规做法仍是 Windows runner。
  • 输出格式与门禁:扫描结果需输出为 cyclonedxspdx-json,供 Sonatype Nexus IQ、Dependency-Track 等国产合规平台消费;关键 KB 缺失时以 exit code 1 阻断流水线。
  • 缓存加速:在 CI 中预先拉取 servercorepatch-scan 工具镜像,利用 Harbor 的 镜像预热 功能,避免每次从微软 CDN 拉取。

答案

  1. 在 GitLab CI 中注册 Windows Runner(需 Server 2019 以上并开启容器功能),标签设为 windows-docker
  2. 准备扫描镜像 patch-scanner:latest,基于 mcr.microsoft.com/powershell:lts-nanoserver,内置脚本 Scan-KB.ps1
    param([string]$BaseImage)
    docker create --name scan $BaseImage
    docker export scan | tar -xf - -C C:\scan
    Get-ChildItem C:\scan\Windows\Servicing\Packages -Filter *.mum |
    Select-String -Pattern 'KB\d{7}' -AllMatches |
    % { $_.Matches.Value } | Sort -Unique | ConvertTo-Json > kb.json
    
  3. .gitlab-ci.yml 阶段:
    stages: [build, scan]
    variables:
      IMAGE_TAG: $CI_REGISTRY/team/app:${CI_COMMIT_SHORT_SHA}-windowsservercore
    build-windows:
      stage: build
      tags: [windows-docker]
      script:
        - docker build -t $IMAGE_TAG .
        - docker push $IMAGE_TAG
    scan-kb:
      stage: scan
      tags: [windows-docker]
      script:
        - docker run --rm -v ${PWD}:/out patch-scanner
          pwsh -File C:\Scan-KB.ps1 -BaseImage $IMAGE_TAG
        - cat kb.json
        - python scripts/check_kb.py kb.json $CI_PROJECT_DIR/required_kb.txt
      allow_failure: false
    
  4. check_kb.py 读取甲方提供的 required_kb.txt,若缺失任一 KB 则 exit 1,GitLab 自动标记流水线失败,并上传 kb.json 到内部 Dependency-Track 实例供审计。

拓展思考

  • 补丁回退策略:若发现高危补丁导致业务容器崩溃,可在 CI 中再跑 dism /remove-package,利用 docker commit 生成回退镜像,并打标签 <镜像名>:<原标签>-kbrollback,实现蓝绿回退。
  • 镜像大小治理:Windows 补丁层累积后镜像可膨胀至 5 GB 以上,可在 CI 里引入 docker buildx imagetools create 把补丁层与业务层做 交叉挂载(cross-mount),复用相同补丁基线,减少 40% 存储。
  • 国产化合规对接:把 kb.json 转换为 GB/T 36627-2018 软件物料清单格式,通过 Harbor 的 漏洞扫描 webhook 推送到国测中心平台,满足等保 2.0 对容器补丁可追溯的要求。