# Securing Container Registry Images

> 通过使用 Trivy 和 Grype 实施漏洞扫描、使用 Cosign 和 Sigstore 强制执行镜像签名、配置镜像仓库访问控制，以及构建阻止部署未扫描或未签名镜像的 CI/CD 流水线，来保护容器仓库（Container Registry）中的镜像安全。

- Skill: `killvxk/securing-container-registry-images` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add killvxk/securing-container-registry-images`
- Raw SKILL.md: https://api.skillmd.com/api/skills/killvxk/securing-container-registry-images/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/securing-container-registry-images

---


# 保护容器仓库镜像

## 适用场景

- 为容器镜像仓库（ECR、ACR、GCR、Docker Hub）建立安全管控时
- 构建在镜像晋级前强制执行漏洞扫描的 CI/CD 流水线时
- 实施镜像签名（Image Signing）和验证以防止供应链攻击时
- 审计现有镜像仓库中存在漏洞、未扫描或未签名的镜像时
- 合规要求为已部署容器镜像提供软件物料清单（SBOM，Software Bill of Materials）时

**不适用于**：运行时容器安全（使用 Falco 或 Sysdig）、Kubernetes 准入控制（在建立镜像仓库管控后使用 OPA Gatekeeper 或 Kyverno），或主机级漏洞扫描（使用 Amazon Inspector 或 Qualys）。

## 前置条件

- 已安装 Trivy（`brew install trivy` 或 `apt install trivy`）
- 已安装 Grype（`curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh`）
- 已安装 Cosign（`go install github.com/sigstore/cosign/v2/cmd/cosign@latest`）
- 已安装 Syft 用于生成 SBOM（`curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh`）
- 具备容器镜像仓库访问权限（ECR、ACR、GCR 或私有仓库）

## 工作流程

### 步骤 1：使用 Trivy 扫描镜像漏洞

在推送到镜像仓库前后，对容器镜像运行全面的漏洞扫描。

```bash
# 扫描本地镜像漏洞
trivy image --severity HIGH,CRITICAL myapp:latest

# 扫描远程仓库中的镜像
trivy image --severity HIGH,CRITICAL 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest

# 以 JSON 格式输出供 CI/CD 处理
trivy image --format json --output trivy-results.json myapp:latest

# 同时扫描漏洞和错误配置
trivy image --scanners vuln,misconfig,secret myapp:latest

# 扫描特定镜像并输出 SBOM
trivy image --format spdx-json --output sbom.json myapp:latest

# 发现严重漏洞时使 CI/CD 失败
trivy image --exit-code 1 --severity CRITICAL myapp:latest
```

### 步骤 2：使用 Grype 进行补充扫描

使用 Grype 作为互补扫描器，覆盖更广泛的漏洞数据库。

```bash
# 使用 Grype 扫描镜像
grype myapp:latest

# 设置严重级别阈值
grype myapp:latest --fail-on critical

# 以 JSON 格式输出供处理
grype myapp:latest -o json > grype-results.json

# 扫描 SBOM 而非直接扫描镜像
syft myapp:latest -o spdx-json > sbom.json
grype sbom:sbom.json

# 扫描基于目录的镜像导出
grype dir:/path/to/image-rootfs
```

### 步骤 3：生成软件物料清单（SBOM）

为所有镜像创建 SBOM，以维护软件组件和依赖项的完整清单。

```bash
# 使用 Syft 以 SPDX 格式生成 SBOM
syft myapp:latest -o spdx-json > sbom-spdx.json

# 以 CycloneDX 格式生成 SBOM
syft myapp:latest -o cyclonedx-json > sbom-cyclonedx.json

# 将 SBOM 作为 OCI artifact 附加到镜像
cosign attach sbom --sbom sbom-spdx.json \
  123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest

# 验证 SBOM 内容
syft myapp:latest -o table | head -50
```

### 步骤 4：使用 Cosign 和 Sigstore 签名镜像

实施镜像签名（Image Signing），确保供应链中镜像的完整性和真实性。

```bash
# 生成签名密钥对
cosign generate-key-pair

# 对仓库中的镜像进行签名
cosign sign --key cosign.key \
  123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest

# 使用 Sigstore 的无密钥签名（基于 OIDC）
cosign sign --yes \
  123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest

# 验证镜像签名
cosign verify --key cosign.pub \
  123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest

# 验证无密钥签名
cosign verify \
  --certificate-identity developer@company.com \
  --certificate-oidc-issuer https://accounts.google.com \
  123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest

# 附加包含扫描结果的证明（Attestation）
cosign attest --predicate trivy-results.json \
  --key cosign.key \
  123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest
```

### 步骤 5：配置镜像仓库级别安全控制

为 ECR、ACR 和 GCR 设置各仓库特定的安全功能。

```bash
# AWS ECR：启用推送时自动扫描
aws ecr put-image-scanning-configuration \
  --repository-name myapp \
  --image-scanning-configuration scanOnPush=true

# ECR：设置镜像标签不可变性（防止覆盖标签）
aws ecr put-image-tag-mutability \
  --repository-name myapp \
  --image-tag-mutability IMMUTABLE

# ECR：设置生命周期策略以清理未标记的镜像
aws ecr put-lifecycle-policy \
  --repository-name myapp \
  --lifecycle-policy-text '{
    "rules": [{
      "rulePriority": 1,
      "description": "Remove untagged images after 7 days",
      "selection": {"tagStatus": "untagged", "countType": "sinceImagePushed", "countUnit": "days", "countNumber": 7},
      "action": {"type": "expire"}
    }]
  }'

# ECR：获取某镜像的扫描结果
aws ecr describe-image-scan-findings \
  --repository-name myapp \
  --image-id imageTag=latest \
  --query 'imageScanFindings.findingSeverityCounts'

