> For the complete documentation index, see [llms.txt](https://atomoh.gitbook.io/kubernetes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://atomoh.gitbook.io/kubernetes/cn/an-quan-yu-ce-le/07-image-security.md).

# 镜像安全

> **支持的版本**: Trivy 0.56+, Kubernetes 1.31, 1.32, 1.33 **最后更新**: February 22, 2026

容器镜像安全是 Kubernetes 安全的第一道防线。本文档介绍镜像扫描、签名、验证以及供应链安全。

## 目录

1. [镜像扫描概述](#image-scanning-overview)
2. [Trivy](#trivy)
3. [Amazon ECR 镜像扫描](#amazon-ecr-image-scanning)
4. [使用 Cosign/Sigstore 进行镜像签名](#image-signing-with-cosignsigstore)
5. [Admission Control 中的镜像验证](#image-verification-in-admission-control)
6. [供应链安全](#supply-chain-security)
7. [基础镜像选择](#base-image-selection)
8. [Image Registry 最佳实践](#image-registry-best-practices)
9. [CI/CD Pipeline 集成](#cicd-pipeline-integration)

***

## 镜像扫描概述

### Shift-Left Security

镜像安全应从开发流程的早期开始。

```
┌─────────────────────────────────────────────────────────────────────────┐
│                    Shift-Left Image Security                             │
│                                                                         │
│  Development Phase           Build Phase              Runtime Phase     │
│  ┌─────────┐               ┌─────────┐               ┌─────────┐       │
│  │ IDE     │               │ CI/CD   │               │ K8s     │       │
│  │ Scanning│──────────────▶│ Scanning│──────────────▶│ Scanning│       │
│  │         │               │         │               │         │       │
│  │ • Local │               │ • Build │               │ • Runtime│      │
│  │   scan  │               │   gate  │               │   monitor│      │
│  │ • Deps  │               │ • Regis-│               │ • Policy │      │
│  │   check │               │   try   │               │   enforce│      │
│  └─────────┘               └─────────┘               └─────────┘       │
│                                                                         │
│  ◀─────────────────── Cost & Ease of Fix ──────────────────────▶       │
│     Low                                                   High          │
└─────────────────────────────────────────────────────────────────────────┘
```

### 扫描目标

| 目标                        | 描述                       | 工具                  |
| ------------------------- | ------------------------ | ------------------- |
| **OS Packages**           | 操作系统包漏洞                  | Trivy, Grype, Clair |
| **Language Dependencies** | npm、pip、go modules 等     | Trivy, Snyk         |
| **Misconfigurations**     | Dockerfile、K8s manifests | Trivy, Checkov      |
| **Secrets**               | 硬编码的敏感信息                 | Trivy, Trufflehog   |
| **Licenses**              | 开源许可证                    | Trivy, FOSSA        |

***

## Trivy

### Trivy 概述

Trivy 是一个面向 containers、filesystems、Git repositories 等的综合安全扫描器。

### Trivy 安装

```bash
# macOS
brew install trivy

# Linux (Debian/Ubuntu)
sudo apt-get install wget apt-transport-https gnupg
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy

# Docker
docker pull aquasec/trivy:latest
```

### 镜像扫描

```bash
# Basic image scan
trivy image nginx:latest

# Severity filtering
trivy image --severity HIGH,CRITICAL nginx:latest

# JSON output
trivy image --format json --output results.json nginx:latest

# SARIF format (GitHub Security integration)
trivy image --format sarif --output results.sarif nginx:latest

# Ignore unfixed vulnerabilities
trivy image --ignore-unfixed nginx:latest

# Include secret scanning
trivy image --scanners vuln,secret nginx:latest
```

### Filesystem 扫描

```bash
# Scan project directory
trivy fs --scanners vuln,secret,config .

# Scan Dockerfile
trivy config Dockerfile

# Scan Kubernetes manifests
trivy config ./k8s/

# Scan Helm charts
trivy config ./charts/my-app/
```

### Trivy 配置文件

```yaml
# trivy.yaml
severity:
  - HIGH
  - CRITICAL

scan:
  scanners:
    - vuln
    - secret
    - config

vulnerability:
  ignore-unfixed: true
  type:
    - os
    - library

secret:
  config: /path/to/secret-config.yaml

misconfiguration:
  helm:
    values:
      - values.yaml

ignore:
  - CVE-2023-12345  # Ignore specific CVE
  - secret-rule-id  # Ignore specific secret rule
```

### Trivy Operator（Kubernetes 集成）

```bash
# Install Trivy Operator
helm repo add aqua https://aquasecurity.github.io/helm-charts/
helm repo update

helm install trivy-operator aqua/trivy-operator \
    --namespace trivy-system \
    --create-namespace \
    --set trivy.ignoreUnfixed=true
```

```yaml
# Check VulnerabilityReport
apiVersion: aquasecurity.github.io/v1alpha1
kind: VulnerabilityReport
metadata:
  name: deployment-nginx-nginx
  namespace: default
spec:
  # Auto-generated by Trivy Operator
report:
  scanner:
    name: Trivy
    version: 0.56.0
  summary:
    criticalCount: 2
    highCount: 5
    mediumCount: 10
    lowCount: 15
  vulnerabilities:
    - vulnerabilityID: CVE-2024-12345
      severity: CRITICAL
      title: "Buffer overflow in libssl"
      installedVersion: "1.1.1"
      fixedVersion: "1.1.2"
```

***

## Amazon ECR 镜像扫描

### Basic Scanning 与 Enhanced Scanning

| 功能                    | Basic Scanning | Enhanced Scanning (Inspector) |
| --------------------- | -------------- | ----------------------------- |
| **Scan Engine**       | Clair          | Amazon Inspector              |
| **Scan Frequency**    | Push 时         | 持续扫描                          |
| **Vulnerability DB**  | CVE            | CVE + Amazon 威胁情报             |
| **Cost**              | 免费             | Inspector 定价                  |
| **Language Packages** | 有限             | 广泛支持                          |
| **AWS Integration**   | 基础             | Security Hub, EventBridge     |

### 启用 Enhanced Scanning

```bash
# Configure registry scanning
aws ecr put-registry-scanning-configuration \
    --scan-type ENHANCED \
    --rules '[
        {
            "repositoryFilters": [
                {"filter": "production/*", "filterType": "WILDCARD"}
            ],
            "scanFrequency": "CONTINUOUS_SCAN"
        },
        {
            "repositoryFilters": [
                {"filter": "development/*", "filterType": "WILDCARD"}
            ],
            "scanFrequency": "SCAN_ON_PUSH"
        }
    ]'
```

### 获取扫描结果

```bash
# Get scan results
aws ecr describe-image-scan-findings \
    --repository-name my-app \
    --image-id imageTag=latest \
    --query 'imageScanFindings.findings[?severity==`CRITICAL`]'

# Vulnerability summary
aws ecr describe-image-scan-findings \
    --repository-name my-app \
    --image-id imageTag=latest \
    --query 'imageScanFindings.findingSeverityCounts'
```

### 通过 EventBridge 发送通知

```yaml
# CloudFormation/SAM template
Resources:
  ECRScanRule:
    Type: AWS::Events::Rule
    Properties:
      Name: ecr-scan-findings
      EventPattern:
        source:
          - aws.ecr
        detail-type:
          - ECR Image Scan
        detail:
          scan-status:
            - COMPLETE
          finding-severity-counts:
            CRITICAL:
              - exists: true
      Targets:
        - Id: SNSTarget
          Arn: !Ref AlertTopic
          InputTransformer:
            InputPathsMap:
              repo: "$.detail.repository-name"
              tag: "$.detail.image-tags[0]"
              critical: "$.detail.finding-severity-counts.CRITICAL"
            InputTemplate: |
              "ECR Scan Alert: Found <critical> CRITICAL vulnerabilities in <repo>:<tag>"
```

***

## 使用 Cosign/Sigstore 进行镜像签名

### Cosign 概述

Cosign 是 Sigstore 项目的一部分，是用于签名和验证 container images 的工具。

```
┌─────────────────────────────────────────────────────────────────────────┐
│                    Cosign Image Signing Workflow                         │
│                                                                         │
│  ┌─────────────┐     ┌─────────────┐     ┌─────────────────────────┐  │
│  │   Build     │────▶│   Sign      │────▶│   Push to Registry      │  │
│  │   Image     │     │   (Cosign)  │     │   (Image + Signature)   │  │
│  └─────────────┘     └─────────────┘     └───────────┬─────────────┘  │
│                                                       │                │
│                                                       ▼                │
│  ┌─────────────────────────────────────────────────────────────────┐  │
│  │                      Container Registry                          │  │
│  │                                                                  │  │
│  │  ┌─────────────────┐    ┌─────────────────┐                    │  │
│  │  │   Image         │    │   Signature     │                    │  │
│  │  │   sha256:abc... │    │   sha256:xyz... │                    │  │
│  │  └─────────────────┘    └─────────────────┘                    │  │
│  └──────────────────────────────────────────────────────────────────┘  │
│                                          │                             │
│                                          ▼                             │
│  ┌─────────────────────────────────────────────────────────────────┐  │
│  │                    Kubernetes Cluster                            │  │
│  │                                                                  │  │
│  │  ┌─────────────┐     ┌─────────────┐     ┌─────────────┐       │  │
│  │  │  Admission  │────▶│   Verify    │────▶│   Deploy    │       │  │
│  │  │  Controller │     │  Signature  │     │    Pod      │       │  │
│  │  │  (Kyverno)  │     │             │     │             │       │  │
│  │  └─────────────┘     └─────────────┘     └─────────────┘       │  │
│  └─────────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────────┘
```

### Cosign 安装

```bash
# macOS
brew install cosign

# Linux
curl -LO 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

# Version check
cosign version
```

### 基于密钥的签名

```bash
# Generate key pair
cosign generate-key-pair

# Sign image
cosign sign --key cosign.key myregistry.io/myapp:v1.0.0

# Verify signature
cosign verify --key cosign.pub myregistry.io/myapp:v1.0.0
```

### Keyless Signing（基于 OIDC）

```bash
# Keyless signing in GitHub Actions
# GITHUB_TOKEN automatically provides OIDC token
cosign sign myregistry.io/myapp:v1.0.0

# Verify keyless signature
cosign verify \
    --certificate-identity=https://github.com/myorg/myrepo/.github/workflows/build.yaml@refs/heads/main \
    --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
    myregistry.io/myapp:v1.0.0
```

### GitHub Actions 集成

```yaml
name: Build, Sign and Push

on:
  push:
    branches: [main]

jobs:
  build-sign-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write  # Required for keyless signing

    steps:
      - uses: actions/checkout@v4

      - name: Install Cosign
        uses: sigstore/cosign-installer@v3

      - name: Login to Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and Push
        uses: docker/build-push-action@v5
        id: build
        with:
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}

      - name: Sign Image (Keyless)
        env:
          DIGEST: ${{ steps.build.outputs.digest }}
        run: |
          cosign sign --yes ghcr.io/${{ github.repository }}@${DIGEST}

      - name: Verify Signature
        run: |
          cosign verify \
            --certificate-identity-regexp="https://github.com/${{ github.repository }}/*" \
            --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
            ghcr.io/${{ github.repository }}:${{ github.sha }}
```

***

## Admission Control 中的镜像验证

### Kyverno imageVerify

```yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signature
spec:
  validationFailureAction: Enforce
  background: false
  rules:
    - name: verify-signature
      match:
        any:
          - resources:
              kinds:
                - Pod
      verifyImages:
        - imageReferences:
            - "ghcr.io/myorg/*"
          attestors:
            - count: 1
              entries:
                - keyless:
                    subject: "https://github.com/myorg/*/.github/workflows/*@refs/heads/main"
                    issuer: "https://token.actions.githubusercontent.com"
                    rekor:
                      url: https://rekor.sigstore.dev
---
# Key-based verification
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-key
spec:
  validationFailureAction: Enforce
  rules:
    - name: verify-key-signature
      match:
        any:
          - resources:
              kinds:
                - Pod
      verifyImages:
        - imageReferences:
            - "myregistry.io/*"
          attestors:
            - count: 1
              entries:
                - keys:
                    publicKeys: |
                      -----BEGIN PUBLIC KEY-----
                      MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
                      -----END PUBLIC KEY-----
```

### Connaisseur

```yaml
# Connaisseur installation
helm repo add connaisseur https://sse-secure-systems.github.io/connaisseur/charts
helm install connaisseur connaisseur/connaisseur \
    -n connaisseur \
    --create-namespace
```

```yaml
# Connaisseur configuration
# values.yaml
validators:
  - name: cosign
    type: cosign
    trustRoots:
      - name: production
        key: |
          -----BEGIN PUBLIC KEY-----
          MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
          -----END PUBLIC KEY-----

policy:
  - pattern: "ghcr.io/myorg/*"
    validator: cosign
    with:
      trustRoot: production
  - pattern: "*"
    validator: deny  # Deny other images
```

***

## 供应链安全

### SBOM (Software Bill of Materials) 生成

```bash
# Generate SBOM with Syft
syft myregistry.io/myapp:latest -o spdx-json > sbom.spdx.json
syft myregistry.io/myapp:latest -o cyclonedx-json > sbom.cyclonedx.json

# Generate SBOM with Trivy
trivy image --format spdx-json --output sbom.json myregistry.io/myapp:latest

# Attach SBOM to image (Cosign)
cosign attach sbom --sbom sbom.spdx.json myregistry.io/myapp:latest
```

### 基于 SBOM 的漏洞扫描

```bash
# Scan SBOM for vulnerabilities
trivy sbom sbom.spdx.json

# Scan SBOM with Grype
grype sbom:sbom.spdx.json
```

### SLSA (Supply chain Levels for Software Artifacts)

```yaml
# Generate SLSA Provenance in GitHub Actions
name: SLSA Build

on:
  push:
    branches: [main]

jobs:
  build:
    outputs:
      digest: ${{ steps.build.outputs.digest }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build and Push
        id: build
        uses: docker/build-push-action@v5
        with:
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}

  provenance:
    needs: build
    permissions:
      actions: read
      id-token: write
      packages: write
    uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.9.0
    with:
      image: ghcr.io/${{ github.repository }}
      digest: ${{ needs.build.outputs.digest }}
    secrets:
      registry-username: ${{ github.actor }}
      registry-password: ${{ secrets.GITHUB_TOKEN }}
```

***

## 基础镜像选择

### 镜像类型对比

| 镜像类型              | 大小        | 漏洞 | 调试  | 使用场景        |
| ----------------- | --------- | -- | --- | ----------- |
| **distroless**    | 非常小       | 极少 | 困难  | Production  |
| **Alpine**        | 小 (\~5MB) | 少  | 可行  | 轻量级 apps    |
| **Chainguard**    | 小         | 极少 | 有限  | 安全优先        |
| **Ubuntu/Debian** | 大         | 多  | 容易  | Dev/Legacy  |
| **Scratch**       | 最小        | 无  | 不可能 | 静态 binaries |

### 使用 Distroless Images

```dockerfile
# Multi-stage build with distroless
FROM golang:1.22 AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server

# Distroless runtime image
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /app/server /server
USER nonroot:nonroot
ENTRYPOINT ["/server"]
```

### 使用 Chainguard Images

```dockerfile
# Chainguard Python image
FROM cgr.dev/chainguard/python:latest
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
USER nonroot
CMD ["python", "app.py"]
```

### Alpine 安全加固

```dockerfile
FROM alpine:3.19

# Install minimal packages only
RUN apk add --no-cache \
    python3 \
    py3-pip \
    && rm -rf /var/cache/apk/*

# Create non-root user
RUN addgroup -g 1000 app && \
    adduser -u 1000 -G app -s /bin/sh -D app

WORKDIR /app
COPY --chown=app:app . .

USER app
CMD ["python3", "app.py"]
```

***

## Image Registry 最佳实践

### 使用私有 Registries

```yaml
# ImagePullSecrets configuration
apiVersion: v1
kind: Secret
metadata:
  name: registry-credentials
  namespace: production
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: <base64-encoded-docker-config>
---
# Set default ImagePullSecret on ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
  namespace: production
imagePullSecrets:
  - name: registry-credentials
```

### Image Pull Policies

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
spec:
  containers:
  - name: app
    image: myregistry.io/myapp@sha256:abc123...  # Use digest
    imagePullPolicy: Always  # Always verify latest
```

### Immutable Tag Policy (Kyverno)

```yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-image-digest
spec:
  validationFailureAction: Enforce
  rules:
    - name: require-digest
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "Images must use digest instead of tags"
        pattern:
          spec:
            containers:
              - image: "*@sha256:*"
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-latest-tag
spec:
  validationFailureAction: Enforce
  rules:
    - name: disallow-latest
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "Using 'latest' tag is not allowed"
        pattern:
          spec:
            containers:
              - image: "!*:latest"
```

***

## CI/CD Pipeline 集成

### 完整的镜像安全 Pipeline

```yaml
# .github/workflows/secure-build.yaml
name: Secure Image Build

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  # 1. Code scanning
  code-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Trivy vulnerability scanner (fs mode)
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          scan-ref: '.'
          severity: 'CRITICAL,HIGH'
          exit-code: '1'

  # 2. Build and scan
  build-scan:
    needs: code-scan
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      security-events: write
      id-token: write

    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Build image for scanning
        uses: docker/build-push-action@v5
        with:
          context: .
          load: true
          tags: ${{ env.IMAGE_NAME }}:scan

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: '${{ env.IMAGE_NAME }}:scan'
          format: 'sarif'
          output: 'trivy-results.sarif'
          severity: 'CRITICAL,HIGH'

      - name: Upload Trivy scan results
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: 'trivy-results.sarif'

      - name: Check for critical vulnerabilities
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: '${{ env.IMAGE_NAME }}:scan'
          exit-code: '1'
          severity: 'CRITICAL'

  # 3. Push and sign
  push-sign:
    needs: build-scan
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write

    outputs:
      digest: ${{ steps.push.outputs.digest }}

    steps:
      - uses: actions/checkout@v4

      - name: Install Cosign
        uses: sigstore/cosign-installer@v3

      - name: Login to Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push
        id: push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

      - name: Sign image with Cosign
        run: |
          cosign sign --yes ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.push.outputs.digest }}

      - name: Generate SBOM
        uses: anchore/sbom-action@v0
        with:
          image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.push.outputs.digest }}
          format: spdx-json
          output-file: sbom.spdx.json

      - name: Attach SBOM to image
        run: |
          cosign attach sbom --sbom sbom.spdx.json ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.push.outputs.digest }}

  # 4. Generate SLSA Provenance
  provenance:
    needs: push-sign
    permissions:
      actions: read
      id-token: write
      packages: write
    uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.9.0
    with:
      image: ghcr.io/${{ github.repository }}
      digest: ${{ needs.push-sign.outputs.digest }}
    secrets:
      registry-username: ${{ github.actor }}
      registry-password: ${{ secrets.GITHUB_TOKEN }}
```

***

## 总结

容器镜像安全的关键方面：

1. **扫描**: 使用 Trivy、ECR enhanced scanning 检测漏洞
2. **签名**: 使用 Cosign/Sigstore 确保镜像完整性
3. **验证**: 使用 Kyverno 只允许已签名镜像
4. **供应链**: 使用 SBOM、SLSA 实现透明度
5. **基础镜像**: 使用 distroless、Chainguard
6. **CI/CD 集成**: 构建自动化安全 pipelines

### 建议

* 对所有镜像应用漏洞扫描
* 始终签名生产镜像
* 使用 digests 而不是 `latest` tag
* 使用 distroless 或最小化基础镜像
* 自动化 SBOM 生成和管理

***

## 参考资料

* [Trivy 官方文档](https://aquasecurity.github.io/trivy/)
* [Cosign/Sigstore 文档](https://docs.sigstore.dev/)
* [Kyverno 镜像验证](https://kyverno.io/docs/writing-policies/verify-images/)
* [SLSA Framework](https://slsa.dev/)
* [Chainguard Images](https://www.chainguard.dev/chainguard-images)
