# Implementing Image Provenance Verification With Cosign

> 使用 Sigstore Cosign 进行容器镜像来源签名与验证，支持基于 OIDC 的无密钥签名、证明附件及 Kubernetes 准入强制执行。

- Skill: `killvxk/implementing-image-provenance-verification-with-cosign` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add killvxk/implementing-image-provenance-verification-with-cosign`
- Raw SKILL.md: https://api.skillmd.com/api/skills/killvxk/implementing-image-provenance-verification-with-cosign/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/implementing-image-provenance-verification-with-cosign

---


# 使用 Cosign 实施镜像来源验证

## 概述

Cosign 是 Sigstore 工具集中用于对容器镜像和 OCI 制品进行签名、验证和附加元数据的工具。它同时支持基于密钥和无密钥（OIDC）两种签名方式，集成了 Fulcio（证书颁发机构）和 Rekor（透明日志），为容器镜像提供供应链安全保障。

## 前提条件

- 已安装 Cosign CLI
- 用于构建镜像的 Docker 或 Podman
- 符合 OCI 规范的容器仓库（Docker Hub、GHCR、GCR、ECR）
- 用于无密钥签名的 OIDC 提供商账号（GitHub、Google、Microsoft）

## 安装 Cosign

```bash
# 通过 Go 安装
go install github.com/sigstore/cosign/v2/cmd/cosign@latest

# 通过 Homebrew 安装
brew install cosign

# 通过脚本安装
curl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64"
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
sudo chmod +x /usr/local/bin/cosign

# 验证安装
cosign version
```

## 基于密钥的签名

### 生成密钥对

```bash
# 生成 cosign 密钥对（创建 cosign.key 和 cosign.pub）
cosign generate-key-pair

# 生成存储在 KMS 中的密钥对
cosign generate-key-pair --kms awskms:///alias/cosign-key
cosign generate-key-pair --kms gcpkms://projects/PROJECT/locations/LOCATION/keyRings/KEYRING/cryptoKeys/KEY
cosign generate-key-pair --kms hashivault://transit/keys/cosign
```

### 使用密钥签名镜像

```bash
# 签名镜像
cosign sign --key cosign.key ghcr.io/myorg/myapp:v1.0.0

# 添加注解签名
cosign sign --key cosign.key \
  -a "build-id=12345" \
  -a "git-sha=$(git rev-parse HEAD)" \
  ghcr.io/myorg/myapp:v1.0.0
```

### 使用密钥验证镜像

```bash
# 验证签名
cosign verify --key cosign.pub ghcr.io/myorg/myapp:v1.0.0

# 带注解检查的验证
cosign verify --key cosign.pub \
  -a "build-id=12345" \
  ghcr.io/myorg/myapp:v1.0.0
```

## 无密钥签名（OIDC）

### 无密钥签名（交互式）

```bash
# 无密钥签名 - 打开浏览器进行 OIDC 认证
cosign sign ghcr.io/myorg/myapp:v1.0.0

# 签名、证书和 Rekor 条目将自动创建
```

### 无密钥签名（CI/CD - 非交互式）

```bash
# GitHub Actions（自动使用 OIDC 令牌）
cosign sign ghcr.io/myorg/myapp:v1.0.0 \
  --yes

# 使用显式身份令牌
cosign sign ghcr.io/myorg/myapp:v1.0.0 \
  --identity-token=$(cat /var/run/sigstore/cosign/oidc-token) \
  --yes
```

### 验证无密钥签名

```bash
# 通过邮件身份验证
cosign verify ghcr.io/myorg/myapp:v1.0.0 \
  --certificate-identity=builder@example.com \
  --certificate-oidc-issuer=https://accounts.google.com

# 通过 GitHub Actions 工作流验证
cosign verify ghcr.io/myorg/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

# 使用正则匹配验证
cosign verify ghcr.io/myorg/myapp:v1.0.0 \
  --certificate-identity-regexp=".*@example.com" \
  --certificate-oidc-issuer=https://accounts.google.com
```

## 证明（SLSA 来源）

### 附加 SBOM 证明

```bash
# 生成 SBOM
syft ghcr.io/myorg/myapp:v1.0.0 -o cyclonedx-json > sbom.cdx.json

