# 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`: ```yaml 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 ```bash 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` ```yaml 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 ```bash git add .gitlab-ci.yml git commit -m "Add keyless signing" git push ``` --- ## Verification Gate Add verification before deployment: ### GitHub Actions ```yaml 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 ```yaml 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 ```yaml 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 ```yaml 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? - [Identity Constraints Guide](./identity-constraints.md) - Secure verification patterns - [Troubleshooting Guide](./keyless-signing-troubleshooting.md) - Common issues and fixes - [Offline Verification](../airgap/offline-verification.md) - Air-gapped environments ## Need Help? - Documentation: https://docs.stella-ops.org/ - Issues: https://github.com/stella-ops/stellaops/issues - Slack: https://stellaops.slack.com/