تخطَّ إلى المحتوى

Sigstore

Sigstore is a free, open-source suite of tools for software supply chain security. It provides cryptographic signing and verification for containers, artifacts, and Git commits — with a public transparency log (Rekor) that makes all signatures auditable and tamper-evident.

Installation

Install cosign

# macOS
brew install cosign

# Linux — binary
LATEST=$(curl -s https://api.github.com/repos/sigstore/cosign/releases/latest | jq -r .tag_name)
curl -L "https://github.com/sigstore/cosign/releases/download/${LATEST}/cosign-linux-amd64" \
  -o cosign
chmod +x cosign
sudo mv cosign /usr/local/bin/

# Linux — package (Debian/Ubuntu)
curl -sLO https://github.com/sigstore/cosign/releases/latest/download/cosign_amd64.deb
dpkg -i cosign_amd64.deb

# Verify
cosign version

Install gitsign

# macOS
brew install gitsign

# Linux
LATEST=$(curl -s https://api.github.com/repos/sigstore/gitsign/releases/latest | jq -r .tag_name)
curl -L "https://github.com/sigstore/gitsign/releases/download/${LATEST}/gitsign_linux_amd64" \
  -o gitsign
chmod +x gitsign
sudo mv gitsign /usr/local/bin/

# Configure Git to use gitsign
git config --global commit.gpgsign true
git config --global gpg.x509.program gitsign
git config --global gpg.format x509

Install rekor-cli

# macOS
brew install rekor-cli

# Linux
LATEST=$(curl -s https://api.github.com/repos/sigstore/rekor/releases/latest | jq -r .tag_name)
curl -L "https://github.com/sigstore/rekor/releases/download/${LATEST}/rekor-cli-linux-amd64" \
  -o rekor-cli
chmod +x rekor-cli
sudo mv rekor-cli /usr/local/bin/

rekor-cli version

Install policy-controller (Kubernetes)

helm repo add sigstore https://sigstore.github.io/helm-charts
helm repo update

helm install policy-controller sigstore/policy-controller \
  --namespace cosign-system \
  --create-namespace \
  --set commonNodeSelector."kubernetes\.io/os"=linux

# Verify
kubectl get pods -n cosign-system
kubectl get crds | grep policy.sigstore.dev

Configuration

Keyless Signing Setup (OIDC)

# Keyless signing uses your OIDC identity (GitHub Actions, Google, etc.)
# No key management required — Fulcio issues ephemeral certificates

# Set environment variables for keyless mode
export COSIGN_EXPERIMENTAL=1   # Deprecated in newer versions — keyless is default now

# In GitHub Actions, set OIDC token permissions:
# permissions:
#   id-token: write
#   contents: read

Key-Based Signing Setup

# Generate a signing key pair
cosign generate-key-pair

# Output: cosign.key (private), cosign.pub (public)
# Protect cosign.key — store in KMS or Vault, not in source control

# Generate with KMS backend (AWS KMS)
cosign generate-key-pair --kms awskms:///arn:aws:kms:us-east-1:123456789:key/abc123

# Generate with KMS backend (GCP KMS)
cosign generate-key-pair --kms gcpkms://projects/my-project/locations/us/keyRings/my-ring/cryptoKeys/my-key

Core Commands

CommandDescription
cosign sign <image>Sign a container image (keyless)
cosign sign --key cosign.key <image>Sign with a private key
cosign verify <image>Verify image signature (keyless)
cosign verify --key cosign.pub <image>Verify with a public key
cosign attach sbom --sbom sbom.json <image>Attach SBOM to image
cosign download sbom <image>Download attached SBOM
cosign attest --predicate sbom.json <image>Attach attestation
cosign verify-attestation <image>Verify attestation
cosign triangulate <image>Show OCI tag for signature/attestation
cosign copy <src> <dst>Copy image with all signatures
cosign tree <image>Show all supply chain metadata
rekor-cli upload --artifact <file>Upload artifact to Rekor log
rekor-cli search --sha <hash>Search Rekor by artifact hash
rekor-cli get --uuid <uuid>Retrieve a Rekor log entry
gitsign verify --certificate-identity <email>Verify a Git commit
gitsign logShow signed commit log
cosign generate-key-pairGenerate signing key pair
cosign public-key --key cosign.keyExtract public key
cosign import-key-pair --key private.pemImport existing key

Advanced Usage

Keyless Container Signing (GitHub Actions)

# .github/workflows/sign.yml
name: Build and Sign
on:
  push:
    branches: [main]

permissions:
  id-token: write      # Required for keyless signing
  contents: read
  packages: write

jobs:
  build-and-sign:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: sigstore/cosign-installer@v3

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

      - name: Sign image (keyless)
        env:
          DIGEST: ${{ steps.build.outputs.digest }}
        run: |
          cosign sign --yes \
            ghcr.io/my-org/my-app@${DIGEST}

      - name: Verify signature
        run: |
          cosign verify \
            --certificate-identity-regexp "https://github.com/my-org/my-app/.github/workflows/sign.yml.*" \
            --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
            ghcr.io/my-org/my-app@${{ steps.build.outputs.digest }}

SBOM Attestation

# Generate SBOM with syft
syft ghcr.io/my-org/my-app:latest -o cyclonedx-json > sbom.json

# Attach SBOM as an attestation
cosign attest \
  --predicate sbom.json \
  --type cyclonedx \
  ghcr.io/my-org/my-app:latest

# Verify and download SBOM attestation
cosign verify-attestation \
  --certificate-identity-regexp ".*" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  --type cyclonedx \
  ghcr.io/my-org/my-app:latest | jq '.payload | @base64d | fromjson'

Custom Provenance Attestation

# Create a SLSA provenance predicate
cat > provenance.json <<EOF
{
  "buildType": "https://github.com/actions/runner/github-hosted",
  "builder": {
    "id": "https://github.com/actions/runner"
  },
  "invocation": {
    "configSource": {
      "uri": "git+https://github.com/my-org/my-app@refs/heads/main",
      "digest": {"sha1": "$GITHUB_SHA"},
      "entryPoint": ".github/workflows/build.yml"
    }
  }
}
EOF

# Attach
cosign attest \
  --predicate provenance.json \
  --type slsaprovenance \
  ghcr.io/my-org/my-app:latest

Policy Controller — ClusterImagePolicy

# Require all images in production to be signed by our CI pipeline
apiVersion: policy.sigstore.dev/v1beta1
kind: ClusterImagePolicy
metadata:
  name: require-signed-images
spec:
  images:
    - glob: "ghcr.io/my-org/**"
  authorities:
    - keyless:
        url: https://fulcio.sigstore.dev
        identities:
          - issuer: https://token.actions.githubusercontent.com
            subjectRegExp: "https://github.com/my-org/.*/\\.github/workflows/.*@refs/heads/main"
      ctlog:
        url: https://rekor.sigstore.dev

Key-Based ClusterImagePolicy

apiVersion: policy.sigstore.dev/v1beta1
kind: ClusterImagePolicy
metadata:
  name: require-key-signed
spec:
  images:
    - glob: "docker.io/myrepo/*"
  authorities:
    - key:
        data: |
          -----BEGIN PUBLIC KEY-----
          MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
          -----END PUBLIC KEY-----

Namespace Opt-In for Policy Enforcement

# Label namespaces to enforce policy-controller admission
kubectl label namespace production \
  policy.sigstore.dev/include=true

# Verify the label is applied
kubectl get namespace production --show-labels

Rekor — Transparency Log Queries

# Search for all entries for a given artifact hash
sha256=$(shasum -a 256 myartifact.tar.gz | awk '{print $1}')
rekor-cli search --sha "sha256:${sha256}"

# Get a specific entry by UUID
rekor-cli get --uuid <uuid> --format json | jq .

# Verify an artifact is in the log
rekor-cli verify --artifact myartifact.tar.gz --signature myartifact.sig --public-key cosign.pub

# Search for entries by email identity (keyless)
rekor-cli search --email ci-bot@myorg.com

gitsign Commit Verification

# Sign commits (automatically, after git config above)
git commit -S -m "feat: add feature"

# Verify a commit's signature
git verify-commit HEAD

# Use gitsign's verbose verify
gitsign verify \
  --certificate-identity ci@myorg.com \
  --certificate-oidc-issuer https://accounts.google.com \
  HEAD

# Show signed commit log
gitsign log --signer-identity

# Check verification in git log
git log --show-signature

Common Workflows

Verify an Image Before Deployment

# Verify image is signed by the expected CI pipeline before deploying
cosign verify \
  --certificate-identity-regexp "https://github.com/my-org/my-app/.*" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  ghcr.io/my-org/my-app:v1.2.3

# If verification passes: exit code 0
# If verification fails: non-zero exit, safe to block the deploy

Inspect Image Supply Chain Metadata

# Show all supply chain artifacts (signatures, SBOMs, attestations)
cosign tree ghcr.io/my-org/my-app:latest

# Download and inspect the SBOM
cosign download sbom ghcr.io/my-org/my-app:latest | jq .

# Verify and print attestation payload
cosign verify-attestation \
  --certificate-identity-regexp ".*" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  --type slsaprovenance \
  ghcr.io/my-org/my-app:latest | jq -r '.payload | @base64d | fromjson'

Integrate Verification in Kubernetes Admission

# 1. Install policy-controller (see Installation section)

# 2. Create ClusterImagePolicy (see Advanced Usage section)

# 3. Label namespaces to enforce
kubectl label namespace production policy.sigstore.dev/include=true

# 4. Test: try to deploy an unsigned image
kubectl run test --image=nginx:latest -n production
# Expected: admission webhook denies the request

# 5. Monitor violations
kubectl get events -n production --field-selector reason=FailedCreate
kubectl logs -n cosign-system deploy/policy-controller-webhook

Tips and Best Practices

  • Sign images by digest, not tag — tags are mutable; always sign and verify using the immutable @sha256:... digest.
  • Use keyless signing in CI — OIDC-based keyless signing eliminates key management entirely; the CI system identity (GitHub Actions, Google SA) is the authority.
  • Store key-based signing keys in KMS — if you must use keys, use awskms://, gcpkms://, or azurekms:// URIs; never commit cosign.key to Git.
  • Attest SBOMs alongside signatures — a signature proves who built the image; an SBOM attestation proves what’s in it — both are needed for supply chain security.
  • Enable policy-controller in warn mode first — set --policy-controller-warn-mode=true to log violations without blocking, then flip to enforce.
  • Use --certificate-identity-regexp carefully — overly broad patterns allow any CI pipeline to be an authority; lock down to your org’s exact workflow paths.
  • Monitor the Rekor log for your org — use rekor-cli search --email or watch for unexpected entries to detect unauthorized signing.
  • Pin cosign-installer Action version — use a commit SHA instead of a tag to prevent supply chain attacks on the tool itself.
  • Include cosign verify in your CD pipeline — verify images at deploy time, not just at build time, to catch images pushed outside the CI pipeline.
  • Use cosign tree regularly — it gives an immediate view of all supply chain metadata for an image, making it easy to spot missing SBOMs or attestations.