Safeguard
Developer Tools•

How do you require image digests with a ValidatingAdmissionPolicy?

Use a ValidatingAdmissionPolicy to reject pods whose images are not pinned by digest. A tested CEL rule, rollout in warn mode, and cases to exempt.

Safeguard Security Team
3 min read

Write a ValidatingAdmissionPolicy whose CEL expression checks that every container image contains an at sign, which marks a digest reference, bind it in Warn and Audit mode first, then switch to Deny. The Kubernetes policy API has been stable since version 1.30, so no webhook is needed.

Why digests

The Kubernetes documentation says a digest identifies a specific version of an image and is immutable, while tags can be moved. With a digest, the cluster runs the same code each time. A reference can carry both: registry.example.com/app:1.4@sha256:..., and only the digest is used to pull.

The policy

This example covers pods and checks regular containers. Test it on your cluster version before relying on it.

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: require-image-digest.example.com
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups: [""]
      apiVersions: ["v1"]
      operations: ["CREATE", "UPDATE"]
      resources: ["pods"]
  validations:
  - expression: "object.spec.containers.all(c, c.image.contains('@sha256:'))"
    message: "All container images must be pinned by sha256 digest."

Add a second validation for init containers, using has(object.spec.initContainers) to guard against the field being absent. Without it, init containers and sidecars escape the rule.

The binding

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: require-image-digest-binding
spec:
  policyName: require-image-digest.example.com
  validationActions: [Warn, Audit]
  matchResources:
    namespaceSelector:
      matchLabels:
        environment: staging

Per the documentation, validationActions accepts Deny, Warn and Audit, and Deny and Warn should not be combined.

Rollout steps

  1. Apply with Warn and Audit in one namespace.
  2. Read the audit events and count violations.
  3. Change deployment templates to resolve tags to digests at release time.
  4. Widen the namespace selector.
  5. Switch to Deny, with system namespaces excluded.

Testing before you enforce

Create a test pod with a tag-only image and confirm you see a warning with the policy message. Create one with a digest and confirm it passes. Then create a pod with a digest in the main container and a tag in an init container, and check that the second validation catches it. Run these as a small script in CI against a scratch cluster, so a Kubernetes upgrade cannot silently change behavior.

Also check how the rule behaves for ephemeral containers and for pods created by Jobs and CronJobs. Controllers create pods from templates, so the rule runs at pod creation, not when you apply the Deployment. A failing rule may therefore show up as a stalled rollout rather than a clear error at apply time. Read the events on the ReplicaSet when that happens.

Cases to think about

Pods created by controllers carry the image from the template, so the policy evaluates pod creation, not just the Deployment. Cluster add-ons often use tags; exclude their namespaces or fix them separately. Do the rule check on registry too if you want, by requiring a prefix.

Remember a digest alone does not make an image safe. It makes it repeatable. Pair it with scanning. Our post on tags vs digests explains the tradeoff.

Quick check

Does a digest rule stop a vulnerable image?

No. It only guarantees the image cannot silently change. You still need scanning and rebuilds.

Do I need a webhook for this?

No. The in-process policy API handles it. Webhooks are for logic that needs external data.

Safeguard offers policies, gates and guardrails for what is allowed to ship; try the free scan to see your inventory.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.