安全左移:将安全融入CI/CD流水线的每一个环节
DevSecOps = Development + Security + Operations,核心思想是"安全左移"(Shift Left Security)——将安全检查从部署前移到开发早期,让安全成为每个人的责任,而不是安全团队的事后审查。
在代码进入仓库之前就进行安全检查,防止漏洞从源头引入。
# ===== Pre-commit安全钩子 =====
# 安装pre-commit框架
pip3 install pre-commit 2>/dev/null || true
# 创建pre-commit配置
cat > /tmp/devsecops/.pre-commit-config.yaml <<'YAML'
repos:
# Semgrep静态分析
- repo: https://github.com/returntocorp/semgrep
rev: v1.45.0
hooks:
- id: semgrep
args: ['--config', 'auto', '--error']
# Gitleaks密钥扫描
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
# 通用代码检查
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
args: ['--maxkb=500']
- id: detect-private-key
YAML
mkdir -p /tmp/devsecops
echo "[+] Pre-commit配置创建完成"
# ===== 手动密钥扫描 =====
# 安装gitleaks
apt-get install -y gitleaks 2>/dev/null || true
# 创建测试仓库
mkdir -p /tmp/test-repo && cd /tmp/test-repo
git init 2>/dev/null
# 模拟密钥泄露
cat > /tmp/test-repo/config.py <<'EOF'
# 危险:硬编码密钥
AWS_SECRET_ACCESS_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
DATABASE_URL = "postgresql://admin:password123@db.internal:5432/prod"
STRIPE_API_KEY = "sk_live_4eC39HqLyjWDarjtT1zdp7dc"
EOF
# 扫描泄露的密钥
echo -e "\n=== 密钥泄露检测 ==="
echo "检测硬编码密钥模式:"
grep -rnE "(SECRET|PASSWORD|API_KEY|TOKEN).*=.*['\"][^'\"]{8,}" \
/tmp/test-repo/ 2>/dev/null | head -5
echo -e "\n检测私钥文件:"
find /tmp/test-repo -name "*.pem" -o -name "*.key" -o -name "id_rsa" 2>/dev/null
echo "[+] 密钥扫描完成"
在CI构建阶段集成SAST、SCA和IaC扫描。
# ===== GitHub Actions安全管线(模拟)=====
cat > /tmp/devsecops/ci-security-pipeline.yml <<'YAML'
name: Security Pipeline
on: [push, pull_request]
jobs:
# 1. SAST静态扫描
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Semgrep Scan
uses: returntocorp/semgrep-action@v1
with:
config: auto
- name: Bandit (Python)
run: |
pip install bandit
bandit -r . -f json -o bandit-report.json
# 2. SCA依赖扫描
sca:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Trivy FS Scan
run: |
trivy fs --severity HIGH,CRITICAL --exit-code 1 .
- name: npm audit
run: npm audit --audit-level=high || true
# 3. 密钥扫描
secret-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Gitleaks
uses: gitleaks/gitleaks-action@v2
# 4. IaC扫描
iac-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkov
run: |
pip install checkov
checkov -d . --framework terraform --severity HIGH,CRITICAL
# 5. 容器镜像扫描
container-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Image
run: docker build -t app:test .
- name: Trivy Image Scan
run: |
trivy image --severity HIGH,CRITICAL --exit-code 1 app:test
YAML
echo "[+] CI安全管线配置创建完成"
# ===== 本地安全扫描脚本 =====
cat > /tmp/devsecops/local_scan.sh <<'SCRIPT'
#!/bin/bash
set -e
TARGET_DIR="${1:-/tmp/vuln-app}"
echo "========================================"
echo " DevSecOps 本地安全扫描"
echo " 目标: $TARGET_DIR"
echo "========================================"
# 1. 密钥扫描
echo -e "\n[1/5] 🔑 密钥泄露扫描"
secrets=$(grep -rnE "(password|secret|api_key|token).*=.*['\"][^'\"]{8,}" \
"$TARGET_DIR" 2>/dev/null | wc -l)
echo " 发现 $secrets 处疑似密钥泄露"
[ "$secrets" -gt 0 ] && grep -rnE "(password|secret|api_key|token).*=.*['\"][^'\"]{8,}" \
"$TARGET_DIR" 2>/dev/null | head -5
# 2. SAST扫描
echo -e "\n[2/5] 🔍 SAST静态分析"
# 检查常见漏洞模式
sqli=$(grep -rn "f\".*SELECT\|execute(" "$TARGET_DIR" 2>/dev/null | wc -l)
cmdi=$(grep -rn "shell=True\|os.system(" "$TARGET_DIR" 2>/dev/null | wc -l)
xss=$(grep -rn "render_template_string\|innerHTML\|v-html" "$TARGET_DIR" 2>/dev/null | wc -l)
echo " SQL注入模式: $sqli"
echo " 命令注入模式: $cmdi"
echo " XSS模式: $xss"
# 3. 依赖扫描
echo -e "\n[3/5] 📦 依赖安全扫描"
if [ -f "$TARGET_DIR/requirements.txt" ]; then
echo " 发现requirements.txt,检查已知漏洞依赖:"
cat "$TARGET_DIR/requirements.txt"
# safety check -r requirements.txt 2>/dev/null
fi
if [ -f "$TARGET_DIR/package.json" ]; then
echo " 发现package.json,运行npm audit:"
# cd "$TARGET_DIR" && npm audit 2>/dev/null
fi
# 4. Dockerfile扫描
echo -e "\n[4/5] 🐳 容器安全扫描"
if [ -f "$TARGET_DIR/Dockerfile" ]; then
echo " 发现Dockerfile,检查安全最佳实践:"
grep -n "RUN.*apt-get install" "$TARGET_DIR/Dockerfile" | while read line; do
if ! echo "$line" | grep -q "no-install-recommends"; then
echo " ⚠️ $line (缺少no-install-recommends)"
fi
done
grep -n "USER " "$TARGET_DIR/Dockerfile" || echo " ❌ 未使用非root用户"
else
echo " 未发现Dockerfile"
fi
# 5. IaC扫描
echo -e "\n[5/5] 📋 IaC配置扫描"
for tf in $(find "$TARGET_DIR" -name "*.tf" 2>/dev/null); do
echo " 发现Terraform文件: $tf"
# 检查公开资源
grep -n "ingress.*0.0.0.0/0" "$tf" 2>/dev/null && \
echo " ❌ 发现公开入站规则" || true
done
echo -e "\n========================================"
echo " 扫描完成!"
echo "========================================"
SCRIPT
chmod +x /tmp/devsecops/local_scan.sh
# 创建测试应用
mkdir -p /tmp/vuln-app
echo "flask==2.0.0" > /tmp/vuln-app/requirements.txt
bash /tmp/devsecops/local_scan.sh /tmp/vuln-app
# ===== 容器镜像安全扫描 =====
# 安装trivy
apt-get install -y trivy 2>/dev/null || true
which trivy &>/dev/null && echo "Trivy已安装" || \
echo "Trivy未安装,使用替代方案"
# ===== 安全Dockerfile =====
cat > /tmp/devsecops/Dockerfile.secure <<'DOCKERFILE'
# ✅ 使用特定版本标签(非latest)
FROM python:3.12-slim-bookworm AS builder
# ✅ 安装依赖时使用no-install-recommends
RUN apt-get update && \
apt-get install -y --no-install-recommends gcc && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# ✅ 多阶段构建(减小攻击面)
FROM python:3.12-slim-bookworm
# ✅ 创建非root用户
RUN groupadd -r appuser && useradd -r -g appuser appuser
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
COPY . .
# ✅ 设置非root用户
USER appuser
# ✅ 健康检查
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8000/health || exit 1
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]
DOCKERFILE
echo "[+] 安全Dockerfile创建完成"
# ===== 模拟镜像扫描 =====
cat > /tmp/devsecops/image_scan.sh <<'SCRIPT'
#!/bin/bash
echo "========================================"
echo " 容器镜像安全扫描"
echo "========================================"
echo -e "\n[1] Dockerfile安全检查"
echo " ✅ 使用特定版本标签(非latest)"
echo " ✅ no-install-recommends减少攻击面"
echo " ✅ 多阶段构建分离编译和运行环境"
echo " ✅ 非root用户运行"
echo " ✅ 健康检查配置"
echo -e "\n[2] 镜像漏洞扫描(模拟)"
echo " 扫描命令: trivy image app:latest"
echo " 扫描结果:"
echo " ├── CRITICAL: 2 (CVE-2024-XXXX, CVE-2024-YYYY)"
echo " ├── HIGH: 5"
echo " ├── MEDIUM: 12"
echo " └── LOW: 8"
echo ""
echo " ❌ 发现2个严重漏洞,构建应中止"
echo -e "\n[3] 镜像安全基线"
echo " ✅ 基础镜像: python:3.12-slim (无高危漏洞)"
echo " ✅ 运行用户: appuser (非root)"
echo " ✅ 暴露端口: 8000 (仅必要端口)"
echo " ❌ SUID/GUID文件: 应移除"
echo " ❌ 敏感文件: 应使用secret挂载"
echo -e "\n========================================"
SCRIPT
chmod +x /tmp/devsecops/image_scan.sh
bash /tmp/devsecops/image_scan.sh
# ===== Open Policy Agent (OPA) 策略 =====
cat > /tmp/devsecops/policy.rego <<'REGO'
package devsecops
# 策略1: 禁止latest标签
deny[msg] {
input.container.image
endswith(input.container.image, ":latest")
msg := sprintf("不允许使用latest标签: %v", [input.container.image])
}
# 策略2: 必须设置资源限制
deny[msg] {
input.container.resources
not input.container.resources.limits
msg := sprintf("容器必须设置资源限制: %v", [input.container.name])
}
# 策略3: 禁止特权容器
deny[msg] {
input.container.securityContext.privileged
msg := sprintf("禁止特权容器: %v", [input.container.name])
}
# 策略4: 必须以非root运行
deny[msg] {
not input.container.securityContext.runAsNonRoot
msg := sprintf("容器必须以非root用户运行: %v", [input.container.name])
}
# 策略5: 禁止hostPath挂载
deny[msg] {
volume := input.container.volumes[_]
volume.hostPath
msg := sprintf("禁止hostPath挂载: %v", [volume.name])
}
REGO
echo "[+] OPA安全策略创建完成"
# ===== 安全门禁配置 =====
cat > /tmp/devsecops/security_gates.sh <<'SCRIPT'
#!/bin/bash
echo "========================================"
echo " CI/CD安全门禁配置"
echo "========================================"
echo -e "\n[1] 安全门禁规则"
echo " ┌─────────────────────────────────────────┐"
echo " │ Gate 1: 密钥扫描 → 0泄露才通过 │"
echo " │ Gate 2: SAST扫描 → 0严重/高危才通过 │"
echo " │ Gate 3: SCA扫描 → 0已知漏洞才通过 │"
echo " │ Gate 4: 镜像扫描 → 0严重漏洞才通过 │"
echo " │ Gate 5: DAST扫描 → 0严重发现才通过 │"
echo " │ Gate 6: 合规检查 → 策略全部通过 │"
echo " └─────────────────────────────────────────┘"
echo -e "\n[2] 门禁执行流程"
echo " Code → Gate1 → Gate2 → Gate3 → Build → Gate4 → Deploy → Gate5 → Gate6 → Prod"
echo " ↓miss ↓miss ↓miss ↓miss ↓miss ↓miss"
echo " BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK"
echo -e "\n[3] 通知与升级"
echo " 严重漏洞: 立即通知安全团队,阻止部署"
echo " 高危漏洞: 通知开发团队,24h内修复"
echo " 中危漏洞: 记录跟踪,下一迭代修复"
echo " 低危漏洞: 记录跟踪,按计划修复"
echo -e "\n========================================"
SCRIPT
chmod +x /tmp/devsecops/security_gates.sh
bash /tmp/devsecops/security_gates.sh
| 阶段 | 工具 | 功能 | 集成方式 |
|---|---|---|---|
| 代码提交 | pre-commit, gitleaks | 密钥扫描/代码格式 | Git Hook |
| 静态扫描 | Semgrep, SonarQube, Bandit | SAST代码分析 | CI Pipeline |
| 依赖扫描 | Trivy, Snyk, Dependabot | SCA漏洞检测 | CI Pipeline |
| 构建安全 | Buildkit, hadolint | Dockerfile检查 | CI Pipeline |
| 镜像扫描 | Trivy, Grype, Clair | 容器漏洞扫描 | 镜像仓库 |
| 部署检查 | OPA, Checkov, Conftest | 策略合规检查 | CD Pipeline |
| 运行时安全 | Falco, Tracee | 运行时监控 | Kubernetes |