SLSA Level 3 Provenance Attestations
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:
- In-Pipeline Sigstore Attestation Generation (Phase 1): Build and sign provenance within the pipeline.
- In-Pipeline Data Collection (Phase 2): Collect granular build metadata for enriched provenance.
- Platform Indication of Provenance Data (Phase 3): Integrate GitLab platform-specific metadata into provenance.
- Out-of-Pipeline Signing (Phase 4): Enable external, KMS-based artifact signing for better security.
- 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
- Provide a modular and reusable GitLab CI component for generating and signing SLSA-compliant provenance.
- Collect detailed build metadata for supported ecosystems (e.g., containers, Go, Maven).
- Embed GitLab-specific platform data (e.g., pipeline variables, commit IDs) into provenance for traceability.
- Support out-of-pipeline signing via secure KMS or HSM, isolating signing keys from build environments.
- Strengthen runner identity to provide trustworthy attestation of build provenance.
- Align with SLSA Level 3 compliance requirements while minimizing disruption to existing workflows.
- Ensure security, scalability, and ease of adoption across GitLab environments.
Non-Goals
- Achieving SLSA Level 4 compliance, which requires isolated and verifiable builds (future consideration).
- Supporting all possible programming ecosystems or artifact types in Phase 1–5 (focus on key ecosystems first).
- Replacing GitLab’s existing artifact storage and distribution mechanisms.
- Building a fully integrated GitLab-native provenance signing mechanism (external tools like Sigstore will be used).
Terminology/Glossary
- SLSA: Supply-chain Levels for Software Artifacts, a framework for improving supply chain security.
- Provenance: Metadata that describes how an artifact was built, including the source code, dependencies, and environment.
- Sigstore: An open-source tool for signing, verifying, and storing software artifacts securely (e.g., cosign and gitsign).
- OIDC Token: Short-lived, identity-based tokens issued by GitLab CI for secure signing.
- Runner: A build agent that executes GitLab CI/CD pipeline jobs.
- KMS: Key Management Service, an external system to securely manage cryptographic keys.
- HSM: Hardware Security Module, hardware-based systems for secure key storage and signing.
Assumptions
- Provenance Generation: Use Sigstore tools (cosign) to generate and sign provenance files.
- Reusable Components: Build modular GitLab CI components for easy adoption across projects.
- Data Collection: Use both build-specific tools (e.g. go, maven) and GitLab platform metadata for provenance enrichment.
- Signing Methods:
- In-pipeline signing via OIDC-based short-lived credentials for fast MVP.
- Out-of-pipeline signing via KMS for long-term secure artifact signing.
- Runner Hardening: Explore options for strong runner identity using hardware-based solutions (e.g., TPM, secure enclaves).
- Focus Ecosystems: Prioritize containers, Go, and Maven ecosystems in early phases.
Decisions
Design Details
Phase 1: In-Pipeline Sigstore Attestation Generation
- Generate provenance metadata using Sigstore tools (cosign).
- Leverage GitLab CI’s OIDC tokens for secure and short-lived credentials.
- Build a reusable GitLab CI component that can be easily included in pipelines.
Phase 2: In-Pipeline Data Collection
- Integrate tools to collect granular build metadata (e.g., go mod graph for Go, Maven dependency trees for Java).
- Include information about environment variables, timestamps, and build inputs.
- Update provenance structure to include enriched metadata.
Phase 3: Platform Indication of Provenance Data
- Enrich provenance with GitLab-specific metadata, such as:
- Source repository URL
- Pipeline ID and job ID
- Commit hash and branch name
- Ensure metadata collection is seamless and integrated into the GitLab CI component.
Phase 4: Out-of-Pipeline Signing
- Enable integration with external KMS (e.g., AWS KMS, Google KMS) or HSM solutions.
- Use long-term signing keys stored securely outside the pipeline.
- Provide an optional component to sign artifacts after the build completes.
Phase 5: Hardening Pipeline Identity
- Introduce strong runner identity using secure hardware (e.g., TPM, HSM, secure boot).
- Embed runner identity into the provenance metadata.
- Ensure that the runner environment can be verified and trusted.
Implementation Plan
Reusable GitLab CI Component
- Define the structure of the component (e.g., input/output variables, artifact paths).
- 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
- Phase 1: Develop and validate the provenance generation component using Sigstore.
- Phase 2: Extend the component to collect build-specific metadata for supported ecosystems.
- Phase 3: Add functionality to collect and embed GitLab platform metadata.
KMS Integration
- Phase 1: Integrate KMS-based out-of-pipeline signing and ensure key isolation.
Runner Identity Enhancements
- Phase 1: Design runner identity enhancements and explore hardware-based solutions.
Deliverables
- Reusable GitLab CI components (published and documented).
- Integration guides for teams to adopt the components.
- Test coverage to validate SLSA Level 3 compliance.
Implementation Details
Sigstore and GitLab OIDC Integration
- How Sigstore Will Be Used:
- Sigstore tools, specifically cosign, will be leveraged to sign and verify provenance.
- 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.
- The OIDC token provided by GitLab is scoped to the running pipeline job, making it ephemeral and secure.
- GitLab OIDC Integration Workflow:
- GitLab generates an OIDC token in the CI component and exposes it as an environment variable.
- Sigstore’s cosign uses the OIDC token to authenticate the GitLab CI job with Sigstore’s transparency log (Rekor).
- Sigstore validates the identity and grants signing capability for the duration of the job.
- cosign generates a signed provenance file (JSON format) and uploads it to GitLab’s artifacts store.
- OIDC Configuration in GitLab:
- Enable GitLab OIDC support by using the existing ID Token feature.
- 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
- Input Variables:
- SIGNING_TOOL: Default to cosign.
- TARGET_ARTIFACT: Path to the artifact or build output.
- PROVENANCE_FILE: Path to generate the provenance file.
- COSIGN_VERSION: Version of cosign to use.
- Output:
- 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
- Build Artifact Stage (build_artifact):
- Builds the artifact (e.g., binary, container image, etc.).
- Saves the artifact as a pipeline artifact.
- Provenance Generation Stage (generate_provenance):
- Uses the reusable component to:
- Generate the provenance file (provenance.json) for the artifact.
- Sign the provenance file using Sigstore’s cosign with GitLab’s OIDC token (CI_JOB_JWT).
- Uploads the signed provenance as a job artifact.
- Uses the reusable component to:
- Provenance Verification Stage (verify_provenance):
- Validates the signed provenance to ensure authenticity.
- Uses cosign verify-attestation to confirm the provenance signature and verify the artifact.
Security Considerations
- Ephemeral OIDC Tokens:
- The ID token is short-lived and scoped to the current job.
- This ensures it cannot be reused outside the pipeline execution context.
- Artifact and Provenance Storage:
- Use GitLab’s artifact storage to securely store both the build artifact and the signed provenance file.
- Artifacts are automatically managed and can be expired after a specified time.
- Isolation:
- If using shared runners, ensure sandboxed environments (e.g., ephemeral containers).
- Self-hosted runners should follow security best practices to prevent token leakage.
- Dependency Management:
- Pin specific versions of Sigstore tools (e.g., cosign) to prevent supply chain attacks.
- CI Variables:
- 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
- Publish the GitLab CI component in a versioned Git repository to ensure teams can pull stable versions.
- Provide clear documentation and examples for adoption.
- Extend the component in later phases to include additional metadata collection and signing enhancements.
ec84ce65
)