# Cosign Interoperability Guide This document describes how to verify StellaOps attestations using [cosign](https://github.com/sigstore/cosign) and how to import cosign-created attestations into StellaOps. ## Overview StellaOps attestations use the [DSSE (Dead Simple Signing Envelope)](https://github.com/secure-systems-lab/dsse) format and OCI Distribution Spec 1.1 referrers API for attachment, which is compatible with cosign's attestation workflow. **Sprint Reference:** `SPRINT_20251228_002_BE_oci_attestation_attach` (T6) ## Verifying StellaOps Attestations with Cosign ### Basic Verification ```bash # Verify any attestation attached to an image cosign verify-attestation \ --type custom \ --certificate-identity-regexp '.*' \ --certificate-oidc-issuer-regexp '.*' \ registry.example.com/app:v1.0.0 # Verify a specific predicate type cosign verify-attestation \ --type stellaops.io/predicates/scan-result@v1 \ --certificate-identity-regexp '.*' \ --certificate-oidc-issuer-regexp '.*' \ registry.example.com/app:v1.0.0 ``` ### Verification with Trust Roots StellaOps supports both keyless (Sigstore Fulcio) and key-based signing: #### Keyless Verification (Sigstore) ```bash # Verify attestation signed with keyless mode cosign verify-attestation \ --type stellaops.io/predicates/scan-result@v1 \ --certificate-identity 'scanner@stellaops.io' \ --certificate-oidc-issuer 'https://oauth2.sigstore.dev/auth' \ registry.example.com/app:v1.0.0 ``` #### Key-Based Verification ```bash # Verify attestation signed with a specific key cosign verify-attestation \ --type stellaops.io/predicates/scan-result@v1 \ --key /path/to/public-key.pem \ registry.example.com/app:v1.0.0 ``` ### Rekor Transparency Log Verification When StellaOps attestations are recorded in Rekor, cosign automatically verifies the inclusion proof: ```bash # Verify with Rekor inclusion proof cosign verify-attestation \ --type stellaops.io/predicates/scan-result@v1 \ --certificate-identity-regexp '.*' \ --certificate-oidc-issuer-regexp '.*' \ --rekor-url https://rekor.sigstore.dev \ registry.example.com/app:v1.0.0 # Skip Rekor verification (offline environments) cosign verify-attestation \ --type stellaops.io/predicates/scan-result@v1 \ --key /path/to/public-key.pem \ --insecure-ignore-tlog \ registry.example.com/app:v1.0.0 ``` ## StellaOps Predicate Types StellaOps uses the following predicate type URIs: | Predicate Type | Description | cosign `--type` | |----------------|-------------|-----------------| | `stellaops.io/predicates/scan-result@v1` | Vulnerability scan results | `stellaops.io/predicates/scan-result@v1` | | `stellaops.io/predicates/sbom@v1` | Software Bill of Materials | `stellaops.io/predicates/sbom@v1` | | `stellaops.io/predicates/vex@v1` | Vulnerability Exploitability eXchange | `stellaops.io/predicates/vex@v1` | | `https://slsa.dev/provenance/v1` | SLSA Provenance | `slsaprovenance` | ### Predicate Type Aliases For convenience, cosign supports type aliases: ```bash # These are equivalent for SLSA provenance cosign verify-attestation --type slsaprovenance ... cosign verify-attestation --type https://slsa.dev/provenance/v1 ... ``` ## Importing Cosign Attestations into StellaOps StellaOps can consume attestations created by cosign: ### CLI Import ```bash # Fetch cosign attestation and import to StellaOps cosign download attestation registry.example.com/app:v1.0.0 > attestation.json # Import into StellaOps stella attest import \ --envelope attestation.json \ --image registry.example.com/app:v1.0.0 ``` ### API Import ```bash curl -X POST https://stellaops.example.com/api/v1/attestations/import \ -H "Content-Type: application/json" \ -d @attestation.json ``` ## Annotation Compatibility StellaOps uses the following annotations on attestation manifests: | Annotation Key | Description | Cosign Equivalent | |----------------|-------------|-------------------| | `org.opencontainers.image.created` | Creation timestamp | Standard OCI | | `dev.stellaops/predicate-type` | Predicate type URI | `dev.cosignproject.cosign/predicateType` | | `dev.stellaops/tenant` | StellaOps tenant ID | Custom | | `dev.stellaops/scan-id` | Associated scan ID | Custom | | `dev.sigstore.cosign/signature` | Signature placeholder | Standard Sigstore | ### Custom Annotations You can add custom annotations when attaching attestations: ```bash # Stella CLI with custom annotations stella attest attach \ --image registry.example.com/app:v1.0.0 \ --attestation scan.json \ --annotation "org.example/team=security" \ --annotation "org.example/policy-version=2.0" ``` ## Media Types StellaOps attestations use standard media types: | Media Type | Usage | |------------|-------| | `application/vnd.dsse.envelope.v1+json` | DSSE envelope containing attestation | | `application/vnd.in-toto+json` | In-toto attestation payload | | `application/vnd.oci.image.manifest.v1+json` | OCI manifest for referrers | ## Trust Root Configuration ### Sigstore Trust Roots For keyless verification, configure the Sigstore trust bundle: ```yaml # stellaops.yaml attestation: trustRoots: sigstore: enabled: true fulcioUrl: https://fulcio.sigstore.dev rekorUrl: https://rekor.sigstore.dev ctlogUrl: https://ctfe.sigstore.dev ``` ### Custom Trust Roots For enterprise deployments with private Sigstore instances: ```yaml # stellaops.yaml attestation: trustRoots: sigstore: enabled: true fulcioUrl: https://fulcio.internal.example.com rekorUrl: https://rekor.internal.example.com trustedRootPem: /etc/stellaops/sigstore-root.pem ``` ### Air-Gapped Environments For offline verification: ```yaml # stellaops.yaml attestation: trustRoots: offline: true bundlePath: /etc/stellaops/trust-bundle.json ``` ## Policy Integration Attestation verification can be integrated into admission control policies: ### Gatekeeper/OPA Policy Example ```rego package stellaops.attestation deny[msg] { input.kind == "Pod" container := input.spec.containers[_] image := container.image # Require scan attestation not has_valid_attestation(image, "stellaops.io/predicates/scan-result@v1") msg := sprintf("Image %v missing valid scan attestation", [image]) } has_valid_attestation(image, predicate_type) { attestation := stellaops.get_attestation(image, predicate_type) stellaops.verify_attestation(attestation) } ``` ### Kyverno Policy Example ```yaml apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-stellaops-attestation spec: validationFailureAction: Enforce rules: - name: check-scan-attestation match: resources: kinds: - Pod verifyImages: - imageReferences: - "*" attestations: - predicateType: stellaops.io/predicates/scan-result@v1 attestors: - entries: - keyless: issuer: https://oauth2.sigstore.dev/auth subject: scanner@stellaops.io ``` ## Troubleshooting ### Common Issues #### No Attestations Found ```bash # List all attestations attached to an image cosign tree registry.example.com/app:v1.0.0 # Or use stella CLI stella attest oci-list --image registry.example.com/app:v1.0.0 ``` #### Signature Verification Failed Check that you're using the correct verification key or identity: ```bash # Inspect the attestation to see signer identity cosign verify-attestation \ --type stellaops.io/predicates/scan-result@v1 \ --certificate-identity-regexp '.*' \ --certificate-oidc-issuer-regexp '.*' \ --output text \ registry.example.com/app:v1.0.0 | jq '.optional.Issuer, .optional.Subject' ``` #### Rekor Entry Not Found If the attestation was created without Rekor submission: ```bash cosign verify-attestation \ --insecure-ignore-tlog \ --key /path/to/public-key.pem \ registry.example.com/app:v1.0.0 ``` ### Debug Mode Enable verbose output for troubleshooting: ```bash COSIGN_EXPERIMENTAL=1 cosign verify-attestation \ --verbose \ --type stellaops.io/predicates/scan-result@v1 \ registry.example.com/app:v1.0.0 ``` ## References - [Cosign Documentation](https://docs.sigstore.dev/cosign/overview/) - [DSSE Specification](https://github.com/secure-systems-lab/dsse) - [In-toto Attestation Framework](https://in-toto.io/) - [OCI Distribution Spec 1.1 Referrers](https://github.com/opencontainers/distribution-spec/blob/main/spec.md#referrers) - [StellaOps Attestor Architecture](../modules/attestor/architecture.md)