CME-712
Container Image Signing and Provenance Verification (Cosign/Sigstore)
Description
Require cryptographic signatures on container images before deployment. Cosign/Sigstore verify image provenance against a trust policy, ensuring only images from authorized build pipelines are admitted. Blocks supply chain attacks where a compromised registry or build system pushes malicious images. Verification can be enforced at admission time via policy controllers (Kyverno, Gatekeeper with cosign) or at pull time via container runtime trust policies (Podman policy.json, CRI-O).
CVSS Vector Impacts
| Metric | Transition | Rationale |
|---|---|---|
| Attack Complexity (AC) | L → H | Attacker must forge a valid cryptographic signature or compromise the signing key to inject a malicious container image; simply pushing to a registry is insufficient |
| Integrity (I) | H → L | Unsigned or tampered images are rejected at admission; modifications to images after signing are detected and blocked |
CWE Relationships
Verification
Verify image signature verification is enforced at admission or runtime level
$ kubectl get clusterimagepolicy --no-headers 2>/dev/null | wc -l || kubectl get policy.sigstore.dev --no-headers 2>/dev/null | wc -l
# Expected: >=1
# Expected: >=1
Platform: kubernetes
$ kubectl get clusterpolicy -o jsonpath='{range .items[*]}{.spec.rules[*].verifyImages}{end}' 2>/dev/null | grep -c 'image'
# Expected: >=1
# Expected: >=1
Platform: kubernetes
$ podman image trust show 2>/dev/null | grep -c 'signedBy'
# Expected: >=1
# Expected: >=1
Platform: linux
$ cat /etc/containers/policy.json 2>/dev/null | grep -c 'signedBy'
# Expected: >=1
# Expected: >=1
Platform: linux
$ cosign verify --key <cosign_public_key> <image> 2>&1 | grep -c 'The following checks were performed'
# Expected: 1
# Expected: 1
Platform: any
$ kubectl run cme-unsigned-test --image=docker.io/library/busybox:latest --restart=Never --dry-run=server 2>&1 | grep -c -i 'denied\|forbidden\|failed.*verif\|signature'
# Expected: >=1
# Expected: >=1
Platform: kubernetes
Remediation
kubernetes
Kyverno ClusterPolicy with cosign image signature verification
cat <<'POLICY' | kubectl apply -f -
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-image-signature
spec:
validationFailureAction: Enforce
background: false
rules:
- name: verify-image-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "<registry>/*"
attestors:
- entries:
- keys:
publicKeys: |-
<cosign_public_key>
POLICY
linux
Podman/CRI-O container image trust policy via policy.json
cp /etc/containers/policy.json /etc/containers/policy.json.bak 2>/dev/null; cat > /etc/containers/policy.json <<'POLICY'
{
"default": [
{
"type": "reject"
}
],
"transports": {
"docker": {
"<registry>": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "/etc/pki/rpm-gpg/<signing_key_file>"
}
],
"registry.access.redhat.com": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release"
}
]
},
"atomic": {
"<registry>": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "/etc/pki/rpm-gpg/<signing_key_file>"
}
]
}
}
}
POLICY
cp <path_to_signing_public_key> /etc/pki/rpm-gpg/<signing_key_file>