Back to Checks
kubernetes

API server pod has AlwaysPullImages admission control plugin enabled

apiserver_always_pull_images_plugin
Service: apiserverSeverity: medium
OfficialBuilt-inVerified
Categories:cluster-security
Resource Type:Pod

Kubernetes API server admission configuration includes AlwaysPullImages, which mutates new Pods to set imagePullPolicy=Always so container images are fetched from the registry at startup using the pod's credentials.

Risk

Without AlwaysPullImages, nodes can run cached images without a fresh registry pull, bypassing credential checks.

  • Unauthorized use of private images (confidentiality)
  • Stale or tampered images deployed (integrity)
  • Vulnerable images persist, widening attack surface (availability)

Run this check with Prowler

Run in Prowler Cloud
Run
prowler kubernetes --checks apiserver_always_pull_images_plugin

Recommendation

Enable AlwaysPullImages on the API server.

Apply defense in depth: restrict pulls to trusted registries, enforce least-privilege image pull secrets, sign and scan images, and prefer immutable digests to prevent drift and ensure verified content.

Remediation

Other

1SSH to a control-plane node
2Edit /etc/kubernetes/manifests/kube-apiserver.yaml
3In spec.containers[0].command or args, ensure the flag includes AlwaysPullImages, e.g.: --enable-admission-plugins=<existing>,AlwaysPullImages
4Save the file; the kubelet will automatically restart the API server with the updated flag

Check Code

from prowler.lib.check.models import Check, Check_Report_Kubernetes
from prowler.providers.kubernetes.services.apiserver.apiserver_client import (
    apiserver_client,
)


class apiserver_always_pull_images_plugin(Check):
    def execute(self) -> Check_Report_Kubernetes:
        findings = []
        for pod in apiserver_client.apiserver_pods:
            report = Check_Report_Kubernetes(metadata=self.metadata(), resource=pod)
            report.status = "PASS"
            report.status_extended = (
                f"AlwaysPullImages admission control plugin is set in pod {pod.name}."
            )
            plugin_set = False
            for container in pod.containers.values():
                plugin_set = False
                for command in container.command:
                    if command.startswith("--enable-admission-plugins"):
                        if "AlwaysPullImages" in command:
                            plugin_set = True
                            break
                if not plugin_set:
                    break
            if not plugin_set:
                report.status = "FAIL"
                report.status_extended = f"AlwaysPullImages admission control plugin is not set in pod {pod.name}."
            findings.append(report)
        return findings