Namespaced Image Validating Policy#
NamespacedImageValidatingPolicy (nivpol) is the namespace-scoped counterpart of ImageValidatingPolicy. It lets teams define image verification rules (signature checking, digest pinning, etc.) within a single namespace rather than cluster-wide. The resource belongs to the policies.kyverno.io API group (v1beta1) and shares its spec structure with ImageValidatingPolicy through the ImageValidatingPolicyLike interface .
Full support for this type — across admission webhooks, background scanning, and policy reporting — was incrementally added via several PRs:
- PR #14242: foundational admission-controller and webhook wiring
- PR #16258: webhook reconciliation stability fix
- PR #16301: background scanner coverage fix
Related bugs were tracked in issue #15286 (webhook call failure) and issue #16300 (background reports not generated).
Webhook Registration and Routing#
The webhook controller (pkg/controllers/webhook/controller.go) handles NamespacedImageValidatingPolicy alongside its cluster-scoped sibling. Key details:
- Informer/lister registration: The controller holds a dedicated
nivpolInformerandnivpolLister. Event handlers for create/update/delete are registered at startup . - Validate webhook path:
buildForPoliciesValidationcallsgetNamespacedImageValidatingPolicies()and appends webhook rules routed to/nivpol/validateunder theImageValidatingPolicyValidateWebhookNameconfiguration . - Mutate webhook path: A parallel path builds mutating webhook entries at
/nivpol/mutate, but only for policies where mutation is actually needed (ivpolsNeedingMutation()) — policies with bothmutateDigest: falseandverifyDigest: falseare excluded . - Policy state recording: After building the configuration, all
ivpolandnivpolpolicies are passed torecordPolicyState()so thepolicystatuscontroller can reflect webhook readiness .
Reconciliation Loop Fix (PR #16258)#
On platforms that normalize webhook configurations (e.g., GKE Autopilot), the webhook controller would enter an infinite reconciliation loop. Two bugs caused this :
- Label selector normalization:
mergeLabelSelectors()emitted non-nil empty maps/slices, which diverged from the Kubernetes API server's stored representation and caused perpetualDeepEqualfailures on every reconcile cycle. - Unnecessary mutation webhook registration: Policies without mutation intent were still registering mutating webhooks, adding extra reconcile churn.
On GKE, this generated over 65 GB of audit logs per week from a single policy before the fix. The fix normalizes empty MatchLabels and MatchExpressions to nil after merging .
Background Scanning and Policy Report Generation#
Background Controller Integration#
The background report controller (pkg/controllers/report/background/controller.go) collects NamespacedImageValidatingPolicy resources during its reconcile loop . When nivpolLister is initialized, FetchNamespacedImageVerificationPolicies is called per namespace; each result is wrapped in engineapi.NewNamespacedImageValidatingPolicy() and included in the policies slice fed to the scanner. Non-background policies are filtered out via celpolicies.RemoveNoneBackgroundPolicies() before wrapping.
Scanner Type-Check Fix (PR #16301)#
The scanner (pkg/controllers/report/utils/scanner.go) classifies incoming GenericPolicy objects using interface assertions. Before PR #16301, this code used AsImageValidatingPolicy() — a type-narrowing call that only matched cluster-scoped policies — causing NamespacedImageValidatingPolicy resources to fall through silently with no report output .
The fix switches to AsImageValidatingPolicyLike(), which matches both ImageValidatingPolicy and NamespacedImageValidatingPolicy through their shared interface. The matched policy is then passed to the ivpolengine provider , which evaluates the image verification rules and feeds results into the background PolicyReport.
PR #16301 also added nil-check guards in the ivpolengine, mpolengine, and vpolengine metric wrappers to prevent nil-pointer panics during background scans .
Policy Status#
The policystatus controller tracks webhook readiness and RBAC health for all CEL-based policy types. For NamespacedImageValidatingPolicy, the dedicated handler lives in pkg/controllers/policystatus/nivpol.go . This file was added as part of PR #14242's status-handling work .
The status conditions mirror those of ImageValidatingPolicy:
WebhookConfigured: set byStateRecorder.Ready(key)after the webhook controller installs the webhook entryRBACPermissionsGranted: verified bySubjectAccessReviewagainst the reports service account for all matched resources
A known bug (issue #15286) manifested as "failed calling webhook 'ivpol.mutate.kyverno.svc-fail'" errors when creating NamespacedImageValidatingPolicy resources. The underlying cause was a resource-version conflict in the status controller ("the object has been modified; please apply your changes to the latest version"). This was resolved after the background scanner fix landed .
Key Source References#
| Component | File | Notes |
|---|---|---|
| API type | api/policies.kyverno.io/v1alpha1/imagevalidating_policy.go | NamespacedImageValidatingPolicy struct; GetTimeoutSeconds() added in PR #14242 |
GenericPolicy wrapper | pkg/engine/api/policy.go:191-199 | AsImageValidatingPolicyLike() returns either scope |
| Webhook controller | pkg/controllers/webhook/controller.go | Informers, webhook build, route /nivpol/validate and /nivpol/mutate |
| Policy status | pkg/controllers/policystatus/nivpol.go | Webhook + RBAC status conditions |
| Background controller | pkg/controllers/report/background/controller.go:841-848 | Fetches and wraps NamespacedImageValidatingPolicy for scan |
| Scanner | pkg/controllers/report/utils/scanner.go:125 | AsImageValidatingPolicyLike() — handles both scopes |
| ivpolengine | pkg/cel/policies/ivpol/engine/ | Evaluates image validation rules for reporting and admission |
Issues and PRs:
- PR #14242 — foundational admission + webhook support
- PR #16258 — webhook reconciliation loop fix
- PR #16301 — background scanner fix
- Issue #15286 — webhook call failure bug
- Issue #16300 — background reports not generated