首页
/ GitLab CI 中的 DevSecOps 流水线工作流:从 MR 安全审查到漏洞生命周期管理

GitLab CI 中的 DevSecOps 流水线工作流:从 MR 安全审查到漏洞生命周期管理

2026-09-09 21:11:59作者:龚格成

本篇文章围绕当前仓库中 building-devsecops-pipeline-with-gitlab-ci 技能所定义的四种核心工作流(合并请求安全审查、容器镜像安全门禁、针对预发布环境的 DAST 动态扫描、漏洞生命周期管理)展开,结合仓库内完整流水线配置、API 参考与脚本实现,说明如何在 GitLab CI/CD 中将 SAST、DAST、容器扫描、依赖扫描、密钥检测与许可证扫描等安全能力内嵌进交付链路。读完本文,你将掌握四条可落地的安全流水线工作流的配置方法与状态流转规则,并能够通过 GitLab API 验证配置与聚合安全报告。

工作流全景:四条贯穿交付生命周期的安全主线

GitLab 将安全测试直接嵌入 CI/CD 流水线,通过托管安全模板(managed security templates)实现"安全左移"。本仓库定义的 workflows.md 给出了四条可独立落地、又相互衔接的工作流骨架,覆盖从"代码提交前"到"生产发布前"的完整安全门禁:

  1. 合并请求安全审查——在 MR 阶段并行执行静态与供应链扫描,用 MR 安全组件(Security Widget)呈现增量漏洞;
  2. 容器镜像安全门禁——在镜像构建后、推送注册表前用 Trivy 把关,阻断高于阈值的高危镜像进入制品库;
  3. 针对预发布环境的 DAST 扫描——对部署到 staging 的运行中应用执行认证动态扫描,作为生产发布的手动放行前提;
  4. 漏洞生命周期管理——把各扫描器发现统一收敛进漏洞报告(Vulnerability Report),走"检测→研判→确认/驳回→修复→复扫→解决"的状态闭环。

下文依次深入这四条工作流,并结合 SKILL.md 中的完整流水线配置、references/api-reference.md 中的模板与变量清单、references/standards.md 中的合规映射,以及 scripts 中的报告聚合实现进行佐证与扩展。

前置条件

在开始配置前,需确认满足以下环境前提(来源:SKILL.md):

  • GitLab Ultimate 许可证(完整安全扫描器套件必需);
  • 已配置 GitLab Runner(共享或自托管均可);
  • 熟悉 .gitlab-ci.yml 流水线配置;
  • 容器构建环境:Docker-in-Docker(DinD)或 Kaniko;
  • 已部署一个可供 DAST 扫描的 staging 环境。

工作流一:合并请求安全审查(MR Security Review)

流程骨架

Developer creates merge request
           |
   Pipeline triggers security scanners in parallel:
   [SAST] [Secret Detection] [Dependency Scanning] [License Scanning]
           |
   MR Security Widget displays results:
   - New vulnerabilities introduced
   - Existing vulnerabilities fixed
   - Comparison with target branch
           |
   [No Critical/High] --> Reviewers can approve and merge
   [Critical/High found] --> MR blocked by approval policy
           |
   Security team reviews findings
           |
   [Confirmed] --> Developer remediates and re-pushes
   [False Positive] --> Dismissed with documented reason
           |
   All findings resolved --> MR eligible for merge

关键实现

流水线通过 include 引入 GitLab 托管安全模板,使 SAST、密钥检测、依赖扫描、许可证扫描在 security 阶段并行触发:

# .gitlab-ci.yml(节选)
include:
  - template: Security/SAST.gitlab-ci.yml
  - template: Security/Secret-Detection.gitlab-ci.yml
  - template: Security/Dependency-Scanning.gitlab-ci.yml
  - template: Security/License-Scanning.gitlab-ci.yml

sast:
  stage: security
  variables:
    SAST_EXCLUDED_PATHS: "spec,test,tests,tmp,node_modules"
    SEARCH_MAX_DEPTH: 10

模板对应的底层扫描器可从 references/api-reference.md 的扫描工具表中确认:SAST 覆盖 Semgrep(多语言)、Bandit(Python)等;密钥检测由 Gitleaks 在 Git 历史中扫描硬编码凭据。MR 安全组件会针对目标分支基线展示三条增量信息:本 MR 新引入的漏洞、本 MR 已修复的漏洞、与目标分支的对比。

