云原生环境变化快、组件多、攻击面大——“上线后请安全团队做渗透"的传统模式,在每天发布几十次的节奏下完全失效。安全左移(Shift-Left)的核心是:把安全检查从"上线后"提前到"每次提交、每次构建、每次部署"里,用自动化门禁把风险挡在进入生产之前。本指南按流水线的推进顺序展开防线:镜像扫描(Trivy/Grype)→ IaC 扫描(tfsec/Checkov/OPA)→ 运行时安全(gVisor/Falco)→ 准入控制(Kyverno/Gatekeeper)→ 质量阈值门禁 → SBOM 依赖治理 → CIS 安全基线。
目录
- 1. 为什么安全要"左移”
- 2. 镜像扫描:Trivy / Grype
- 3. IaC 扫描:tfsec / Checkov / OPA
- 4. 容器运行时安全:gVisor / Falco
- 5. 准入控制:Kyverno / Gatekeeper
- 6. 流水线安全门禁:质量阈值拦截
- 7. SBOM 与依赖治理
- 8. 安全基线 CIS
- 9. 最佳实践与避坑
1. 为什么安全要"左移"
1.1 传统安全模式的失效
传统模式:开发 → 测试 → 部署 → 上线 → 安全测试(渗透/扫描)
- 反馈太晚:漏洞到上线后才发现,修复成本高 10~100 倍
- 节奏不匹配:安全测试以周为单位,CI/CD 以分钟为单位
- 责任分离:开发不懂安全,安全不懂流水线 → 互相甩锅
左移:把安全能力织进 CI/CD 每一环
提交扫密钥 → 构建扫依赖 → 出包扫镜像 → 部署验策略 → 运行时检测
1.2 左移的价值量化
| 发现阶段 | 修复相对成本 | 反馈速度 |
|---|---|---|
| 编码时 | 1x | 秒级 |
| 构建时 | 10x | 分钟级 |
| 测试时 | 50x | 小时级 |
| 上线后 | 100x | 天/周级 |
💡 核心观点:左移不是"删掉上线的安全检查",而是"把检查往前叠加"。上线后该扫的照扫,只是大部分问题已经在前置门禁被拦下。
2. 镜像扫描:Trivy / Grype
2.1 扫描工具对比
| 工具 | 数据源 | 支持格式 | 特点 |
|---|---|---|---|
| Trivy | OS + 语言依赖 + IaC + SBOM | 多格式 | 一体化,Go 单二进制,CI 友好 |
| Grype | OS + 语言依赖 | CycloneDX | Anchore 出品,与 Syft 深度集成 |
| Clair | OS 层 | — | 静态分析,与 Quay 集成 |
| Snyk | 语言依赖 + 镜像 | — | SaaS 漏洞库全,成本高 |
2.2 Trivy 实战
# 扫描本地镜像
trivy image registry:5000/shop/api:v1.2.3
# 指定严重级别 + 输出 SARIF(给 CI 展示)
trivy image --severity CRITICAL,HIGH \
--format sarif --output trivy.sarif registry:5000/shop/api:v1.2.3
# 只扫新增漏洞(基线对比)
trivy image --severity CRITICAL --ignore-unfixed \
--scanners vuln registry:5000/shop/api:v1.2.3
2.3 扫描进 CI 的两种方式
# 方式一:GitHub Actions + trivy-action
- name: Trivy scan
uses: aquasecurity/trivy-action@0.24.0
with:
image-ref: registry:5000/shop/api:${GITHUB_SHA}
severity: CRITICAL,HIGH
exit-code: '1'
# 方式二:容器内直接跑(适用于自定义流水线)
docker run --rm aquasec/trivy:latest image \
--severity CRITICAL --exit-code 1 registry:5000/shop/api:${SHA}
门禁设计:CRITICAL 一律拦截(无修复版除外);HIGH 有 patch 拦截、无 patch 记录
新引入漏洞(对基线 diff)优先级最高,一律拦截
3. IaC 扫描:tfsec / Checkov / OPA
3.1 为什么 IaC 也要扫
IaC 定义了生产环境的全部配置——错误配置就是"预埋的漏洞":
- S3 Bucket 设为 Public → 数据泄露
- 安全组 0.0.0.0/0 全开 → 被任意访问
- 数据库无加密、无备份 → 数据裸奔
对策:把"策略即代码"应用到 Terraform/K8s 清单上
tfsec(Terraform 安全扫描)+ Checkov(多 IaC)+ OPA(通用策略引擎)
3.2 tfsec 与 Checkov 对比
| 工具 | 范围 | 规则来源 | 集成 |
|---|---|---|---|
| tfsec | Terraform HCL | 内置 + 自定义 | Trivy 已内嵌 |
| Checkov | TF/K8s/Dockerfile/Bicep 等 | 内置 + 自定义 | PR 评论、CLI |
| OPA/Rego | 任意 JSON/YAML 策略 | 完全自定义 | K8s 准入、Terraform plan |
3.3 实战示例
# tfsec 扫描 Terraform
tfsec . --format sarif --out tfsec.sarif --soft-fail
# Checkov 扫描整个 repo
checkov -d . --framework terraform,kubernetes --output sarif > checkov.sarif
# OPA Rego 示例:禁止安全组全开
package terraform
deny[msg] {
resource := input.resources["aws_security_group_rule"][_]
resource.values.port_range[0] == 0
resource.values.port_range[1] == 0
resource.values.protocol == "-1"
msg := sprintf("安全组 %s 全端口开放", [resource.address])
}
3.4 在 Terraform plan 阶段拦截
# CI 里:terraform plan → OPA 对 plan 输出做策略评估
terraform plan -out plan.tfplan
terraform show -json plan.tfplan | opa eval --data policy/ \
--input - --format json "data.terraform.deny"
# 有 deny 结果 → 流水线失败
4. 容器运行时安全:gVisor / Falco
4.1 运行时防御的两层
第一层 隔离(防逃逸):gVisor 用用户态内核拦截系统调用
第二层 检测(防异常):Falco 监控行为,发现入侵后告警
两者互补:gVisor 让你"更难逃",Falco 让你"更快发现"
4.2 gVisor 沙箱(runsc)
# 在 K8s 里用 gVisor RuntimeClass 隔离不可信工作负载
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: gvisor
handler: runsc
---
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
runtimeClassName: gvisor
containers:
- name: untrusted-job
image: public-image:latest
4.3 Falco 规则:检测异常行为
# falco_rules.yaml:检测容器里启动 shell(常见攻击特征)
- rule: Terminal shell in container
desc: A shell was spawned in a container
condition: spawned_process and container and shell_procs
output: "shell in container (user=%user.name proc=%proc.name)"
priority: WARNING
tags: [tty, container]
# 部署 Falco(DaemonSet)并接告警
kubectl apply -f https://raw.githubusercontent.com/falcosecurity/falco/master/integrations/k8s/falco.yaml
# 告警输出到 stdout / file / Alertmanager / Slack
5. 准入控制:Kyverno / Gatekeeper
5.1 准入控制器是什么
API Server 写入 etcd 前调用准入 Webhook:
Mutating 先改(注入 sidecar/标签)、Validating 后验(违反即拒绝)
方案:Kyverno(K8s 原生 DSL,上手快)/ Gatekeeper(OPA Rego,表达力强)
5.2 Kyverno 策略示例
# 禁止容器以 root 运行 + 强制只读根文件系统
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-non-root
spec:
validationFailureAction: Enforce
rules:
- name: non-root-user
match:
resources:
kinds: [Pod]
validate:
message: "容器必须以非 root 运行"
pattern:
spec:
containers:
- securityContext:
runAsNonRoot: "true"
5.3 双工具对比
| 维度 | Kyverno | Gatekeeper |
|---|---|---|
| 规则语言 | YAML DSL | Rego |
| 上手难度 | 低 | 高(需学 Rego) |
| 自动修复 | 支持 mutate | 有限 |
| 生态 | 新兴 | OPA 生态 |
6. 流水线安全门禁:质量阈值拦截
6.1 把安全质量做成"分数"与"阈值"
综合安全评分 = 漏洞严重度 + 覆盖率 + 合规违例数 + 密钥泄露数
- 评分低于阈值 → 构建失败
- 门禁分级:warning(记录)/ error(拦截)
- 紧急通道:高危业务可申请"风险接受",需安全负责人审批
6.2 一个多检查门禁的 CI 示例
# GitHub Actions:串联多个安全检查
jobs:
security-gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Secret scan
run: gitleaks detect --exit-code 1
- name: IaC scan
run: |
tfsec . --soft-fail
checkov -d . --soft-fail
- name: Dependency audit
run: |
osv-scanner --format json -r . | tee deps.json
- name: Gate decision
run: |
python ci/gate.py --deps deps.json \
--max-critical 0 --max-high 5
6.3 门禁的数据来自哪里
数据来源:漏洞(Trivy/Grype/osv-scanner)、策略违例(OPA/Kyverno)、
密钥(Gitleaks)、依赖(SBOM+漏洞库)→ 汇总 JSON → 门槛脚本判定
7. SBOM 与依赖治理
7.1 SBOM 的用途
SBOM 解决三件事:知道用了什么组件(供应链透明度)、
出漏洞快速定位受影响镜像(应急响应)、满足合规审计(EO 14028 / CRA)
生成:syft packages dir:. -o cyclonedx-json > sbom.json
7.2 依赖漏洞的自动化治理
# osv-scanner:用 Google OSV 数据库扫依赖
osv-scanner -r --format json . > osv.json
# Dependabot / Renovate 自动开升级 PR
# renovate.json 配置自动升级策略
{
"extends": ["config:recommended"],
"automerge": true,
"prHourlyLimit": 4,
"packageRules": [
{ "matchSeverity": "critical", "automerge": true }
]
}
7.3 依赖治理闭环
发现(扫描)→ 评估(严重级/影响面)→ 修复(升级/替换)→ 验证(回归)→ 防复发(门禁)
关键:把"依赖漏洞"也纳入发布门禁,新引入高危依赖直接拦下
8. 安全基线 CIS
8.1 CIS Benchmark 是什么
CIS(Center for Internet Security)发布业界公认的加固基线:
- CIS Kubernetes Benchmark:控制平面/Worker/Etcd 配置加固
- CIS Docker Benchmark:守护进程/容器配置加固
- CIS Distribution 基线:OS 级(Ubuntu/CentOS 等)
目标:给"安全默认配置"一个可核对、可审计的清单
8.2 用 kube-bench 检查 K8s 基线
# 在控制平面节点跑 kube-bench(官方 CIS 检查器)
kubectl apply -f job-kube-bench.yaml
# 输出包含 FAIL/WARN/PASS 清单,关注 FAIL 项
# 关键检查项示例:
# 1.1.1 确保 kube-apiserver 使用 --authorization-mode=RBAC
# 1.2.6 确保 --profiling=false(关闭性能分析接口)
# 4.2.6 确保 etcd 启用 --client-cert-auth
# kube-bench 输出片段(概念)
{
"id": "1.2.6",
"test_number": "1.2.6",
"status": "FAIL",
"desc": "Ensure that the --profiling argument is set to false"
}
8.3 基线落地节奏
1. 先跑一遍基线记录 FAIL 清单
2. 修复"高风险+低成本"项(关 profiling、开 RBAC)
3. 有业务影响的项做风险接受(记录理由与负责人)
4. 基线检查接入定期巡检 + 变更门禁
9. 最佳实践与避坑
9.1 Checklist
□ 镜像扫描(Trivy/Grype)进 CI,CRITICAL/HIGH 门禁拦截
□ IaC 扫描(tfsec/Checkov/OPA)覆盖 Terraform/K8s 清单
□ 运行时隔离(gVisor)用于不可信工作负载
□ Falco 监控异常行为并接告警
□ Kyverno/Gatekeeper 做准入控制(非 root、只读根文件系统)
□ 流水线多检查汇总成统一安全评分 + 阈值门禁
□ SBOM 生成进构建,依赖漏洞用 osv-scanner 治理
□ CIS 基线(kube-bench)定期巡检并纳入变更门禁
□ 每次发布保留 SBOM + 扫描报告(可追溯、可审计)
9.2 常见坑
| 坑 | 现象 | 对策 |
|---|---|---|
| 扫描只看镜像 | 配置/依赖漏洞漏掉 | 全链路多扫描器 |
| 门禁一刀切 | 业务被频繁卡死 | 分级 + 风险接受通道 |
| 只扫不修 | 报告堆成山 | 漏洞闭环流程 |
| Falco 只装不看 | 告警无人处理 | 接 On-Call/Slack |
| 准入规则写太松 | 形同虚设 | Enforce + 定期审计 |
| SBOM 生成了不存 | 应急时找不到 | 随镜像存 Registry |
9.3 一句话原则
安全左移 = "每个提交都被检查,每个缺陷都被拦截,
让漏洞死在 CI 里,而不是活在线上。"
小结
云原生安全左移 = 提交扫密钥(Gitleaks)→ 构建扫依赖与 SBOM(osv-scanner/Syft)→ 出包扫镜像(Trivy/Grype)→ 部署前验策略(OPA/Kyverno)→ 运行时隔离与检测(gVisor/Falco)→ 上线前过 CIS 基线,全程用"质量阈值门禁"把风险挡在生产之外。落地记住五件事:多扫描器全覆盖而不是只扫镜像、门禁分级加风险接受通道、扫描结果必须闭环到修复、准入控制用 Enforce 并持续审计、每次发布留存 SBOM 与扫描报告。当"安全"成为流水线里的一个普通步骤而不是上线后的神秘流程,团队才能真正做到"发布的越快,风险越低"。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。