apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: restrict-image-registries annotations: policies.kyverno.io/title: Restrict Image Registries policies.kyverno.io/category: Zero Trust policies.kyverno.io/severity: high policies.kyverno.io/description: >- Validates that all container images come from allowed registries. Images must either use an explicit allowed registry prefix (docker.io/, ghcr.io/, quay.io/, etc.) or be short-name Docker Hub references (no dots before the first slash, e.g. grafana/grafana or busybox). spec: validationFailureAction: Enforce background: true rules: - name: validate-container-registries skipBackgroundRequests: true match: any: - resources: kinds: - Pod exclude: any: - resources: namespaces: - kube-system - kube-node-lease - kyverno validate: allowExistingViolations: true message: >- Images must come from allowed registries: docker.io, ghcr.io, quay.io, registry.k8s.io, gcr.io, lscr.io, registry.gitlab.com, cr.fluentbit.io, public.ecr.aws, ecr-public.aws.com, oci.external-secrets.io, docker-registry3.mariadb.com. Docker Hub short names (org/image or library images) are also allowed. foreach: - list: "request.object.spec.containers" deny: conditions: all: # Image does NOT start with any allowed registry prefix - key: "{{element.image}}" operator: AnyNotIn value: - "docker.io/*" - "ghcr.io/*" - "quay.io/*" - "registry.k8s.io/*" - "gcr.io/*" - "lscr.io/*" - "registry.gitlab.com/*" - "cr.fluentbit.io/*" - "public.ecr.aws/*" - "ecr-public.aws.com/*" - "oci.external-secrets.io/*" - "docker-registry3.mariadb.com/*" # AND image looks like a registry hostname (has a dot before the first slash) # This allows Docker Hub short names like grafana/grafana or busybox - key: "{{element.image}}" operator: Equals value: "*.*/*" - list: "request.object.spec.initContainers || []" deny: conditions: all: - key: "{{element.image}}" operator: AnyNotIn value: - "docker.io/*" - "ghcr.io/*" - "quay.io/*" - "registry.k8s.io/*" - "gcr.io/*" - "lscr.io/*" - "registry.gitlab.com/*" - "cr.fluentbit.io/*" - "public.ecr.aws/*" - "ecr-public.aws.com/*" - "oci.external-secrets.io/*" - "docker-registry3.mariadb.com/*" - key: "{{element.image}}" operator: Equals value: "*.*/*" - list: "request.object.spec.ephemeralContainers || []" deny: conditions: all: - key: "{{element.image}}" operator: AnyNotIn value: - "docker.io/*" - "ghcr.io/*" - "quay.io/*" - "registry.k8s.io/*" - "gcr.io/*" - "lscr.io/*" - "registry.gitlab.com/*" - "cr.fluentbit.io/*" - "public.ecr.aws/*" - "ecr-public.aws.com/*" - "oci.external-secrets.io/*" - "docker-registry3.mariadb.com/*" - key: "{{element.image}}" operator: Equals value: "*.*/*"