Files
Homelabv4/infrastructure/kyverno/policies/restrict-image-registries.yaml
T
Scooby HuskyandClaude Opus 4.6 131cbca4a6 Fix ArgoCD ServerSideDiff permanent OutOfSync diffs
Add explicit CRD/API defaults to manifests that were causing ArgoCD's
SSA dry-run to produce results different from live state:

- HTTPRoutes: add group, kind, weight defaults to parentRefs/backendRefs
- Kyverno ClusterPolicies: add skipBackgroundRequests, allowExistingViolations
- Tetragon TracingPolicies: add return, maxData, resolve, returnCopy defaults
- Gateway certificateRefs: add group="" default
- Guacamole Gateway: add group="" to certificateRefs

Add ignoreDifferences for resources that legitimately differ:
- Cilium cert Secrets (auto-generated, data always differs)
- Istio ValidatingWebhookConfiguration failurePolicy (istiod mutates)
- Crowdsec LAPI Secrets (randomly generated)
- ServiceMonitor/PodMonitor relabeling action defaults
- StatefulSet volumeClaimTemplates apiVersion/kind defaults

Persist argocd-cm ignoreDifferences config in ArgoCD Helm values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 17:32:59 -05:00

110 lines
4.2 KiB
YAML

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: "*.*/*"