Files
git.stella-ops.org/docs/guides/keyless-signing-quickstart.md
StellaOps Bot 907783f625 Add property-based tests for SBOM/VEX document ordering and Unicode normalization determinism
- Implement `SbomVexOrderingDeterminismProperties` for testing component list and vulnerability metadata hash consistency.
- Create `UnicodeNormalizationDeterminismProperties` to validate NFC normalization and Unicode string handling.
- Add project file for `StellaOps.Testing.Determinism.Properties` with necessary dependencies.
- Introduce CI/CD template validation tests including YAML syntax checks and documentation content verification.
- Create validation script for CI/CD templates ensuring all required files and structures are present.
2025-12-26 15:17:58 +02:00

6.0 KiB

Keyless Signing Quick Start

Get keyless signing working in your CI/CD pipeline in under 5 minutes.

Overview

Keyless signing uses your CI platform's OIDC identity to sign artifacts without managing private keys. The signature is bound to your repository, branch, and workflow identity.

┌─────────────┐     ┌─────────┐     ┌───────────────┐
│ CI Platform │────▶│ Fulcio  │────▶│ Signed Artifact│
│ OIDC Token  │     │ Sigstore│     │ + Rekor Entry │
└─────────────┘     └─────────┘     └───────────────┘

GitHub Actions (Fastest)

Step 1: Add the workflow

Create .github/workflows/sign.yml:

name: Build and Sign

on:
  push:
    branches: [main]

jobs:
  build-and-sign:
    runs-on: ubuntu-latest
    permissions:
      id-token: write    # Required for OIDC
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@v4

      - name: Build container
        run: |
          docker build -t ghcr.io/${{ github.repository }}:${{ github.sha }} .
          docker push ghcr.io/${{ github.repository }}:${{ github.sha }}

      - name: Install StellaOps CLI
        run: curl -sL https://get.stella-ops.org/cli | sh

      - name: Get OIDC Token
        id: oidc
        run: |
          TOKEN=$(curl -sLS "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=sigstore" \
            -H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \
            | jq -r '.value')
          echo "::add-mask::${TOKEN}"
          echo "token=${TOKEN}" >> $GITHUB_OUTPUT

      - name: Sign container
        env:
          STELLAOPS_OIDC_TOKEN: ${{ steps.oidc.outputs.token }}
        run: |
          DIGEST=$(docker inspect ghcr.io/${{ github.repository }}:${{ github.sha }} \
            --format='{{index .RepoDigests 0}}' | cut -d@ -f2)
          stella attest sign --keyless --artifact "$DIGEST"

Step 2: Push and verify

git add .github/workflows/sign.yml
git commit -m "Add keyless signing"
git push

Check Actions tab - your container is now signed!


GitLab CI (5 minutes)

Step 1: Update .gitlab-ci.yml

stages:
  - build
  - sign

build:
  stage: build
  image: docker:24
  services:
    - docker:dind
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - echo "ARTIFACT_DIGEST=$(docker inspect $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --format='{{index .RepoDigests 0}}' | cut -d@ -f2)" >> build.env
  artifacts:
    reports:
      dotenv: build.env

sign:
  stage: sign
  image: stella-ops/cli:latest
  id_tokens:
    STELLAOPS_OIDC_TOKEN:
      aud: sigstore
  needs:
    - build
  script:
    - stella attest sign --keyless --artifact "$ARTIFACT_DIGEST"
  only:
    - main

Step 2: Push

git add .gitlab-ci.yml
git commit -m "Add keyless signing"
git push

Verification Gate

Add verification before deployment:

GitHub Actions

deploy:
  needs: [build-and-sign]
  runs-on: ubuntu-latest
  environment: production
  steps:
    - name: Verify before deploy
      run: |
        stella attest verify \
          --artifact "${{ needs.build-and-sign.outputs.digest }}" \
          --certificate-identity "repo:${{ github.repository }}:ref:refs/heads/main" \
          --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
          --require-rekor

    - name: Deploy
      run: kubectl set image deployment/app app=$IMAGE

GitLab CI

deploy:
  stage: deploy
  environment: production
  needs:
    - sign
  script:
    - |
      stella attest verify \
        --artifact "$ARTIFACT_DIGEST" \
        --certificate-identity "project_path:$CI_PROJECT_PATH:ref_type:branch:ref:main" \
        --certificate-oidc-issuer "https://gitlab.com" \
        --require-rekor
    - kubectl set image deployment/app app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  only:
    - main

Identity Patterns Cheat Sheet

GitHub Actions

Pattern Example
Any branch repo:org/repo:.*
Main only repo:org/repo:ref:refs/heads/main
Tags only repo:org/repo:ref:refs/tags/v.*
Environment repo:org/repo:environment:production

OIDC Issuer: https://token.actions.githubusercontent.com

GitLab CI

Pattern Example
Any ref project_path:group/project:.*
Main only project_path:group/project:ref_type:branch:ref:main
Tags only project_path:group/project:ref_type:tag:.*
Protected project_path:group/project:ref_protected:true

OIDC Issuer: https://gitlab.com (or self-hosted URL)


Using Reusable Workflows

For cleaner pipelines, use StellaOps reusable workflows:

GitHub Actions

jobs:
  sign:
    uses: stella-ops/workflows/.github/workflows/stellaops-sign.yml@v1
    with:
      artifact-digest: sha256:abc123...
      artifact-type: image
    permissions:
      id-token: write

  verify:
    needs: [sign]
    uses: stella-ops/workflows/.github/workflows/stellaops-verify.yml@v1
    with:
      artifact-digest: sha256:abc123...
      certificate-identity: "repo:${{ github.repository }}:ref:refs/heads/main"
      certificate-oidc-issuer: "https://token.actions.githubusercontent.com"

GitLab CI

include:
  - project: 'stella-ops/templates'
    file: '.gitlab-ci-stellaops.yml'

sign-container:
  extends: .stellaops-sign
  variables:
    ARTIFACT_DIGEST: sha256:abc123...
    ARTIFACT_TYPE: image

What's Next?

Need Help?