Kubernetes v1.33 Fixes a 10-Year-Old Image Pull Loophole
For over a decade, Kubernetes had a subtle but significant security gap when it came to image pull policies and private registries. This long-standing issue (tracked as #18787) allowed pods to reuse container images already pulled onto a node, even if they weren’t authorized to do so.
With Kubernetes v1.33, that loophole is finally being addressed.
The Problem: Reusing Private Images Without Authorization¶
In Kubernetes, image pull policies control when the Kubelet fetches container images from registries. If a pod specifies imagePullPolicy: IfNotPresent
and the image already exists on the node, Kubelet skips the pull and starts the pod using the cached image. This works fine for public images, but becomes a problem for private ones.
Here’s what could happen:
- Pod A in namespace
team-a
is authorized to pullprivate.registry/foo/bar:latest
using image pull secrets. The image is pulled and cached on Node X. - Pod B in namespace
team-b
schedules to the same node and references the same image withimagePullPolicy: IfNotPresent
, but lacks the necessary pull secrets. - Since the image already exists, Kubelet starts Pod B using the image, without validating if Pod B had the right to use it.
This broke the isolation model and led to unintentional privilege escalations across namespaces.
The Fix: Enforcing Image Pull Secrets Even After Caching¶
Starting with Kubernetes v1.33, a new feature controlled by the KubeletEnsureSecretPulledImages
flag changes this behavior. Now, Kubelet verifies that a pod has valid credentials before letting it run a cached image pulled from a private registry.
The key idea: presence of the image on the node is no longer enough. Authorization is always checked—even for IfNotPresent
and Never
pull policies.
Behavior by Pull Policy¶
- Always: No change. Kubelet always pulls the image, and registry auth is enforced.
- IfNotPresent: Now validates credentials against a local cache of previously successful image pulls.
- Never: Kubelet won't pull, but it still checks that credentials match what was used for the original authorized pull.
How It Works Internally¶
The feature uses a file-based cache to track:
- Credential hashes used during successful image pulls
- Originating Secrets that supplied these credentials
When a pod references a cached image:
- If its credentials match the cached entry (via hash or Secret name), it is allowed to run.
- If not, the Kubelet attempts a new pull using the new credentials to verify access.
The cache ensures credential reuse is safe while allowing verification without unnecessary registry calls.
Projected Service Account Tokens (PSAT) Support¶
In parallel, KEP-4412 enables projected service account tokens to be used by the Kubelet when pulling images, providing better workload isolation and finer-grained access control.
Together, these efforts improve how image pulls are authenticated and authorized at node level.
How to Enable¶
To test the feature:
You can monitor the evolution of this enhancement in KEP-2535 and track its graduation toward beta in v1.34.
What’s Next?¶
Future improvements are already planned:
- Support for PSAT-based image credential providers (KEP-4412)
- TTLs for credential entries to handle expiration and revocation
- In-memory cache to reduce I/O latency
- Benchmarking performance under load
Final Thoughts¶
It’s rare to see a 10-year-old issue resolved in such a comprehensive and forward-looking manner. Kubernetes v1.33’s enhancement to image pull security finally closes a long-ignored hole, bringing clarity and control to multi-tenant environments that depend on private registries.
If you're running shared clusters, enabling this feature is a no-brainer.
FAQs
What was the image pull security issue in Kubernetes prior to v1.33?
Pods could reuse cached private images on a node without validating their credentials. If a private image had already been pulled by an authorized pod, any subsequent pod referencing it (even without pull secrets) could start using it, bypassing registry authentication.
What specific change does Kubernetes v1.33 introduce to fix the image reuse issue?
Kubernetes v1.33 introduces the KubeletEnsureSecretPulledImages
feature flag. When enabled, Kubelet enforces image pull secret validation even for cached images. Before starting a pod, Kubelet checks that the pod's credentials (pull secrets or service account tokens) match those used when the image was originally pulled. If they don’t, Kubelet attempts a new pull using the provided credentials. This ensures that only authorized pods can use cached private images, closing the loophole that previously allowed unauthorized access.
How does the credential validation mechanism work?
Kubelet maintains a file-based cache of credential hashes and originating secrets from prior successful image pulls. When a pod tries to use a cached image, Kubelet checks that its credentials match the cached entry. If not, it attempts a fresh pull with the new credentials.
What are the implications for imagePullPolicy settings?
Always
: Behavior remains unchanged, Kubelet pulls the image every time.IfNotPresent
: Now validates credentials before using the cached image.Never
: Kubelet won’t pull, but it still validates that the pod has matching credentials for the cached image.