Supply chain verification (cosign & SBOM)

Audience: DevOps / platform engineers Time: ~25 min Prerequisites: Custom deployment (Kubernetes & Helm), cosign installed on your build workstation

Control Core supports optional container image signing and SBOM generation on your engineering release path. Signing requires your organization to provision and manage signing keys. Nothing is signed by default — your pipeline must be configured to enable it.

What is implemented

CapabilityWhat you receiveDefault
Image signing (cosign)A signing hook in the build script that calls cosign sign when keys are configuredSkipped when keys or tooling absent
SLSA provenance attestationdocker buildx --provenance attaches a SLSA level-1 provenance envelope to each imageOn when DOCKER_PLATFORM set
SBOM attestationdocker buildx --sbom attaches a CycloneDX SBOM to each imageOn when DOCKER_PLATFORM set
Merged CycloneDX SBOMA SBOM generation script merges dependency data from all componentsRegenerate when deps change
Vulnerability gateRun the security scan script (trivy, pip-audit, npm audit, bandit, semgrep) before promotingRequired before production rollout

Enable signing on your release builds

Configure your keys once, then run the build script as usual:

# Option A — AWS KMS-backed key (recommended for production)
export COSIGN_KMS_KEY="awskms:///arn:aws:kms:REGION:ACCOUNT:key/KEY_ID"
# or by alias:
# export COSIGN_KMS_KEY="awskms:///alias/your-cosign-key"

# Option B — local key file (development / air-gapped)
export COSIGN_KEY="/path/to/cosign.key"

# Build and push with signing
export DOCKER_PLATFORM=linux/amd64
scripts/build-and-push-ecr.sh --target all --tag YOUR_RELEASE_TAG

The script signs each image immediately after push. If cosign is not in PATH or no key is configured, signing is skipped with a warning — the build succeeds but the image is unsigned.

Troubleshooting: cosign not installed — skipping signing — install cosign from docs.sigstore.dev. For SOC 2 CC6.8 evidence, do not promote unsigned images to a bank pilot without a documented exception in your change management system.

Verify a pushed image

Replace IMAGE with your registry path and tag:

export IMAGE="REGISTRY/controlcoreio/control-plane-api:RELEASE_TAG"

# Verify signature with KMS key
cosign verify --key "${COSIGN_KMS_KEY}" "$IMAGE"

# Verify signature with public key file
cosign verify --key /path/to/cosign.pub "$IMAGE"

Expected output: exit code 0 and a JSON array of verified signature payloads. Any non-zero exit means the image was not signed with the expected key.

Troubleshooting: no matching signatures — the image was pushed without signing, or the wrong key is configured. Re-push with COSIGN_* set and record the image digest in your change management record.

Read SLSA provenance attestations

# Retrieve and display the SLSA provenance envelope
cosign verify-attestation \
  --key "${COSIGN_KMS_KEY}" \
  --type slsaprovenance \
  "$IMAGE" | jq '.payload | @base64d | fromjson'

The decoded payload includes: builder ID, build configuration (Dockerfile, args), build timestamp, and the materials (git commit SHA, base image digest) used to produce the image. Use this record as your build-time audit trail for SOC 2 CC6.8.

Read SBOM attestations

# Retrieve the CycloneDX SBOM attached to the image
cosign verify-attestation \
  --key "${COSIGN_KMS_KEY}" \
  --type sbom \
  "$IMAGE" | jq '.payload | @base64d | fromjson'

The SBOM lists all OS packages, Python/Go libraries, and their versions. Feed this into your preferred SBOM analysis tool (Dependency-Track, Grype, Trivy) for vulnerability correlation.

Install Kyverno in your cluster, then apply an ImageVerification policy that blocks unsigned or improperly signed images:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: controlcore-image-verification
spec:
  validationFailureAction: Enforce
  rules:
    - name: verify-controlcore-images
      match:
        any:
          - resources:
              kinds: [Pod]
              namespaces: [controlcore]
      verifyImages:
        - imageReferences:
            - "REGISTRY/controlcoreio/*:*"
          attestors:
            - count: 1
              entries:
                - keys:
                    publicKeys: |-
                      # Paste your cosign public key (PEM) here
                      -----BEGIN PUBLIC KEY-----
                      ...
                      -----END PUBLIC KEY-----
          attestations:
            - predicateType: https://slsa.dev/provenance/v0.2
              conditions:
                - all:
                    - key: "{{ builder.id }}"
                      operator: Equals
                      value: "https://your-ci.example.com"

Troubleshooting: Pod fails ImageVerificationFailed — confirm the public key PEM matches the key used to sign, and that the image reference pattern covers your registry prefix. View Kyverno policy reports: kubectl get policyreport -n controlcore.

Enforce with OPA Gatekeeper (alternative)

Apply a ConstraintTemplate that calls cosign (or an admission webhook) to verify signatures before pod admission. Refer to Gatekeeper's external data provider for the verification sidecar pattern.

SBOM and vulnerability posture

Regenerate the merged SBOM whenever application dependencies change using the SBOM generation script included with your release package.

Before promoting a tag to production, pair SBOM review with vulnerability scanning:

# Container layer scan
trivy image --severity HIGH,CRITICAL "$IMAGE"

# Python dependency audit (from the API requirements file)
pip-audit -r requirements.txt

# Node dependency audit (from the Control Plane UI source)
npm audit --audit-level=high

Customer packages on controlcore2026 contain deliverables only — no engineering monorepo source.

SOC 2 alignment (honest scope)

TSCWhat Control Core providesWhat you operate
CC6.8Signing hooks, SLSA provenance, SBOM metadata, local vuln gateKey custody, mandatory verify before prod, exception process, admission policy
CC9.2SBOM + provenance attestationsVendor review, accept/fix/suppress decisions

Request a SOC 2 evidence packet from your account team when preparing for audit.

Next steps