From 6f22d0f5f0a9a0f757c2313084d640a2a0ad6279 Mon Sep 17 00:00:00 2001 From: baohua Date: Thu, 5 Mar 2026 22:19:18 -0800 Subject: [PATCH] Add image security --- 18_security/18.6_image_security.md | 558 +++++++++++++++++++++++++++++ 18_security/README.md | 3 + 2 files changed, 561 insertions(+) create mode 100644 18_security/18.6_image_security.md diff --git a/18_security/18.6_image_security.md b/18_security/18.6_image_security.md new file mode 100644 index 0000000..686b82b --- /dev/null +++ b/18_security/18.6_image_security.md @@ -0,0 +1,558 @@ +## 18.6 容器镜像安全扫描与供应链安全 + +在 DevOps 流程中,容器镜像安全已经成为不容忽视的关键环节。从开发、构建、存储到部署,镜像的整个生命周期都需要安全防护。本节深入讨论镜像漏洞扫描、软件物料清单(SBOM)、镜像签名验证等供应链安全实践。 + +### 18.6.1 容器镜像漏洞扫描工具对比 + +#### Trivy - 轻量级通用扫描器 + +Trivy 是由 Aqua Security 开发的开源漏洞扫描器,以其轻量级、快速、准确而闻名,已成为业界标准。 + +**优点:** +- 零依赖,单个二进制文件 +- 扫描速度快(秒级) +- 支持镜像、文件系统、Git 仓库多种扫描源 +- 数据库每日自动更新 +- 支持多种输出格式(JSON、表格、SBOM 等) + +**安装与基本使用:** + +```bash +# 安装 Trivy +curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin + +# 扫描本地镜像 +trivy image nginx:latest + +# 生成 JSON 格式报告 +trivy image -f json -o report.json nginx:latest + +# 扫描文件系统 +trivy fs /path/to/project + +# 扫描 Git 仓库 +trivy repo https://github.com/aquasecurity/trivy +``` + +**在 CI/CD 中集成:** + +```bash +# 设置严重程度过滤 +trivy image --severity HIGH,CRITICAL \ + --exit-code 1 \ + myregistry.com/myapp:v1.0.0 +``` + +#### Grype - 支持多种软件包的扫描器 + +Grype 由 Anchore 开发,支持更广泛的软件包管理器和语言。 + +**优点:** +- 支持 Java、Python、Go、Ruby、JavaScript 等多种语言的依赖检测 +- 与 Syft(SBOM 生成器)配合效果好 +- 可自定义漏洞数据库源 +- 支持离线扫描模式 + +**安装与使用:** + +```bash +# 安装 Grype +curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin + +# 扫描镜像 +grype docker:nginx:latest + +# 与 Syft 配合生成 SBOM +syft docker:nginx:latest -o json > sbom.json +grype sbom:sbom.json + +# 扫描特定目录 +grype dir:/path/to/app +``` + +#### Snyk - 完整的安全平台 + +Snyk 提供了商业级的安全扫描服务,特别适合企业环境。 + +**特点:** +- 支持开源漏洞和许可证扫描 +- 与多个 Git 平台深度集成(GitHub、GitLab、Bitbucket) +- 提供修复建议和自动化修复 PR +- 支持 Kubernetes 部署后安全监控 + +**基本使用:** + +```bash +# 安装 Snyk CLI +npm install -g snyk + +# 认证 +snyk auth + +# 扫描镜像 +snyk container test docker-archive://image.tar + +# 监控仓库 +snyk monitor --docker +``` + +**工具对比表:** + +| 特性 | Trivy | Grype | Snyk | +|------|-------|-------|------| +| 零依赖 | ✓ | ✗ | ✗ | +| 离线模式 | ✓ | ✓ | ✗ | +| 许可证扫描 | ✗ | ✓ | ✓ | +| 自动修复 | ✗ | ✗ | ✓ | +| 开源免费 | ✓ | ✓ | 部分 | +| IDE 集成 | ✓ | ✓ | ✓ | + +### 18.6.2 SBOM(软件物料清单)生成与管理 + +SBOM(Software Bill of Materials)是一份详细列表,记录了软件中使用的所有组件、依赖库及其版本信息。SBOM 在供应链安全中至关重要,特别是在发现新的安全漏洞时,能快速定位受影响的应用。 + +#### Syft - SBOM 生成工具 + +Syft 是 Anchore 推出的专业 SBOM 生成工具。 + +**安装:** + +```bash +curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin +``` + +**生成 SBOM:** + +```bash +# 从镜像生成 SBOM(多种格式) +syft docker:nginx:latest -o json > sbom.json +syft docker:nginx:latest -o spdx > sbom.spdx +syft docker:nginx:latest -o cyclonedx > sbom.xml + +# 从本地文件系统生成 +syft dir:/path/to/app -o json > sbom.json + +# 从 OCI 镜像档案生成 +syft oci-archive:image.tar -o json > sbom.json +``` + +#### CycloneDX 与 SPDX 格式 + +两种主流的 SBOM 格式: + +**CycloneDX 格式示例:** + +```xml + + + + + openssl + 1.1.1k + pkg:deb/debian/openssl@1.1.1k-1+deb11u5 + + + curl + 7.74.0-1.3+deb11u1 + pkg:deb/debian/curl@7.74.0-1.3+deb11u1 + + + +``` + +**SPDX 格式示例:** + +```json +{ + "SPDXID": "SPDXRef-DOCUMENT", + "spdxVersion": "SPDX-2.2", + "creationInfo": { + "created": "2024-03-01T12:00:00Z", + "creators": ["Tool: syft"] + }, + "packages": [ + { + "SPDXID": "SPDXRef-Package-openssl", + "name": "openssl", + "versionInfo": "1.1.1k", + "downloadLocation": "NOASSERTION" + } + ] +} +``` + +#### SBOM 的应用场景 + +**漏洞关联:** + +当新的 CVE 被发现时,可快速查询受影响的应用: + +```bash +# 使用 Grype 针对 SBOM 进行漏洞扫描 +grype sbom:sbom.json --add-cpes-if-none +``` + +**合规性报告:** + +将 SBOM 保存为构建产物,用于审计和合规性检查。 + +**依赖升级决策:** + +通过分析 SBOM 中的依赖版本,制定安全升级计划。 + +### 18.6.3 镜像签名与验证(Cosign/Notary) + +镜像签名确保镜像的来源可信且未被篡改。两种主流方案是 Cosign 和 Notary。 + +#### Cosign - 现代签名解决方案 + +Cosign 是 Sigstore 项目的核心工具,支持无密钥签名,适合现代 CI/CD 流程。 + +**安装:** + +```bash +wget https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64 +chmod +x cosign-linux-amd64 +sudo mv cosign-linux-amd64 /usr/local/bin/cosign +``` + +**生成密钥对(传统方式):** + +```bash +cosign generate-key-pair +# 生成 cosign.key 和 cosign.pub +``` + +**签名镜像:** + +```bash +# 使用私钥签名(推送到仓库前) +cosign sign --key cosign.key myregistry.com/myapp:v1.0.0 + +# 系统会提示输入私钥密码 +``` + +**验证签名:** + +```bash +# 使用公钥验证 +cosign verify --key cosign.pub myregistry.com/myapp:v1.0.0 + +# 输出结果示例 +# Verification successful! +# { +# "critical": { +# "identity": {...}, +# "image": {...}, +# "type": "cosign container image signature" +# }, +# "optional": {...} +# } +``` + +**Keyless 签名(推荐用于 CI/CD):** + +```bash +# 在 GitHub Actions 等 CI 中无需存储密钥 +cosign sign --yes myregistry.com/myapp:v1.0.0 + +# 验证时自动使用 OIDC 令牌验证身份 +cosign verify myregistry.com/myapp:v1.0.0 \ + --certificate-identity https://github.com/myorg/myrepo/.github/workflows/build.yml@refs/heads/main \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com +``` + +#### Docker Content Trust(DCT)与 Notary + +Docker Content Trust 使用 Notary 实现镜像签名,是 Docker 官方的签名解决方案。 + +**启用 DCT:** + +```bash +# 在环境中启用 DCT +export DOCKER_CONTENT_TRUST=1 + +# 此后所有 docker push/pull 都需要签名 +docker push myregistry.com/myapp:v1.0.0 +# 如果镜像未签名,操作会被拒绝 + +# 禁用 DCT(仅用于特定操作) +docker push --disable-content-trust myregistry.com/myapp:v1.0.0 +``` + +**签名密钥管理:** + +```bash +# 首次推送时会提示创建 Delegation Key +# 密钥存储在 ~/.docker/trust/private/root_keys/ 和 ~/.docker/trust/private/tuf_keys/ + +# 查看签名信息 +docker inspect --format='{{.RepoDigests}}' myregistry.com/myapp:v1.0.0 +``` + +### 18.6.4 供应链安全最佳实践 + +#### 1. 基础镜像安全 + +```dockerfile +# ❌ 不推荐:使用 latest 标签 +FROM ubuntu:latest +RUN apt-get update && apt-get install -y curl + +# ✓ 推荐:固定基础镜像版本和摘要 +FROM ubuntu:22.04@sha256:a6d2b38300ce017add71440577d5b0a90460d0e6... +RUN apt-get update && apt-get install -y curl=7.68.0-1ubuntu1 +``` + +#### 2. 构建时扫描 + +在 Dockerfile 中集成安全扫描: + +```dockerfile +FROM golang:1.20-alpine AS builder +WORKDIR /app +COPY . . + +# 使用 Trivy 扫描源代码 +RUN apk add --no-cache curl && \ + curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin && \ + trivy fs . --exit-code 1 --severity HIGH,CRITICAL + +RUN go build -o app . + +FROM alpine:3.17@sha256:abcd... +COPY --from=builder /app/app /app +``` + +#### 3. 运行时镜像扫描策略 + +```bash +# 镜像构建完成后立即扫描 +trivy image --severity HIGH,CRITICAL \ + --exit-code 1 \ + --timeout 30m \ + $IMAGE_NAME:$IMAGE_TAG + +# 定期扫描已部署的镜像 +trivy image --scanners vuln,misconfig registry:5000/myapp:latest +``` + +#### 4. 镜像仓库安全配置 + +**Harbor(私有镜像仓库)的安全扫描:** + +```yaml +# harbor.yml 配置示例 +trivy: + enabled: true + # 启用镜像扫描 + image_source: "Official" + +# 默认扫描配置 +scan_on_push: true # 推送时自动扫描 +scan_all: true # 扫描仓库中的所有镜像 +``` + +#### 5. 政策执行(Admission Controller) + +在 Kubernetes 环境中使用 Admission Webhook 强制镜像签名和扫描: + +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: image-security-policy +webhooks: +- name: image-security.example.com + clientConfig: + service: + name: image-security-webhook + namespace: security + path: "/validate" + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + admissionReviewVersions: ["v1"] + sideEffects: None +``` + +### 18.6.5 CI/CD 中集成安全扫描 + +#### GitHub Actions 工作流示例 + +```yaml +name: Build and Scan Image + +on: + push: + branches: [main, develop] + pull_request: + branches: [main] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-scan: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + security-events: write + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Build Docker image + uses: docker/build-push-action@v4 + with: + context: . + push: false + load: true + tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + + - name: Run Trivy vulnerability scan + uses: aquasecurity/trivy-action@master + with: + image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + format: 'sarif' + output: 'trivy-results.sarif' + severity: 'HIGH,CRITICAL' + + - name: Upload Trivy results to GitHub Security tab + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: 'trivy-results.sarif' + + - name: Generate SBOM + uses: anchore/sbom-action@v0 + with: + image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + format: cyclonedx-json + output-file: sbom-cyclonedx.json + + - name: Upload SBOM + uses: actions/upload-artifact@v3 + with: + name: sbom + path: sbom-cyclonedx.json + + - name: Sign image with Cosign + if: github.event_name == 'push' + env: + COSIGN_EXPERIMENTAL: 1 + run: | + cosign sign --yes ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + + - name: Login to Registry and Push + if: github.event_name == 'push' + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Push image + uses: docker/build-push-action@v4 + with: + context: . + push: true + tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest +``` + +#### GitLab CI 工作流示例 + +```yaml +stages: + - build + - scan + - sign + - push + +variables: + REGISTRY: registry.gitlab.com + IMAGE_NAME: $REGISTRY/$CI_PROJECT_PATH + +build: + stage: build + image: docker:latest + services: + - docker:dind + script: + - docker build -t $IMAGE_NAME:$CI_COMMIT_SHA . + - docker save $IMAGE_NAME:$CI_COMMIT_SHA > image.tar + +scan:trivy: + stage: scan + image: aquasec/trivy:latest + script: + - trivy image --severity HIGH,CRITICAL --exit-code 1 docker-archive://image.tar + allow_failure: false + +scan:grype: + stage: scan + image: anchore/grype:latest + script: + - grype docker-archive://image.tar + +generate:sbom: + stage: scan + image: anchore/syft:latest + script: + - syft docker-archive://image.tar -o cyclonedx > sbom.xml + artifacts: + reports: + sbom: sbom.xml + +sign: + stage: sign + image: gcr.io/projectsigstore/cosign:latest + script: + - cosign sign --key $COSIGN_KEY $IMAGE_NAME:$CI_COMMIT_SHA + only: + - main + +push: + stage: push + image: docker:latest + services: + - docker:dind + script: + - docker load < image.tar + - docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $REGISTRY + - docker push $IMAGE_NAME:$CI_COMMIT_SHA + only: + - main +``` + +### 18.6.6 常见问题与最佳实践 + +**Q: 扫描报告中有过时的 CVE,如何处理?** + +A: 某些 CVE 可能已经被修复但数据库未更新,可以: +- 手动验证安全补丁是否已应用 +- 使用工具的忽略列表功能(如 Trivy 的 `.trivyignore`) +- 定期更新扫描工具和漏洞数据库 + +**Q: 如何平衡镜像大小和安全性?** + +A: +- 使用多阶段构建减少最终镜像大小 +- 使用精简基础镜像(Alpine、Distroless) +- 定期更新依赖而不是一味求小 +- 优先安全性,体积次之 + +**Q: 如何管理和轮换签名密钥?** + +A: +- 在密钥管理系统(如 HashiCorp Vault)中存储密钥 +- 定期轮换密钥(建议每 90 天) +- 使用 Keyless 签名消除密钥管理复杂性 +- 保留密钥轮换的审计日志 diff --git a/18_security/README.md b/18_security/README.md index 5b20824..e014fdf 100644 --- a/18_security/README.md +++ b/18_security/README.md @@ -43,6 +43,9 @@ flowchart LR * [其它安全特性](18.5_other_feature.md) * 镜像安全(漏洞扫描、签名验证)、运行时安全(非 root 运行、只读文件系统、Seccomp、AppArmor)、Dockerfile 安全实践、软件供应链安全(SBOM、SLSA)。 +* [镜像安全](18.6_image_security.md) + * 容器镜像的安全扫描、漏洞检测与签名验证。 + ## 安全扫描清单 部署前检查: