SLSA Level 3 Provenance Attestations

This page contains information related to upcoming products, features, and functionality. It is important to note that the information presented is for informational purposes only. Please do not rely on this information for purchasing or planning purposes. The development, release, and timing of any products, features, or functionality may be subject to change or delay and remain at the sole discretion of GitLab Inc.
Status Authors Coach DRIs Owning Stage Created
ongoing nrosandich darbyfrey devops software supply chain security 2024-12-18

Summary

This document outlines the technical vision, principles, and key architectural decisions for implementing SLSA Level 3 compliance within GitLab CI/CD pipelines. The solution will provide a reusable, modular, and secure way to generate, sign, and verify provenance for artifacts while hardening pipeline identity and build infrastructure.

Proposal

We propose a phased implementation of SLSA Level 3 compliance across GitLab CI/CD pipelines using modular and reusable components. Each phase addresses a critical step:

  1. In-Pipeline Sigstore Attestation Generation (Phase 1): Build and sign provenance within the pipeline.
  2. In-Pipeline Data Collection (Phase 2): Collect granular build metadata for enriched provenance.
  3. Platform Indication of Provenance Data (Phase 3): Integrate GitLab platform-specific metadata into provenance.
  4. Out-of-Pipeline Signing (Phase 4): Enable external, KMS-based artifact signing for better security.
  5. Hardening Pipeline Identity (Phase 5): Strengthen runner identity and build trust into the infrastructure.

This phased approach ensures an MVP can be delivered early, with incremental security and compliance enhancements added over time.

Goals

  1. Provide a modular and reusable GitLab CI component for generating and signing SLSA-compliant provenance.
  2. Collect detailed build metadata for supported ecosystems (e.g., containers, Go, Maven).
  3. Embed GitLab-specific platform data (e.g., pipeline variables, commit IDs) into provenance for traceability.
  4. Support out-of-pipeline signing via secure KMS or HSM, isolating signing keys from build environments.
  5. Strengthen runner identity to provide trustworthy attestation of build provenance.
  6. Align with SLSA Level 3 compliance requirements while minimizing disruption to existing workflows.
  7. Ensure security, scalability, and ease of adoption across GitLab environments.

Non-Goals

  1. Achieving SLSA Level 4 compliance, which requires isolated and verifiable builds (future consideration).
  2. Supporting all possible programming ecosystems or artifact types in Phase 1–5 (focus on key ecosystems first).
  3. Replacing GitLab’s existing artifact storage and distribution mechanisms.
  4. Building a fully integrated GitLab-native provenance signing mechanism (external tools like Sigstore will be used).

Terminology/Glossary

  1. SLSA: Supply-chain Levels for Software Artifacts, a framework for improving supply chain security.
  2. Provenance: Metadata that describes how an artifact was built, including the source code, dependencies, and environment.
  3. Sigstore: An open-source tool for signing, verifying, and storing software artifacts securely (e.g., cosign and gitsign).
  4. OIDC Token: Short-lived, identity-based tokens issued by GitLab CI for secure signing.
  5. Runner: A build agent that executes GitLab CI/CD pipeline jobs.
  6. KMS: Key Management Service, an external system to securely manage cryptographic keys.
  7. HSM: Hardware Security Module, hardware-based systems for secure key storage and signing.

Assumptions

  1. Provenance Generation: Use Sigstore tools (cosign) to generate and sign provenance files.
  2. Reusable Components: Build modular GitLab CI components for easy adoption across projects.
  3. Data Collection: Use both build-specific tools (e.g. go, maven) and GitLab platform metadata for provenance enrichment.
  4. Signing Methods:
    1. In-pipeline signing via OIDC-based short-lived credentials for fast MVP.
    2. Out-of-pipeline signing via KMS for long-term secure artifact signing.
  5. Runner Hardening: Explore options for strong runner identity using hardware-based solutions (e.g., TPM, secure enclaves).
  6. Focus Ecosystems: Prioritize containers, Go, and Maven ecosystems in early phases.

Decisions

Design Details

Phase 1: In-Pipeline Sigstore Attestation Generation

  1. Generate provenance metadata using Sigstore tools (cosign).
  2. Leverage GitLab CI’s OIDC tokens for secure and short-lived credentials.
  3. Build a reusable GitLab CI component that can be easily included in pipelines.

Phase 2: In-Pipeline Data Collection

  1. Integrate tools to collect granular build metadata (e.g., go mod graph for Go, Maven dependency trees for Java).
  2. Include information about environment variables, timestamps, and build inputs.
  3. Update provenance structure to include enriched metadata.

Phase 3: Platform Indication of Provenance Data

  1. Enrich provenance with GitLab-specific metadata, such as:
    1. Source repository URL
    2. Pipeline ID and job ID
    3. Commit hash and branch name
  2. Ensure metadata collection is seamless and integrated into the GitLab CI component.

Phase 4: Out-of-Pipeline Signing

  1. Enable integration with external KMS (e.g., AWS KMS, Google KMS) or HSM solutions.
  2. Use long-term signing keys stored securely outside the pipeline.
  3. Provide an optional component to sign artifacts after the build completes.

Phase 5: Hardening Pipeline Identity

  1. Introduce strong runner identity using secure hardware (e.g., TPM, HSM, secure boot).
  2. Embed runner identity into the provenance metadata.
  3. Ensure that the runner environment can be verified and trusted.

Implementation Plan

Reusable GitLab CI Component

  1. Define the structure of the component (e.g., input/output variables, artifact paths).
  2. Create templates for users to integrate the component into their .gitlab-ci.yml files.

Key Implementation Projects

Note: the projects listed below are note dependent on each other and can be done in parallel.

Provenance Generation

  1. Phase 1: Develop and validate the provenance generation component using Sigstore.
  2. Phase 2: Extend the component to collect build-specific metadata for supported ecosystems.
  3. Phase 3: Add functionality to collect and embed GitLab platform metadata.

KMS Integration

  1. Phase 1: Integrate KMS-based out-of-pipeline signing and ensure key isolation.

Runner Identity Enhancements

  1. Phase 1: Design runner identity enhancements and explore hardware-based solutions.

Deliverables

  1. Reusable GitLab CI components (published and documented).
  2. Integration guides for teams to adopt the components.
  3. Test coverage to validate SLSA Level 3 compliance.

Implementation Details

Sigstore and GitLab OIDC Integration

  1. How Sigstore Will Be Used:
    1. Sigstore tools, specifically cosign, will be leveraged to sign and verify provenance.
    2. cosign can utilize GitLab CI’s OIDC integration to securely authenticate the job and issue short-lived credentials. These credentials will sign the provenance file.
    3. The OIDC token provided by GitLab is scoped to the running pipeline job, making it ephemeral and secure.
  2. GitLab OIDC Integration Workflow:
    1. GitLab generates an OIDC token in the CI component and exposes it as an environment variable.
    2. Sigstore’s cosign uses the OIDC token to authenticate the GitLab CI job with Sigstore’s transparency log (Rekor).
    3. Sigstore validates the identity and grants signing capability for the duration of the job.
    4. cosign generates a signed provenance file (JSON format) and uploads it to GitLab’s artifacts store.
  3. OIDC Configuration in GitLab:
    1. Enable GitLab OIDC support by using the existing ID Token feature.
    2. Use GitLab CI/CD’s environment variables to expose tokens and necessary metadata.

Reusable GitLab CI Component

The reusable component will abstract away the complexity of provenance generation and signing. It will be implemented as a GitLab CI Component using a template YAML file.

Component Overview

  1. Input Variables:
    1. SIGNING_TOOL: Default to cosign.
    2. TARGET_ARTIFACT: Path to the artifact or build output.
    3. PROVENANCE_FILE: Path to generate the provenance file.
    4. COSIGN_VERSION: Version of cosign to use.
  2. Output:
    1. Signed provenance file uploaded as a pipeline artifact.

Example reusable Component YAML

# .gitlab/components/provenance-signer.yml
component:
  inputs:
    variables:
      SIGNING_TOOL: "cosign" # Default signing tool
      TARGET_ARTIFACT: ""    # Path to artifact (e.g., build artifact)
      PROVENANCE_FILE: "provenance.json" # Output provenance file
      COSIGN_VERSION: "v2.1.0"

  id_tokens:
    GITLAB_OIDC_TOKEN:
      aud: sigstore
  script:
    - echo "Installing Sigstore cosign..."
    - wget -O /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-linux-amd64
    - chmod +x /usr/local/bin/cosign
    - echo "Generating provenance for ${TARGET_ARTIFACT}..."
    - cosign generate-provenance ${TARGET_ARTIFACT} > ${PROVENANCE_FILE}
    - echo "Signing provenance using GitLab OIDC token..."
    - cosign attest --type slsaprovenance --predicate ${PROVENANCE_FILE} --oidc-issuer "https://gitlab.com" --oidc-token ${GITLAB_OIDC_TOKEN}
  artifacts:
    paths:
      - ${PROVENANCE_FILE}
    expire_in: 7d

Example: Adding the Component to a Pipeline

Here’s how a project would integrate the reusable component into their .gitlab-ci.yml pipeline.

Pipeline YAML Example

stages:
  - build
  - provenance

variables:
  COSIGN_VERSION: "v2.1.0"

build_artifact:
  stage: build
  script:
    - echo "Building artifact..."
    - mkdir -p dist
    - echo "Example artifact content" > dist/example-artifact.txt
  artifacts:
    paths:
      - dist/
    expire_in: 7d

generate_provenance:
  stage: provenance
  needs: ["build_artifact"] # Ensure artifact is built first
  component: .gitlab/components/provenance-signer.yml
  variables:
    TARGET_ARTIFACT: "dist/example-artifact.txt"
    PROVENANCE_FILE: "dist/provenance.json"

verify_provenance:
  stage: provenance
  needs: ["generate_provenance"]
  script:
    - echo "Verifying signed provenance..."
    - cosign verify-attestation --type slsaprovenance dist/example-artifact.txt --certificate-identity-regexp ".*" --certificate-oidc-issuer "https://gitlab.com"

Pipeline Workflow Explanation

  1. Build Artifact Stage (build_artifact):
    1. Builds the artifact (e.g., binary, container image, etc.).
    2. Saves the artifact as a pipeline artifact.
  2. Provenance Generation Stage (generate_provenance):
    1. Uses the reusable component to:
      1. Generate the provenance file (provenance.json) for the artifact.
      2. Sign the provenance file using Sigstore’s cosign with GitLab’s OIDC token (CI_JOB_JWT).
    2. Uploads the signed provenance as a job artifact.
  3. Provenance Verification Stage (verify_provenance):
    1. Validates the signed provenance to ensure authenticity.
    2. Uses cosign verify-attestation to confirm the provenance signature and verify the artifact.

Security Considerations

  1. Ephemeral OIDC Tokens:
    1. The ID token is short-lived and scoped to the current job.
    2. This ensures it cannot be reused outside the pipeline execution context.
  2. Artifact and Provenance Storage:
    1. Use GitLab’s artifact storage to securely store both the build artifact and the signed provenance file.
    2. Artifacts are automatically managed and can be expired after a specified time.
  3. Isolation:
    1. If using shared runners, ensure sandboxed environments (e.g., ephemeral containers).
    2. Self-hosted runners should follow security best practices to prevent token leakage.
  4. Dependency Management:
    1. Pin specific versions of Sigstore tools (e.g., cosign) to prevent supply chain attacks.
  5. CI Variables:
    1. CI Variables will be included in signed provenance file. But will follow the Visibility setting where Masked variables will not store the value, only the key.

Component Maintenance and Scalability

  1. Publish the GitLab CI component in a versioned Git repository to ensure teams can pull stable versions.
  2. Provide clear documentation and examples for adoption.
  3. Extend the component in later phases to include additional metadata collection and signing enhancements.
Last modified January 9, 2025: Initial slsa level 3 blueprint (ec84ce65)