Configure Image Provenance Using ImagePolicyWebhook
More Info:
Verifies image provenance is enforced via the ImagePolicyWebhook admission controller so only approved, verified images can be admitted to the cluster.
Risk Level
High
Address
Security
Compliance Standards
- CIS GKE
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Review current admission configuration for ImagePolicyWebhook
- Machine: any machine with kubectl access
- Command:
kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations \-o yaml | grep -i -A5 -B5 "imagepolicy"
- Interpretation: Check if any webhook configuration refers to an ImagePolicyWebhook implementation (e.g., names/URLs mentioning “image-policy”, “imageprovenance”, or your chosen image policy service). If none exist, image provenance via ImagePolicyWebhook is not configured.
-
Identify and inspect any image policy webhook configuration
- Machine: any machine with kubectl access
- Commands:
For each candidate webhook name (replace with actual name you saw, for examplekubectl get validatingwebhookconfigurationskubectl get mutatingwebhookconfigurations
image-policy-webhook):kubectl get validatingwebhookconfiguration image-policy-webhook -o yaml - Interpretation: Confirm that the webhook is configured to intercept
CREATEandUPDATEoperations onpodsand/or higher-level workload types (Deployments, StatefulSets, DaemonSets, Jobs, CronJobs) in relevant API groups.
-
Verify the webhook enforces only approved, verified images
- Machine: any machine with kubectl access
- From the webhook config YAML, collect:
clientConfig.urlorclientConfig.servicetargetrules.resourcesandrules.operationsfailurePolicyandnamespaceSelector/objectSelector
- Then retrieve the backing Service/Deployment implementing the webhook (example name, adjust as needed):
kubectl get svc,imagepolicy-deployment -n kube-system -o yamlkubectl logs deploy/imagepolicy-deployment -n kube-system --tail=100
- Interpretation: Using your organization’s image policy design, confirm that the webhook backend validates image provenance (e.g., signature verification, allowed registries, allowed repositories/tags) and rejects non‑compliant images.
-
Check behavior with a non‑compliant image (safe test)
- Machine: any machine with kubectl access
- Create a pod manifest using an image that should be rejected by policy (e.g., from an unapproved registry or with a disallowed tag):
cat <<'EOF' > /tmp/test-unapproved-image.yamlapiVersion: v1kind: Podmetadata:name: test-unapproved-imagenamespace: defaultspec:containers:- name: cimage: gcr.io/library/busybox:latestcommand: ["sh", "-c", "sleep 3600"]EOFkubectl apply -f /tmp/test-unapproved-image.yaml
- Interpretation: The request should be rejected by the webhook, with an error message indicating image policy violation. If the pod is admitted and runs, provenance is not effectively enforced.
-
If image provenance is missing or ineffective, plan and apply an ImagePolicyWebhook configuration
- Machine: any machine with kubectl access
- Using Kubernetes documentation and your image verification solution, prepare:
- A Deployment/Service that implements image verification logic.
- A
ValidatingWebhookConfigurationthat:- Targets
CREATE/UPDATEon workloads using containers. - Uses
failurePolicy: Fail(or your risk‑based choice). - Uses appropriate
namespaceSelectorto include production namespaces.
- Targets
- Apply once designed:
kubectl apply -f /path/to/your-image-policy-webhook.yaml
-
Re‑verify enforcement and document the decision
- Machine: any machine with kubectl access
- Confirm configuration and behavior after changes:
kubectl get validatingwebhookconfigurations -o yaml | grep -i -A5 -B5 "imagepolicy"kubectl delete pod test-unapproved-image --ignore-not-foundkubectl apply -f /tmp/test-unapproved-image.yaml
- Interpretation: Ensure the test pod is rejected; capture the webhook configuration and rejection output as evidence. If you intentionally choose not to enforce image provenance via ImagePolicyWebhook (e.g., using a different trusted mechanism), document that rationale and the alternative controls in your risk register.
Using kubectl
# 1) Check if ImagePolicyWebhook admission plugin is enabled (GKE Autopilot/Standard)
# Run on: any machine with kubectl access
kubectl get podsecurityadmissionconfigurations --all-namespaces
If this returns No resources found or there is no admission configuration mentioning ImagePolicyWebhook, you likely do not have a cluster-scoped admission configuration resource configured. In GKE, image provenance is typically configured via Binary Authorization rather than raw ImagePolicyWebhook; absence here means you must confirm how provenance is enforced.
# 2) List all Validating and MutatingWebhookConfigurations
# Run on: any machine with kubectl access
kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations -o wide
Review the NAME and WEBHOOKS columns. A problem exists if:
- There is no webhook related to image policy, image verification, or provenance (names often contain strings like
imagepolicy,binauthz,image-verify,cosign,notary), and - You rely on this mechanism to enforce provenance (per your policy).
# 3) Inspect candidate webhook configurations for image provenance logic
# Replace <webhook-name> with any likely image-related webhook name
# Run on: any machine with kubectl access
kubectl get validatingwebhookconfiguration <webhook-name> -o yaml
kubectl get mutatingwebhookconfiguration <webhook-name> -o yaml
In the YAML, focus on:
-
webhooks.rules→apiGroups,apiVersions,resources:
A problem exists if the webhook does not target pod/image-bearing resources such as:apiGroups: [""],resources: ["pods", "pods/ephemeralcontainers"]- Or workload types like
deployments,daemonsets,statefulsets,jobs,cronjobs.
-
webhooks.rules.operations:
A problem exists ifCREATE(and ideallyUPDATE) operations are not included for these resources, because images could be introduced/changed without being checked. -
webhooks.clientConfig:
A problem exists if theserviceorurltargets a non-existent/broken backend (service missing, TLS misconfigured, or timeouts), meaning image checks may silently fail-open depending onfailurePolicy. -
webhooks.failurePolicy:
A problem exists iffailurePolicy: Ignoreis set, because if the external verifier is unreachable, images may be admitted without provenance verification. Many orgs requirefailurePolicy: Fail. -
webhooks.matchPolicy,namespaceSelector,objectSelector:
A problem exists if selectors exclude namespaces or pods that should be governed by provenance policy (for example, all application namespaces are excluded).
# 4) Check whether the webhook is actually invoked on pod creation
# Run on: any machine with kubectl access
# Try to create a simple pod using an untrusted or obviously test image
kubectl apply -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: image-provenance-test
namespace: default
spec:
containers:
- name: test
image: nginx:1.7.9 # adjust to an image that should be blocked by your policy
EOF
Interpretation:
-
If the pod is created successfully and your policy says unverified/unapproved images must be blocked, this indicates:
- No effective image provenance enforcement, or
- The webhook configuration does not cover this namespace/resource/type.
-
If the pod fails to create with an error message from an admission controller (e.g. mentioning image verification, signature, policy, or provenance), that indicates some form of image provenance enforcement is in place. Review the error details and webhook config to confirm it meets your policy and CIS guidance.
# 5) Clean up the test pod
# Run on: any machine with kubectl access
kubectl delete pod image-provenance-test -n default --ignore-not-found
Use the above evidence to decide whether:
- Image provenance is enforced (via ImagePolicyWebhook, Binary Authorization, or an equivalent validating webhook), and
- The scope and failure behavior align with your security requirements and the benchmark recommendation.
Automation
#!/usr/bin/env bash
# Purpose: Report ImagePolicyWebhook / image provenance configuration cluster-wide
# Scope: Run on any machine with kubectl access and current kube-context set
set -euo pipefail
echo "=== 1) API server admission configuration (ImagePolicyWebhook) ==="
echo
echo "--- API Server Pod/Deployment manifests using ImagePolicyWebhook (if any) ---"
kubectl get pods -A \
-l component=kube-apiserver, tier=control-plane \
-o wide 2>/dev/null || echo "No kube-apiserver pods with standard labels found"
echo
echo "--- API Server container args containing 'admission-control' or 'enable-admission-plugins' ---"
kubectl get pods -A \
-l component=kube-apiserver,tier=control-plane \
-o jsonpath='{range .items[*]}Namespace: {.metadata.namespace} | Pod: {.metadata.name}{"\n"} Args: {.spec.containers[*].command} {.spec.containers[*].args}{"\n\n"}{end}' \
2>/dev/null || echo "Unable to fetch kube-apiserver pod args via standard labels."
echo
echo "--- API Server ConfigMap / flags (kube-apiserver) via kube-system namespace (best-effort) ---"
kubectl get cm -n kube-system 2>/dev/null | grep -Ei 'apiserver|kube-apiserver' || \
echo "No obvious kube-apiserver ConfigMaps found in kube-system."
echo
echo "NOTE: You must verify that the kube-apiserver process is started with:"
echo " - admission-control=...,ImagePolicyWebhook,... (legacy)"
echo " OR"
echo " - enable-admission-plugins=...,ImagePolicyWebhook,... (current)"
echo "If ImagePolicyWebhook is missing from both, image provenance is NOT enforced by this mechanism."
echo
echo "=== 2) Validating/MutatingAdmissionConfiguration that references ImagePolicyWebhook ==="
echo
echo "--- AdmissionConfiguration resources (if API is enabled) ---"
# This may fail if the AdmissionConfiguration API is not served
kubectl get ValidatingAdmissionPolicyConfiguration 2>/dev/null || \
echo "No ValidatingAdmissionPolicyConfiguration resources or API not available."
kubectl get MutatingAdmissionPolicyConfiguration 2>/dev/null || \
echo "No MutatingAdmissionPolicyConfiguration resources or API not available."
echo
echo "NOTE: Classic ImagePolicyWebhook configuration usually comes from an"
echo "AdmissionConfiguration file/flag on the API server, not a Kubernetes object."
echo "You must inspect the kube-apiserver startup flags or managed control-plane"
echo "configuration to confirm whether an AdmissionConfiguration file is used and"
echo "that it defines 'imagePolicy' with 'kubeConfigFile' and 'allowTTLSeconds', etc."
echo
echo "=== 3) Image policy / provenance enforcement using other admission mechanisms ==="
echo
echo "--- ValidatingWebhookConfiguration objects (may implement image provenance) ---"
kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io -o wide 2>/dev/null || \
echo "No ValidatingWebhookConfiguration resources found."
echo
echo "--- MutatingWebhookConfiguration objects (may implement image mutation/signature checks) ---"
kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io -o wide 2>/dev/null || \
echo "No MutatingWebhookConfiguration resources found."
echo
echo "--- Details of webhooks that reference images or provenance keywords ---"
webhook_keywords='image|cosign|notary|provenance|signature|sigstore|policy-controller'
kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io -o yaml 2>/dev/null | \
egrep -i "$webhook_keywords" || \
echo "No obvious image/provenance-related patterns found in ValidatingWebhookConfigurations."
echo
kubectl get mutatingwebhookconfigurations.admissionregistration.k8s.io -o yaml 2>/dev/null | \
egrep -i "$webhook_keywords" || \
echo "No obvious image/provenance-related patterns found in MutatingWebhookConfigurations."
echo
echo "=== 4) Namespaces or workloads explicitly bypassing admission webhooks ==="
echo
echo "--- Namespaces labeled to disable admission webhooks (common patterns) ---"
kubectl get ns --show-labels 2>/dev/null | \
egrep 'no\-webhook|skip\-webhook|admission\-skip|webhook=disabled' || \
echo "No namespaces with obvious 'skip webhook' labels using common patterns."
echo
echo "--- Pods using hostNetwork or privileged (high risk if image provenance is weak) ---"
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{" hostNet="}{.spec.hostNetwork}{" privileged="}{range .spec.containers[*]}{.securityContext.privileged}{" "}{end}{"\n"}{end}' 2>/dev/null || \
echo "Unable to list pod security context details."
echo
echo "=== 5) Summary: what indicates a problem ==="
cat <<'EOF'
Review guidance:
1) API server flags:
- PROBLEM if:
* kube-apiserver is NOT configured with ImagePolicyWebhook via either:
- --admission-control including ImagePolicyWebhook
- --enable-admission-plugins including ImagePolicyWebhook
AND you have no alternative enforced image provenance mechanism (e.g. cosign-based webhook).
2) AdmissionConfiguration:
- PROBLEM if:
* API server references an AdmissionConfiguration file, but it does NOT define
an 'imagePolicy' section pointing to a kubeConfigFile for the webhook and
appropriate allow/deny behavior; or the referenced webhook service does not exist.
3) Webhooks:
- POTENTIAL PROBLEM if:
* There are no ValidatingWebhookConfiguration or MutatingWebhookConfiguration
objects that implement image signature/provenance checks (by design or by name),
and ImagePolicyWebhook is also not configured.
4) Bypasses:
- PROBLEM / RISK if:
* Critical namespaces or workloads are labeled/annotated to skip admission webhooks,
effectively bypassing image provenance checks.
This script does NOT automatically determine compliance.
You must:
- Confirm the kube-apiserver startup configuration (flags / managed control-plane settings).
- Confirm whether an ImagePolicyWebhook or equivalent webhook is deployed and reachable.
- Decide whether the observed configuration satisfies your image provenance policy.
EOF