Files
git.stella-ops.org/docs/guides/identity-constraints.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

11 KiB

Identity Constraints for Keyless Verification

Overview

Keyless signing binds cryptographic signatures to OIDC identities. When verifying signatures, you must specify which identities are trusted. This document covers identity constraint patterns for all supported CI/CD platforms.

Core Concepts

Certificate Identity

The certificate identity is the subject claim from the OIDC token, embedded in the Fulcio certificate. It identifies:

  • Who created the signature (repository, branch, workflow)
  • When the signature was created (within the certificate validity window)
  • Where the signing happened (CI platform, environment)

OIDC Issuer

The OIDC issuer is the URL of the identity provider that issued the token. Each CI platform has its own issuer:

Platform Issuer URL
GitHub Actions https://token.actions.githubusercontent.com
GitLab CI (SaaS) https://gitlab.com
GitLab CI (Self-hosted) https://your-gitlab-instance.com
Gitea https://your-gitea-instance.com

Verification Flow

┌─────────────────────────────────────────────────────────────────────────┐
│                        Verification Process                              │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  1. Extract certificate from attestation                                 │
│     └─▶ Contains: subject, issuer, SAN, validity period                 │
│                                                                          │
│  2. Validate certificate chain                                           │
│     └─▶ Chains to trusted Fulcio root                                   │
│                                                                          │
│  3. Check OIDC issuer                                                    │
│     └─▶ Must match --certificate-oidc-issuer                            │
│                                                                          │
│  4. Check certificate identity                                           │
│     └─▶ Subject must match --certificate-identity pattern               │
│                                                                          │
│  5. Verify Rekor inclusion (if required)                                 │
│     └─▶ Signature logged during certificate validity                    │
│                                                                          │
│  6. Verify signature                                                     │
│     └─▶ Signature valid for artifact digest                             │
│                                                                          │
└─────────────────────────────────────────────────────────────────────────┘

Platform-Specific Patterns

GitHub Actions

GitHub Actions OIDC tokens include rich context about the workflow execution.

Token Claims

Claim Description Example
sub Subject (identity) repo:org/repo:ref:refs/heads/main
repository Full repository name org/repo
repository_owner Organization/user org
ref Git ref refs/heads/main
ref_type Ref type branch or tag
job_workflow_ref Workflow file .github/workflows/release.yml@refs/heads/main
environment Deployment environment production

Identity Patterns

Constraint Pattern Example
Any ref repo:<owner>/<repo>:.* repo:stellaops/scanner:.*
Main branch repo:<owner>/<repo>:ref:refs/heads/main repo:stellaops/scanner:ref:refs/heads/main
Any branch repo:<owner>/<repo>:ref:refs/heads/.* repo:stellaops/scanner:ref:refs/heads/.*
Version tags repo:<owner>/<repo>:ref:refs/tags/v.* repo:stellaops/scanner:ref:refs/tags/v.*
Environment repo:<owner>/<repo>:environment:<env> repo:stellaops/scanner:environment:production
Workflow (use SAN) N/A

Examples

# Accept only main branch
stella attest verify \
  --artifact sha256:abc123... \
  --certificate-identity "repo:stellaops/scanner:ref:refs/heads/main" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com"

# Accept main or release branches
stella attest verify \
  --artifact sha256:abc123... \
  --certificate-identity "repo:stellaops/scanner:ref:refs/heads/(main|release/.*)" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com"

# Accept any version tag
stella attest verify \
  --artifact sha256:abc123... \
  --certificate-identity "repo:stellaops/scanner:ref:refs/tags/v[0-9]+\.[0-9]+\.[0-9]+.*" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com"

# Accept production environment only
stella attest verify \
  --artifact sha256:abc123... \
  --certificate-identity "repo:stellaops/scanner:environment:production" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com"

GitLab CI

GitLab CI provides OIDC tokens with project and pipeline context.

Token Claims

Claim Description Example
sub Subject project_path:group/project:ref_type:branch:ref:main
project_path Full project path stellaops/scanner
namespace_path Namespace stellaops
ref Git ref main
ref_type Ref type branch or tag
ref_protected Protected ref true or false
environment Environment name production
pipeline_source Trigger source push, web, schedule

Identity Patterns

Constraint Pattern Example
Any ref project_path:<group>/<project>:.* project_path:stellaops/scanner:.*
Main branch project_path:<group>/<project>:ref_type:branch:ref:main Full pattern
Protected refs project_path:<group>/<project>:ref_protected:true Full pattern
Tags project_path:<group>/<project>:ref_type:tag:ref:.* Full pattern

