# Images are signed using Docker Content Trust or Cosign; verification enforced at deployment

- **Pattern:** `ab-001644` (`infrastructure-hardening.monitoring-incident-response.image-signing`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001644
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001644)

## Why it matters

Unsigned container images can be silently replaced in a registry — an attacker who gains push access to a registry can swap a legitimate image for a malicious one with the same tag, and every subsequent deployment pulls the compromised image without any cluster-level detection (CWE-494, NIST 800-53 CM-14, SLSA L3). Image signing with Cosign or Docker Content Trust creates a cryptographically verifiable chain from the image back to the CI system that built it. SSDF 800-218 PS.2.1 requires build provenance. Without admission webhook enforcement, signing alone is advisory — images can still be deployed without verification.

## Severity rationale

Low because unsigned image exploitation requires registry write access as a prerequisite, making it a targeted rather than opportunistic attack vector.

## Remediation

Sign images during CI/CD with Cosign and enforce verification at admission. In `.github/workflows/build.yml`:

```bash
# Generate key pair once, store private key as CI secret
cosign generate-key-pair

# Sign after push
cosign sign --key cosign.key $IMAGE_REF
```

Store `COSIGN_PRIVATE_KEY` and `COSIGN_PASSWORD` as CI secrets. The public key (`cosign.pub`) is committed to the repository. For enforcement, deploy Sigstore's policy-controller and create a `ClusterImagePolicy` referencing your public key — this blocks admission of any pod whose image digest cannot be verified against the policy.

## Detection

- **ID:** `image-signing`
- **Severity:** `low`
- **What to look for:** Check CI/CD pipelines for image signing steps (Cosign, Docker Content Trust, Notary). Count all container images built by the project and determine how many include signing. Check Kubernetes admission controller policies for signature verification enforcement (ImageSigningPolicy, ClusterImagePolicy).
- **Pass criteria:** 100% of container images built by the project are signed during the CI/CD build step using Cosign, Docker Content Trust, or equivalent. Kubernetes enforces image signature verification at deployment time via an admission webhook or policy controller. Report: "X of Y images are signed; verification enforced via Z."
- **Fail criteria:** Any images are unsigned, or signing exists but Kubernetes does not enforce signature verification at deployment time.
- **Skip (N/A) when:** The project has minimal container usage or image signing is not feasible in the environment.
- **Detail on fail:** Quote the CI/CD config and admission policy. Example: `"Container images in registry are unsigned. No Cosign or Docker Content Trust signatures found in .github/workflows/build.yml."` or `"Images are signed, but no ValidatingWebhookConfiguration enforces signature verification at deployment time"`
- **Remediation:** Enable image signing with Cosign and enforce verification:

  ```bash
  # Sign image during build
  cosign sign --key cosign.key <image:tag>

  # Create signing key
  cosign generate-key-pair
  ```

  Enforce verification in Kubernetes with policy controller:

  ```yaml
  apiVersion: admissionregistration.k8s.io/v1
  kind: ValidatingWebhookConfiguration
  metadata:
    name: image-signature-verify
  webhooks:
    - name: image-signature.example.com
      clientConfig:
        service:
          name: cosign-webhook
          namespace: cosign-system
      rules:
        - operations: ["CREATE"]
          apiGroups: [""]
          apiVersions: ["v1"]
          resources: ["pods"]
  ```

## External references

- cwe CWE-494
- slsa L3
- nist CM-14
- ssdf PS.2.1

Taxons: supply-chain, operational-readiness

HTML version: https://auditbuffet.com/patterns/ab-001644