门禁与策略配置

要使"Critical/High 阻断合并"真正生效,需要在 Security & Compliance > Policies 中创建两类策略(来源:SKILL.md):

  1. Scan Execution Policy:要求所有分支强制运行 SAST 与密钥检测;
  2. Merge Request Approval Policy:当检测到关键漏洞时,要求安全团队审批后方可合并。

资产模板 assets/template.md 中提供了策略配置检查表,便于逐项确认扫描执行策略的生效范围(所有分支/仅默认分支)与 MR 审批策略的严重度触发条件、审批人名单。

增量扫描与缓存优化

MR 场景下可开启增量扫描:设置 SAST_INCREMENTAL: "true" 让 SAST 仅扫描变更文件;同时使用 CI 缓存减少依赖下载时间。默认情况下安全扫描器之间互不依赖,可并行执行(来源:SKILL.md 的 Pipeline Optimization 小节)。

工作流二:容器镜像安全门禁(Container Image Security Gate)

流程骨架

Docker image built in CI
           |
   Container scanning (Trivy) analyzes image layers
           |
   Findings categorized by severity
           |
   [Below threshold] --> Image pushed to registry with metadata
   [Above threshold] --> Pipeline fails, image not pushed
           |
   Registry stores scan results as artifact
           |
   Deployment pulls only scanned/approved images

关键实现

镜像在 build 阶段构建并推送到 GitLab 容器注册表后,security 阶段的 container_scanning 作业使用 Trivy 对镜像层进行 CVE 扫描。在 SKILL.md 的完整配置中,容器扫描作业通过以下变量把关:

build:
  stage: build
  image: docker:24.0
  services:
    - docker:24.0-dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $DOCKER_IMAGE .
    - docker push $DOCKER_IMAGE

container_scanning:
  stage: security
  variables:
    CS_IMAGE: $DOCKER_IMAGE
    CS_SEVERITY_THRESHOLD: "HIGH"
  • CS_IMAGE 指定要扫描的镜像(对应 references/api-reference.md 中的安全变量表);
  • CS_SEVERITY_THRESHOLD: "HIGH" 表示当镜像存在 High 及以上严重度漏洞时作业失败、镜像不被放行;
  • 扫描结果作为制品存储于注册表元数据中,后续部署只拉取已扫描且通过门禁的镜像。

scripts/agent.pygenerate_gitlab_ci() 中可以看到同一逻辑的程序化表达:当启用 container_scanning 阶段时,自动在 variables 中写入 CS_IMAGE{registry}/$CI_PROJECT_PATH:$CI_COMMIT_SHA),保证扫描目标与本次提交构建的镜像一致。

工作流三:针对预发布环境的 DAST 扫描(DAST Against Staging)

流程骨架

Application deployed to staging
           |
   DAST browser scan initiated against staging URL
           |
   Authenticated scan crawls application pages
           |
   Active testing for XSS, SQLi, CSRF, etc.
           |
   Results added to vulnerability report
           |
   [Pass] --> Manual deploy-to-production gate enabled
   [Fail on critical] --> Staging deployment rolled back
           |
   Production deploy requires manual approval

关键实现

DAST 属于动态测试,针对运行中的应用发起攻击载荷,可发现静态分析无法覆盖的运行时漏洞(XSS、SQLi、CSRF 等),因此要求目标已部署且可访问。完整配置中,DAST 通过 needs 依赖 staging 部署作业,仅对默认分支触发:

deploy-staging:
  stage: deploy-staging
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/app app=$DOCKER_IMAGE -n staging
    - kubectl rollout status deployment/app -n staging --timeout=300s
  environment:
    name: staging
    url: https://staging.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