# 将 SBOM 作为证明附加
cosign attest --key cosign.key \
  --type cyclonedx \
  --predicate sbom.cdx.json \
  ghcr.io/myorg/myapp:v1.0.0

# 验证证明
cosign verify-attestation --key cosign.pub \
  --type cyclonedx \
  ghcr.io/myorg/myapp:v1.0.0
```

### 附加漏洞扫描证明

```bash
# 运行扫描并保存结果
grype ghcr.io/myorg/myapp:v1.0.0 -o json > vuln-scan.json

# 将扫描结果作为证明附加
cosign attest --key cosign.key \
  --type vuln \
  --predicate vuln-scan.json \
  ghcr.io/myorg/myapp:v1.0.0
```

### SLSA 来源证明

```bash
# 附加 SLSA 来源
cosign attest --key cosign.key \
  --type slsaprovenance \
  --predicate provenance.json \
  ghcr.io/myorg/myapp:v1.0.0

# 验证 SLSA 来源
cosign verify-attestation --key cosign.pub \
  --type slsaprovenance \
  ghcr.io/myorg/myapp:v1.0.0
```

## CI/CD 集成

### GitHub Actions

```yaml
name: Sign and Publish
on:
  push:
    tags: ['v*']

permissions:
  contents: read
  packages: write
  id-token: write  # 无密钥签名所需

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

      - uses: sigstore/cosign-installer@v3

      - name: 登录到 GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: 构建并推送
        id: build
        uses: docker/build-push-action@v5
        with:
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}

      - name: 签名镜像（无密钥）
        run: |
          cosign sign --yes \
            ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}

      - name: 生成并附加 SBOM
        run: |
          syft ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }} -o cyclonedx-json > sbom.json
          cosign attest --yes \
            --type cyclonedx \
            --predicate sbom.json \
            ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}
```

## Kubernetes 准入强制执行

### Policy Controller（Sigstore）

```bash
# 安装 policy-controller
helm repo add sigstore https://sigstore.github.io/helm-charts
helm install policy-controller sigstore/policy-controller \
  --namespace cosign-system --create-namespace
```

```yaml
# 在命名空间强制要求签名镜像
apiVersion: policy.sigstore.dev/v1beta1
kind: ClusterImagePolicy
metadata:
  name: require-signed-images
spec:
  images:
    - glob: "ghcr.io/myorg/**"
  authorities:
    - keyless:
        url: https://fulcio.sigstore.dev
        identities:
          - issuer: https://token.actions.githubusercontent.com
            subjectRegExp: "https://github.com/myorg/.*"
      ctlog:
        url: https://rekor.sigstore.dev
```

### Kyverno 集成

```yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signature
spec:
  validationFailureAction: Enforce
  rules:
    - name: verify-cosign-signature
      match:
        any:
          - resources:
              kinds: ["Pod"]
      verifyImages:
        - imageReferences:
            - "ghcr.io/myorg/*"
          attestors:
            - entries:
                - keyless:
                    subject: "https://github.com/myorg/*"
                    issuer: "https://token.actions.githubusercontent.com"
                    rekor:
                      url: https://rekor.sigstore.dev
```

## 透明日志（Rekor）

```bash
# 在 Rekor 中搜索镜像签名
rekor-cli search --email builder@example.com

# 获取特定条目
rekor-cli get --uuid <entry-uuid>

# 验证条目包含情况
cosign verify ghcr.io/myorg/myapp:v1.0.0 \
  --certificate-identity=builder@example.com \
  --certificate-oidc-issuer=https://accounts.google.com
```

## 最佳实践

1. 在 CI/CD 自动化流水线中**使用无密钥签名**
2. **按摘要签名**而非按标签签名，以确保引用的不可变性
3. 在签名旁边**附加 SBOM 证明**
4. 使用 policy-controller 或 Kyverno 在**准入阶段强制签名验证**
5. 使用 **OIDC 身份**验证代替单纯的密钥验证
6. 对于基于密钥的签名，将密钥**存储在 KMS 中**（AWS KMS、GCP KMS、HashiCorp Vault）
7. **验证完整信任链**：签名 + 证书 + Rekor 包含情况
8. 在签名上以注解形式**包含构建元数据**