Examples

# Accept main branch only
stella attest verify \
  --artifact sha256:abc123... \
  --certificate-identity "project_path:stellaops/scanner:ref_type:branch:ref:main" \
  --certificate-oidc-issuer "https://gitlab.com"

# Accept any protected ref
stella attest verify \
  --artifact sha256:abc123... \
  --certificate-identity "project_path:stellaops/scanner:ref_protected:true.*" \
  --certificate-oidc-issuer "https://gitlab.com"

# Self-hosted GitLab
stella attest verify \
  --artifact sha256:abc123... \
  --certificate-identity "project_path:mygroup/myproject:.*" \
  --certificate-oidc-issuer "https://gitlab.internal.example.com"

Gitea

Gitea OIDC tokens follow a similar pattern to GitHub Actions.

Token Claims

Claim Description Example
sub Subject org/repo:ref:refs/heads/main
repository Repository path org/repo
ref Git ref refs/heads/main

Identity Patterns

Constraint Pattern Example
Any ref <org>/<repo>:.* stellaops/scanner:.*
Main branch <org>/<repo>:ref:refs/heads/main stellaops/scanner:ref:refs/heads/main
Tags <org>/<repo>:ref:refs/tags/.* stellaops/scanner:ref:refs/tags/.*

Examples

# Accept main branch
stella attest verify \
  --artifact sha256:abc123... \
  --certificate-identity "stella-ops.org/git.stella-ops.org:ref:refs/heads/main" \
  --certificate-oidc-issuer "https://git.stella-ops.org"

Best Practices

Security Recommendations

  1. Always Constrain to Repository

    Never accept wildcards that could match any repository:

    # BAD - accepts any repository
    --certificate-identity "repo:.*"
    
    # GOOD - specific repository
    --certificate-identity "repo:stellaops/scanner:.*"
    
  2. Prefer Branch/Tag Constraints for Production

    # Better - only main branch
    --certificate-identity "repo:stellaops/scanner:ref:refs/heads/main"
    
    # Even better - only signed tags
    --certificate-identity "repo:stellaops/scanner:ref:refs/tags/v.*"
    
  3. Use Environment Constraints When Available

    # Most specific - production environment only
    --certificate-identity "repo:stellaops/scanner:environment:production"
    
  4. Always Require Rekor Proofs

    # Always include --require-rekor for production
    stella attest verify \
      --artifact sha256:... \
      --certificate-identity "..." \
      --certificate-oidc-issuer "..." \
      --require-rekor
    
  5. Pin Trusted Issuers

    Only trust expected OIDC issuers. Never accept .* for issuer.

Common Patterns

Multi-Environment Trust

# GitHub Actions - Different constraints per environment
staging:
  identity: "repo:myorg/myrepo:ref:refs/heads/.*"

production:
  identity: "repo:myorg/myrepo:ref:refs/(heads/main|tags/v.*)"

Cross-Repository Trust

# Trust signatures from multiple repositories
stella attest verify \
  --artifact sha256:... \
  --certificate-identity "repo:myorg/(repo1|repo2|repo3):ref:refs/heads/main" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com"

Organization-Wide Trust

# Trust any repository in organization (use with caution)
stella attest verify \
  --artifact sha256:... \
  --certificate-identity "repo:myorg/.*:ref:refs/heads/main" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com"

Troubleshooting

Common Errors

Error Cause Solution
identity mismatch Pattern doesn't match certificate subject Check ref format (refs/heads/ vs branch name)
issuer mismatch Wrong OIDC issuer URL Use correct issuer for platform
certificate expired Signing cert expired, no Rekor proof Ensure --require-rekor and Rekor was used at signing
no attestations found Attestation not attached to artifact Verify attestation was pushed to registry

Debugging Identity Patterns

# Inspect certificate to see actual identity
stella attest inspect \
  --artifact sha256:... \
  --show-cert

# Expected output:
# Certificate Subject: repo:stellaops/scanner:ref:refs/heads/main
# Certificate Issuer: https://token.actions.githubusercontent.com
# Certificate SAN: https://github.com/stellaops/scanner/.github/workflows/release.yml@refs/heads/main

Testing Patterns

# Test pattern matching locally
echo "repo:myorg/myrepo:ref:refs/heads/main" | \
  grep -E "repo:myorg/myrepo:ref:refs/heads/(main|develop)"