Add cosign trusted root creation to ProvenancePublisher

What does this MR do and why?

Adds ProvenancePublisher#cosign_create_trusted_root(ca_certificate:, dir:), a private method next to cosign_import_key_pair and cosign_create_signing_config that builds a cosign trusted root from the project's CA certificate.

The verification approach was agreed in https://gitlab.com/gitlab-org/gitlab/-/work_items/630121 (Option B): the leaf certificate goes in the bundle, and cosign gets the project CA as a trusted root via --trusted-root. Without --trusted-root, cosign attest-blob --certificate leaf.pem signs but skips the certificate chain check, so the trusted root has to be passed.

Not called yet, and the whole flow is behind the slsa_provenance_statement feature flag (https://gitlab.com/gitlab-org/gitlab/-/work_items/547866). https://gitlab.com/gitlab-org/gitlab/-/work_items/603913 will wire this in, alongside the offline signing config from !261751 (merged). Related: !261090 (merged) (with_local_ca_signing_material).

No database, API, UI or docs changes. Only the public CA certificate is used, never SigningCertificate#private_key.

Tests: new describe block in spec/lib/supply_chain/provenance_publisher_spec.rb with 8 examples, covering the exact cosign command, the CA file contents and 0600 mode, that dir is validated before cosign runs, a nil dir, a comma in dir, a PEM string and a nil certificate, a comma in the issuer, and a cosign failure. Full file: 32 examples, 0 failures.

Manual testing: tested end to end in a GDK box with real cosign v3.1.3 and v3.1.1, signing and verifying with the Option B commands from https://gitlab.com/gitlab-org/gitlab/-/work_items/630121. All checks passed on both versions.

References

Screenshots or screen recordings

Not applicable, backend only.

How to set up and validate locally

With cosign installed (brew install cosign):

  1. In a Rails console, build a CA and a leaf certificate, import the leaf key pair, then create the trusted root:

    project = Project.first
    driver = SupplyChain::PostgresCaDriver.new(project)
    ca_certificate = driver.ca_certificate
    leaf = driver.generate_leaf_certificate(ci_config_ref_uri: "#{project.full_path}//.gitlab-ci.yml@refs/heads/main")
    
    # allocate skips the build and JWT setup, which these two methods don't use
    publisher = SupplyChain::ProvenancePublisher.allocate
    dir = Dir.mktmpdir
    File.write(File.join(dir, 'leaf.pem'), leaf.certificate.to_pem)
    imported = publisher.send(:cosign_import_key_pair, key: leaf.key, dir: dir) # writes cosign.key
    
    publisher.send(:cosign_create_trusted_root, ca_certificate: ca_certificate, dir: dir)
    # => "<dir>/trusted-root.json"
    
    puts dir, imported[:password], Gitlab.config.gitlab.url
    puts leaf.certificate.extensions.find { |e| e.oid == 'subjectAltName' }.value # the SAN, after "URI:"
  2. From a shell in dir, with COSIGN_PASSWORD set to the password from step 1, create a test artifact, a predicate and an offline signing config, then sign:

    echo "hello" > artifact.txt
    echo '{"buildDefinition":{"buildType":"manual-test"}}' > predicate.json
    cosign signing-config create --out signing-config.json
    cosign attest-blob --key cosign.key --certificate leaf.pem --trusted-root trusted-root.json \
      --signing-config signing-config.json --predicate predicate.json --type slsaprovenance1 \
      --bundle good.sigstore.json --yes artifact.txt
  3. Verify the bundle with the same trusted root:

    cosign verify-blob-attestation --bundle good.sigstore.json --trusted-root trusted-root.json \
      --certificate-identity <SAN> --certificate-oidc-issuer <ci_server_url> \
      --type slsaprovenance1 --insecure-ignore-tlog --insecure-ignore-sct artifact.txt
  4. Run the specs: bin/rspec spec/lib/supply_chain/provenance_publisher_spec.rb

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Saahil Sabu Hameed

Merge request reports

Loading
Loading