Files
git.stella-ops.org/docs/attestor/cosign-interop.md

8.4 KiB

Cosign Interoperability Guide

This document describes how to verify StellaOps attestations using cosign and how to import cosign-created attestations into StellaOps.

Overview

StellaOps attestations use the DSSE (Dead Simple Signing Envelope) 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

# 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)

# 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

# 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:

# 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:

# 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

# 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

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:

# 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:

# 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:

# 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:

# 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

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

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

# 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:

# 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:

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:

COSIGN_EXPERIMENTAL=1 cosign verify-attestation \
  --verbose \
  --type stellaops.io/predicates/scan-result@v1 \
  registry.example.com/app:v1.0.0

References