引言
DevSecOps 的本质是"将安全左移"——在软件开发生命周期的早期阶段发现和修复安全问题,而不是等到上线前再做安全测试。一个漏洞在开发阶段修复的成本是生产阶段的十分之一乃至更低。
但 DevSecOps 知易行难。本文从一个实际的 CI/CD 流水线出发,拆解每个阶段可以嵌入哪些安全工具和策略。
安全流水线总体架构
一个完整的 DevSecOps 流水线通常包含以下几个安全门禁点:
代码提交 → SAST 扫描 → 依赖检查 → 镜像构建
→ 镜像扫描 → 镜像签名 → 部署 → DAST 扫描
→ 合规检查 → K8s 准入控制
每个环节负责不同的安全维度,互不重复、互不替代。
第一阶段:代码安全(SAST)
静态应用安全测试在编译前分析源代码,是最早介入的安全检查。Semgrep 是当前最值得关注的 SAST 工具,它既可以用现成的规则集,也支持编写自定义规则。
CI 集成示例
# GitHub Actions
- name: SAST Scan
uses: semgrep/semgrep-action@v1
with:
config: >-
p/default
p/gitleaks
p/owasp-top-ten
env:
SEMGREP_RULES: >-
p/default
p/gitleaks
env:
SEMGREP_TIMEOUT: 300
自定义规则示例
Semgrep 的最大优势在于规则编写极其直观。下面是一个检测硬编码密码的规则:
rules:
- id: hardcoded-password
patterns:
- pattern: |
$PASS = "..."
- metavariable-regex:
metavariable: $PASS
regex: (password|passwd|pwd|secret)
message: "检测到疑似硬编码密码"
languages:
- go
- python
- java
severity: ERROR
在实际落地的过程中,SAST 的门槛策略建议先设置 WARNING 级别,让团队逐步适应,一两个月后再提升到 ERROR。
第二阶段:依赖安全(SCA)
第三方依赖引入的漏洞是供应链攻击的主要入口。OWASP Top 10 中,“使用已知漏洞的组件"多年位列前茅。
- name: Dependency Scan
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1'
scanners: 'vuln,secret'
Trivy 的 scanners: vuln,secret 参数同时扫描漏洞和硬编码密钥。SBOM 的生成也推荐在这个阶段完成:
# 生成 SPDX 格式的 SBOM
trivy fs --format spdx-json --output sbom.spdx.json .
第三阶段:镜像安全
镜像的完整安全流水线应该包含三道关卡:
关卡 1:基础镜像检查 → 是否使用许可的基础镜像
关卡 2:漏洞扫描 → CRITICAL/HIGH 漏洞阻断
关卡 3:镜像签名 → cosign 签名 + 验签
多架构镜像支持
随着 ARM 架构的普及,构建多架构镜像已是必备能力:
# 创建 manifest 列表
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t ghcr.io/secshu/app:v1.0.0 \
--push .
第四阶段:基础设施即代码检查
Kubernetes 清单文件和 Terraform 代码同样需要安全检查。Checkov 和 kube-score 是两个常用的 IaC 扫描工具:
# Checkov 扫描 K8s 清单
checkov -d . --framework kubernetes
# kube-score 评分
kube-score score deployment.yaml
Checkov 可以检测到以下典型问题:
- 容器设置了
privileged: true - 没有配置资源限制(CPU/Memory)
- 挂载了宿主机的敏感路径
- ServiceAccount 的 automount 未关闭
- 缺少 Pod Disruption Budget
OPA/Gatekeeper 策略即代码
OPA 将策略从配置中解耦出来,用 Rego 语言编写策略,通过 Gatekeeper 在 K8s 集群中强制执行:
# 禁止使用 latest 标签
package k8s.required_labels
violation[{"msg": msg}] {
container := input.request.object.spec.template.spec.containers[_]
endswith(container.image, ":latest")
msg := sprintf("容器 %v 使用了 latest 标签,请指定具体版本", [container.name])
}
第五阶段:运行时安全
部署后的持续监测构成了流水线的最后一段。这一阶段的重点不同于前四个阶段,它不是阻断性问题,而是发现和响应问题:
- K8s 审计日志:持续采集 API Server 的审计日志
- Falco:运行时异常行为检测
- 网络流量:Cilium NetworkPolicy 和 Hubble 观察网络行为
- 合规巡检:kube-bench 定期检查集群配置
工具选型建议
按阶段推荐的免费/开源工具组合:
| 阶段 | 推荐工具 | 备选 |
|---|---|---|
| SAST | Semgrep | CodeQL, SonarQube |
| SCA | Trivy + Grype | Snyk, Dependabot |
| IaC 扫描 | Checkov | KICS, tfsec |
| K8s 清单评分 | kube-score | polaris |
| 镜像签名 | cosign | Notation |
| 策略引擎 | OPA/Gatekeeper | Kyverno |
| 运行时检测 | Falco | Tetragon, Tracee |
| 合规基线 | kube-bench | kubescape |
落地的关键建议
不要追求一次性覆盖所有环节
DevSecOps 落地最大的误区是试图一步到位。推荐的推进路线:
第一阶段:SAST + 依赖扫描(最简单的两个环节)
↓ 等待 2-4 周修复积压问题
第二阶段:镜像扫描 + IaC 检查
↓ 等待 2-4 周修复积压问题
第三阶段:镜像签名 + 准入控制
↓
第四阶段:运行时检测 + 持续监控
指标驱动
通过量化指标来推动安全改进,而不是靠"安全意识”:
- 流水线阻断率:SAST 阻断的构建占总构建的比例
- 平均修复时间(MTTR):从发现到修复的平均时间
- 漏洞数量趋势:随时间变化的漏洞数量曲线
- 门禁通过率:通过安全检查的构建占比
修复反馈闭环
最容易被忽视的一点:安全工具不仅要发现问题,还要把问题推送到开发者最熟悉的地方。Semgrep 和 Trivy 都支持 SARIF 格式输出,可以直接在 GitHub、GitLab 的 PR 中显示批注,让开发者在代码审查时就看到问题。
总结
DevSecOps 不是购买几个安全工具就能实现的,它涉及流程、工具和文化的系统性变化。三个关键原则:
- 渐进式实施:从 SAST+SCA 开始,逐步扩展
- 融入现有流程:安全门禁嵌入 CI/CD,不增加额外的人工环节
- 关注开发者体验:好的 DevSecOps 让开发者感觉"被辅助"而非"被检查"
当你发现安全门禁不再是团队的抱怨对象时,DevSecOps 就真正落地了。