# Azure ACR：启用容器仓库的 Defender for Cloud
az security pricing create --name ContainerRegistry --tier standard

# GCR：启用容器分析（Container Analysis）
gcloud services enable containeranalysis.googleapis.com
gcloud artifacts docker images list-vulnerabilities \
  LOCATION-docker.pkg.dev/PROJECT/REPO/IMAGE@sha256:DIGEST
```

### 步骤 6：构建带安全门禁的 CI/CD 流水线

将扫描和签名作为强制门禁集成到 CI/CD 流水线中。

```yaml
# GitHub Actions：扫描、签名并推送镜像
name: Container Security Pipeline
on: push

jobs:
  build-scan-sign:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build image
        run: docker build -t myapp:${{ github.sha }} .

      - name: Trivy vulnerability scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: myapp:${{ github.sha }}
          format: json
          output: trivy-results.json
          severity: CRITICAL,HIGH
          exit-code: 1

      - name: Generate SBOM
        run: syft myapp:${{ github.sha }} -o spdx-json > sbom.json

      - name: Push to ECR
        run: |
          aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_REGISTRY
          docker tag myapp:${{ github.sha }} $ECR_REGISTRY/myapp:${{ github.sha }}
          docker push $ECR_REGISTRY/myapp:${{ github.sha }}

      - name: Sign image with Cosign
        run: |
          cosign sign --key env://COSIGN_PRIVATE_KEY \
            $ECR_REGISTRY/myapp:${{ github.sha }}

      - name: Attach SBOM
        run: |
          cosign attach sbom --sbom sbom.json \
            $ECR_REGISTRY/myapp:${{ github.sha }}
```

## 核心概念

| 术语 | 定义 |
|------|------|
| 容器镜像扫描（Container Image Scanning） | 对容器镜像各层进行自动化分析，识别操作系统包和应用程序依赖中的已知漏洞 |
| 镜像签名（Image Signing） | 使用 Cosign 或 Notation 对容器镜像真实性和完整性进行加密证明的验证机制 |
| 软件物料清单（SBOM） | 容器镜像中软件组件、库和依赖项的完整清单 |
| 标签不可变性（Tag Immutability） | 防止覆盖现有镜像标签的仓库设置，确保标签始终指向同一个镜像摘要 |
| Sigstore | 为软件供应链安全提供无密钥签名、透明度日志和验证工具的开源项目 |
| 镜像证明（Image Attestation） | 附加到镜像的经加密签名的元数据（扫描结果、SBOM、构建来源），可在部署前进行验证 |

## 工具与系统

- **Trivy**：面向容器镜像、文件系统、Git 仓库和 Kubernetes 资源的综合漏洞扫描工具
- **Grype**：Anchore 出品的漏洞扫描工具，对容器镜像和 SBOM 具有广泛的漏洞数据库覆盖
- **Cosign**：Sigstore 工具集，支持基于密钥和无密钥工作流的镜像签名、验证和证明
- **Syft**：SBOM 生成工具，支持针对容器镜像和文件系统的 SPDX 和 CycloneDX 格式
- **AWS ECR**：内置扫描、标签不可变性和生命周期策略的容器镜像仓库

## 常见场景

### 场景：实施安全的镜像晋级流水线

**场景背景**：开发团队在没有安全管控的情况下将镜像推送到开发仓库。安全团队需要实施一个晋级流水线，对镜像进行扫描、签名，并仅将经过审批的镜像晋级到生产仓库。

**方法**：
1. 为开发仓库配置 ECR 推送时自动扫描
2. 将 Trivy 扫描作为 CI/CD 门禁，阻止含严重（CRITICAL）漏洞的镜像
3. 使用 Syft 生成 SBOM 并与镜像扫描结果一起存储
4. 扫描通过后使用 Cosign 对已审批镜像进行签名
5. 配置生产仓库，要求所有推送的镜像必须包含签名
6. 在生产 Kubernetes 中配置 Kyverno 或 OPA Gatekeeper，在 Pod 创建前验证镜像签名
7. 在两个仓库中实施生命周期策略，清理未标记和旧镜像

**常见陷阱**：漏洞数据库持续更新。今天通过扫描的镜像，明天可能发现新的严重漏洞。应对已部署的镜像实施持续扫描，而不仅限于构建时扫描。镜像签名密钥必须安全存储在 KMS 或 Vault 中，不能存放在 CI/CD 环境变量里。

## 输出格式

```
容器仓库安全报告
=====================================
仓库: 123456789012.dkr.ecr.us-east-1.amazonaws.com
镜像库数量: 24
报告日期: 2026-02-23

镜像清单:
  总镜像数: 342
  已扫描: 298 (87%)
  已签名: 156 (46%)
  含 SBOM: 134 (39%)

漏洞摘要:
  严重漏洞:    23 个（分布在 8 个镜像中）
  高危漏洞:   145 个（分布在 34 个镜像中）
  中危漏洞:   456 个（分布在 67 个镜像中）
  无漏洞镜像:  89 个

需立即修复的严重镜像:
  myapp:1.2.3           - 5 个严重漏洞（openssl 中的 CVE-2026-xxxx）
  api-gateway:2.0.1     - 3 个严重漏洞（log4j 中的 CVE-2026-yyyy）
  worker:latest         - 4 个严重漏洞（glibc 中的 CVE-2026-zzzz）

仓库配置状态:
  推送时扫描已启用:     18 / 24 个仓库
  标签不可变性:         12 / 24 个仓库
  生命周期策略:         20 / 24 个仓库
  强制镜像签名:          8 / 24 个仓库
```