dast:
  stage: dast
  variables:
    DAST_WEBSITE: https://staging.example.com
    DAST_FULL_SCAN_ENABLED: "true"
    DAST_BROWSER_SCAN: "true"
  needs:
    - deploy-staging
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  • DAST_WEBSITE:目标 URL(对应 references/api-reference.md 的安全变量表);
  • DAST_FULL_SCAN_ENABLED: "true":启用全量主动测试(对应 api-reference 中 ZAP 作为 DAST 底层引擎);
  • DAST_BROWSER_SCAN: "true":浏览器扫描模式,可爬取并测试应用页面;
  • 认证扫描(Token/Cookie 方式)可根据环境在 assets/template.md 的"Environment-Specific DAST Targets"表中规划,区分被动扫描与全量扫描。

生产门禁

生产部署作业 deploy-production 被设为 when: manual,即只有 DAST 通过后由人工手动触发,从而实现"手动部署到生产"的门禁:

deploy-production:
  stage: deploy-production
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/app app=$DOCKER_IMAGE -n production
    - kubectl rollout status deployment/app -n production --timeout=300s
  environment:
    name: production
    url: https://app.example.com
  when: manual
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

工作流四:漏洞生命周期管理(Vulnerability Lifecycle Management)

流程骨架

Scanner detects vulnerability
           |
   Status: "Detected" in vulnerability report
           |
   Security analyst triages finding
           |
   [Confirmed vulnerability]        [False positive]
           |                              |
   Status: "Confirmed"              Status: "Dismissed"
   Issue created automatically      Reason documented
           |
   Developer assigned fix
           |
   Fix merged, scanner re-runs
           |
   Vulnerability no longer detected
           |
   Status: "Resolved"

漏洞报告与状态流转

GitLab 将各扫描器(SAST、DAST、容器、依赖、密钥)的发现统一收敛到 Security & Compliance > Vulnerability Report。每条漏洞记录包含(来源:SKILL.md):

  • 严重度评级:Critical、High、Medium、Low、Info;
  • 扫描器来源:SAST / DAST / Container / Dependency / Secret;
  • 漏洞位置:源码位置或镜像层;
  • 修复建议与推荐补丁;
  • 状态追踪:Detected(检测到)、Confirmed(已确认)、Dismissed(已驳回)、Resolved(已解决)。

状态机语义即上方骨架:扫描器发现后为 Detected;安全分析师研判后确认漏洞进入 Confirmed 并自动创建 Issue 指派开发者,或作为误报进入 Dismissed(必须记录原因);修复合并后扫描器复扫不再检出,状态转为 Resolved

使用 API 与脚本推进闭环

状态流转、覆盖率统计与合规报告可通过 GitLab API 自动驱动。本仓库 references/api-reference.md 给出了两个关键接口:

  • 流水线配置校验:POST /api/v4/projects/:id/ci/lint(携带 PRIVATE-TOKEN,请求体为 {"content": "yaml-string"});
  • 漏洞发现查询:GET /api/v4/projects/:id/vulnerability_findings

scripts/process.py 实现了跨项目聚合上报:通过 GET /api/v4/groups/{group_id}/projects?include_subgroups=true 枚举组内项目,再查询各项目 state=detected 的漏洞与最近成功流水线的作业,统计六类扫描器(sast、secret_detection、dependency_scanning、container_scanning、dast、license_scanning)的启用覆盖率、按严重度的漏洞总量与 Top 10 高危项目,最终输出 JSON 报告(默认文件名 gitlab_devsecops_report_YYYYMMDD.json)。运行方式:

export GITLAB_TOKEN=<token>
export GITLAB_URL=https://gitlab.com   # 可选,默认 gitlab.com
export GITLAB_GROUP_ID=<group_id>
python3 scripts/process.py

对应地,scripts/agent.py 是一个流水线生成代理:根据所选安全阶段与项目类型(python/javascript/java/go)生成 .gitlab-ci.yml 结构,支持 --stages--project-type--gitlab-url--token--project-id 等参数,并可通过 POST /ci/lint 接口在线校验配置合法性,同时计算安全阶段覆盖率(如启用全部六类阶段则报告 "Full coverage")。

扫描器覆盖矩阵:多类漏洞的防线选择

不同漏洞类型应优先选用不同的扫描器组合。根据 references/standards.md 的覆盖矩阵:

漏洞类型 主扫描器 辅助扫描器
SQL 注入 SAST(Semgrep) DAST
XSS SAST DAST
SSRF SAST DAST
命令注入 SAST DAST
不安全反序列化 SAST N/A
依赖中的已知 CVE 依赖扫描 容器扫描
硬编码凭据 密钥检测 SAST
许可证违规 许可证扫描 N/A
镜像中的 OS 级 CVE 容器扫描 N/A
认证缺陷 DAST SAST

这张矩阵说明:SAST 负责在源码层广覆盖注入类缺陷,DAST 负责在运行时验证可利用性,依赖扫描与容器扫描分别覆盖源码级依赖与镜像层 OS 包,密钥检测与许可证扫描各司其职,共同织成多层防线。

合规与成熟度映射

将流水线工作流对齐外部框架,可将其作为审计与持续改进的依据:

OWASP DevSecOps Pipeline 成熟度模型(来源:references/standards.md):

等级 SAST DAST SCA 容器 密钥 许可证
L1 基础 手动运行 手动依赖检查 预提交钩子
L2 集成 MR 触发 定时扫描 CI 触发 构建时扫描 提交时 CI 扫描 CI 触发
L3 强制 合并必需 部署前门禁 阻断关键 CVE 阻断高危镜像 推送保护 策略强制
L4 优化 自定义规则、误报调优 认证全量扫描 自动修复 PR 仅签名镜像 自动轮换 SBOM 生成

本文四条工作流对应的配置即处于 L3(强制)级别:MR 阻断、部署前 DAST 门禁、容器镜像阈值阻断、密钥推送保护等。

NIST SP 800-218(SSDF)映射(节选):PW.5(安全地创建源码)对应 SAST 与密钥检测;PW.7(审查与测试代码)对应 MR 安全组件;PW.8(测试可执行代码)对应 DAST;PW.9(安全配置软件)对应容器扫描;RV.1/RV.2/RV.3 对应漏洞报告、严重度分级与 Issue 跟踪。

CIS 软件供应链安全(SCS):SCS-1 保护分支与签名提交、SCS-2 固定模板版本与 Runner 隔离、SCS-3 依赖扫描与许可证合规、SCS-4 容器扫描与镜像签名、SCS-5 手动门禁与环境审批——与工作流二、三中的镜像门禁与手动生产部署一一对应。

此外,SKILL.md 的元数据声明该技能对齐 NIST CSF 的 PR.PS-01、GV.SC-07、ID.IM-04、PR.PS-04 控制项,并映射 MITRE ATT&CK 的 T1195(供应链投毒)、T1552.001(凭据泄露)、T1190(暴露的漏洞利用入口)等战术,说明该流水线同时服务于供应链安全与攻防对抗视角。

监控指标与持续运营

流水线工作流上线后,建议围绕以下指标建立运营闭环(目标值来源:SKILL.md 的 Monitoring and Metrics 表格):

指标 说明 建议目标
流水线安全覆盖率 已启用全部扫描器的项目占比 > 95%
关键漏洞 MTTR 关键漏洞从发现到解决耗时 < 48 小时
误报率 被驳回为误报的发现占比 < 15%
密钥检测阻断率 被推送规则阻断的含密钥提交占比 > 99%

这些指标中的"扫描器覆盖率"与"按严重度漏洞统计"恰好可由 scripts/process.py 直接产出,形成"流水线配置 → 自动聚合 → 指标度量"的完整闭环。assets/template.md 还给出了按严重度划分的 SLA 基线(Critical:4 小时完成研判、24 小时完成修复、48 小时总 SLA),可作为漏洞生命周期管理中状态流转的时效约束。

小结

本仓库通过 workflows.md 定义了 MR 安全审查、容器镜像安全门禁、staging DAST 扫描、漏洞生命周期管理四条核心工作流,配合 SKILL.md 的完整 .gitlab-ci.yml 配置、references/api-reference.md 的模板与变量参考、references/standards.md 的合规映射,以及 scripts 中的配置生成与覆盖率评估脚本,构成了从"安全左移"到"生产门禁"、再到"持续度量"的完整 DevSecOps 落地路径。读者可据此在自己的 GitLab 项目中直接套用上述流水线结构,并结合 ci/lint API 校验配置、用报告脚本跟踪安全运营指标,逐步将流水线从"集成级"推进到"强制级"乃至"优化级"。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
900
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
927
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.94 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
603
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
396
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
527