# Building Devsecops Pipeline With Gitlab CI

> 在 GitLab CI/CD 中设计并实现全面的 DevSecOps 流水线，集成 SAST、DAST、容器扫描、依赖扫描和密钥检测。

- Skill: `killvxk/building-devsecops-pipeline-with-gitlab-ci` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add killvxk/building-devsecops-pipeline-with-gitlab-ci`
- Raw SKILL.md: https://api.skillmd.com/api/skills/killvxk/building-devsecops-pipeline-with-gitlab-ci/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- License: Apache-2.0
- Author: killvxk (https://skillmd.com/u/killvxk)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/killvxk/building-devsecops-pipeline-with-gitlab-ci

---


# 使用 GitLab CI 构建 DevSecOps 流水线

## 概述

GitLab 提供了一个集成的 DevSecOps 平台，将安全测试直接嵌入 CI/CD 流水线。通过利用 GitLab 内置的安全扫描器——SAST、DAST、容器扫描、依赖扫描、密钥检测和许可证合规——团队可以将安全左移（Shift Left），在开发阶段而非部署后发现漏洞。GitLab Duo AI 协助进行 SAST 漏洞的误报检测，帮助安全团队专注于真正的问题。

## 前置条件

- GitLab Ultimate 许可证（完整安全扫描器套件所需）
- 已配置 GitLab Runner（共享或自托管）
- 熟悉 `.gitlab-ci.yml` 流水线配置
- 用于容器构建的 Docker-in-Docker（DinD）或 Kaniko
- 部署到暂存（Staging）环境的应用程序（用于 DAST 扫描）

## 核心安全扫描阶段

### 静态应用安全测试（SAST）

SAST 在编译前分析源代码中的漏洞。GitLab 使用 Semgrep、SpotBugs、Gosec、Bandit 和 NodeJsScan 等分析器支持 14+ 种语言。最简单的集成方式是使用 GitLab 托管的模板。

### 动态应用安全测试（DAST）

DAST 通过向 HTTP 端点模拟攻击载荷来测试运行中的应用程序。它能检测静态分析无法发现的 XSS、SQLi、CSRF 和其他运行时漏洞。DAST 需要已部署的、可访问的目标 URL。

### 容器扫描（Container Scanning）

使用 Trivy 扫描 Docker 镜像中 OS 包和应用依赖的已知 CVE。在 Docker 构建阶段之后运行，在镜像进入仓库前进行门控。

### 依赖扫描（Dependency Scanning）

检查依赖清单（package.json、requirements.txt、pom.xml、Gemfile.lock）中的已知漏洞版本。在源代码级别运行，是容器扫描的补充。

### 密钥检测（Secret Detection）

使用模式匹配和熵分析扫描提交中意外提交的凭据、API 密钥、令牌和私钥。在每次提交时运行，防止密钥进入仓库。

## 实施

### 完整流水线配置

```yaml
# .gitlab-ci.yml

stages:
  - build
  - test
  - security
  - deploy-staging
  - dast
  - deploy-production

variables:
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
  SECURE_LOG_LEVEL: "info"

# 引入 GitLab 托管的安全模板
include:
  - template: Security/SAST.gitlab-ci.yml
  - template: Security/Secret-Detection.gitlab-ci.yml
  - template: Security/Dependency-Scanning.gitlab-ci.yml
  - template: Security/Container-Scanning.gitlab-ci.yml
  - template: DAST.gitlab-ci.yml
  - template: Security/License-Scanning.gitlab-ci.yml

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
  rules:
    - if: $CI_COMMIT_BRANCH

unit-tests:
  stage: test
  image: $DOCKER_IMAGE
  script:
    - npm ci
    - npm run test:coverage
  coverage: '/Lines\s*:\s*(\d+\.?\d*)%/'
  artifacts:
    reports:
      junit: junit-report.xml
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

# 覆盖 SAST 以在 security 阶段运行
sast:
  stage: security
  variables:
    SAST_EXCLUDED_PATHS: "spec,test,tests,tmp,node_modules"
    SEARCH_MAX_DEPTH: 10

# 覆盖容器扫描
container_scanning:
  stage: security
  variables:
    CS_IMAGE: $DOCKER_IMAGE
    CS_SEVERITY_THRESHOLD: "HIGH"

# 覆盖依赖扫描
dependency_scanning:
  stage: security

# 覆盖密钥检测
secret_detection:
  stage: security

# 许可证合规扫描
license_scanning:
  stage: security

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 在已部署的暂存环境上运行
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

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
```

### 安全审批策略

配置扫描执行策略以强制执行必要的安全扫描：

1. 导航到 Security & Compliance > Policies
2. 创建"Scan Execution Policy"，要求在所有分支上执行 SAST 和密钥检测
3. 创建"Merge Request Approval Policy"，要求在检测到严重漏洞时由安全团队审批

### 自定义 SAST 规则集配置

创建 `.gitlab/sast-ruleset.toml` 以自定义分析器行为：

```toml
[semgrep]
  [[semgrep.ruleset]]
    dirs = ["src"]

  [[semgrep.passthrough]]
    type = "url"
    target = "/sgrep-rules/custom-rules.yml"
    value = "https://semgrep.dev/p/owasp-top-ten"

  [[semgrep.passthrough]]
    type = "url"
    target = "/sgrep-rules/java-rules.yml"
    value = "https://semgrep.dev/p/java"
```

## 安全仪表盘与漏洞管理

### 漏洞报告

GitLab 将所有扫描器发现的问题整合到单一漏洞报告中，可通过 Security & Compliance > Vulnerability Report 访问。每个漏洞包括：
- 严重性评级（Critical、High、Medium、Low、Info）
- 扫描器来源（SAST、DAST、Container、Dependency、Secret）
- 在源代码或镜像层中的位置
- 修复指南和建议修复方案
- 状态跟踪（Detected、Confirmed、Dismissed、Resolved）

### 合并请求安全组件

每个合并请求都显示安全扫描组件，显示：
- 该 MR 引入的新漏洞
- 该 MR 修复的漏洞
- 与目标分支基线的对比

## 流水线优化

- **并行执行**：安全扫描器在 security 阶段并发运行
- **缓存**：使用 CI 缓存来加速依赖下载
- **增量扫描**：SAST 可使用 `SAST_INCREMENTAL: "true"` 仅扫描变更文件
- **失败条件**：在关键扫描器上设置 `allow_failure: false` 以强制执行质量门控

## 监控与指标

| 指标 | 描述 | 目标 |
|--------|-------------|--------|
| 流水线安全覆盖率 | 启用了所有扫描器的项目百分比 | > 95% |
| 严重漏洞 MTTR | 从检测到修复严重发现的时间 | < 48 小时 |
| 误报率 | 被标记为误报而关闭的发现百分比 | < 15% |
| 密钥检测拦截率 | 被推送规则拦截的密钥提交百分比 | > 99% |

## 参考资料

- [GitLab 安全扫描文档](https://docs.gitlab.com/ee/user/application_security/)
- [GitLab SAST 分析器](https://docs.gitlab.com/ee/user/application_security/sast/)
- [GitLab DAST 配置](https://docs.gitlab.com/ee/user/application_security/dast/)
- [GitLab 安全策略](https://docs.gitlab.com/ee/user/application_security/policies/)
- [GitLab 漏洞管理](https://docs.gitlab.com/ee/user/application_security/vulnerability_report/)

