Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Sign and verify container image provenance using Sigstore Cosign with keyless OIDC-based signing, attestations, and Kubernetes admission enforcement.
.claude/skills/implementing-image-provenance-verification-with-cosign/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | — | — |
| case-14 | ✗→✓ | ▲ Improved | — | — |
| case-11 | ✗→✓ | ▲ Improved | — | — |
| case-06 | ✗→✓ | ▲ Improved | — | — |
| case-03 | ✓→✓ | = Same ✓ | — | — |
Cosign is a Sigstore tool for signing, verifying, and attaching metadata to container images and OCI artifacts. It supports both key-based and keyless (OIDC) signing, integrates with Fulcio (certificate authority) and Rekor (transparency log), and enables supply chain security for container images.
bash# Install via Go go install github.com/sigstore/cosign/v2/cmd/cosign@latest # Install via Homebrew brew install cosign # Install via script 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 # Verify installation cosign version
bash# Generate cosign key pair (creates cosign.key and cosign.pub) cosign generate-key-pair # Generate key pair stored in 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# Sign an image cosign sign --key cosign.key ghcr.io/myorg/myapp:v1.0.0 # Sign with annotations cosign sign --key cosign.key \ -a "build-id=12345" \ -a "git-sha=$(git rev-parse HEAD)" \ ghcr.io/myorg/myapp:v1.0.0
bash# Verify signature cosign verify --key cosign.pub ghcr.io/myorg/myapp:v1.0.0 # Verify with annotation check cosign verify --key cosign.pub \ -a "build-id=12345" \ ghcr.io/myorg/myapp:v1.0.0
bash# Keyless sign - opens browser for OIDC auth cosign sign ghcr.io/myorg/myapp:v1.0.0 # The signature, certificate, and Rekor entry are created automatically
bash# GitHub Actions (uses OIDC token automatically) cosign sign ghcr.io/myorg/myapp:v1.0.0 \ --yes # With explicit identity token cosign sign ghcr.io/myorg/myapp:v1.0.0 \ --identity-token=$(cat /var/run/sigstore/cosign/oidc-token) \ --yes
bash# Verify by email identity cosign verify ghcr.io/myorg/myapp:v1.0.0 \ --certificate-identity=builder@example.com \ --certificate-oidc-issuer=https://accounts.google.com # Verify by GitHub Actions workflow 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 # Verify with regex matching cosign verify ghcr.io/myorg/myapp:v1.0.0 \ --certificate-identity-regexp=".*@example.com" \ --certificate-oidc-issuer=https://accounts.google.com
bash# Generate SBOM syft ghcr.io/myorg/myapp:v1.0.0 -o cyclonedx-json > sbom.cdx.json # Attach SBOM as attestation cosign attest --key cosign.key \ --type cyclonedx \ --predicate sbom.cdx.json \ ghcr.io/myorg/myapp:v1.0.0 # Verify attestation cosign verify-attestation --key cosign.pub \ --type cyclonedx \ ghcr.io/myorg/myapp:v1.0.0
bash# Run scan and save results grype ghcr.io/myorg/myapp:v1.0.0 -o json > vuln-scan.json # Attach scan results as attestation cosign attest --key cosign.key \ --type vuln \ --predicate vuln-scan.json \ ghcr.io/myorg/myapp:v1.0.0
bash# Attach SLSA provenance cosign attest --key cosign.key \ --type slsaprovenance \ --predicate provenance.json \ ghcr.io/myorg/myapp:v1.0.0 # Verify SLSA provenance cosign verify-attestation --key cosign.pub \ --type slsaprovenance \ ghcr.io/myorg/myapp:v1.0.0
yamlname: Sign and Publish on: push: tags: ['v*'] permissions: contents: read packages: write id-token: write # Required for keyless signing jobs: build-sign: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: sigstore/cosign-installer@v3 - name: Login to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push id: build uses: docker/build-push-action@v5 with: push: true tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }} - name: Sign image (keyless) run: | cosign sign --yes \ ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }} - name: Generate and attach 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 }}
bash# Install 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# Enforce signed images in namespace 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
yamlapiVersion: 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
bash# Search Rekor for image signatures rekor-cli search --email builder@example.com # Get specific entry rekor-cli get --uuid <entry-uuid> # Verify entry inclusion cosign verify ghcr.io/myorg/myapp:v1.0.0 \ --certificate-identity=builder@example.com \ --certificate-oidc-issuer=https://accounts.google.com
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +18 percentage points is the difference between those two pass rates over the 21 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.