Documentskyverno
Registry Authentication
Registry Authentication
Type
Topic
Status
Published
Created
Jul 8, 2026
Updated
Jul 8, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

Registry Authentication in Kyverno#

Overview#

Registry authentication in Kyverno controls how the admission controller pulls image metadata from container registries. This matters in two distinct code paths:

  1. Image verification (ImageValidatingPolicy, classic ClusterPolicy) — uses the legacy registryclient package
  2. CEL image data (MutatingPolicy, ValidatingPolicy, ImageValidatingPolicy CEL functions) — uses the imagedataloader module from the Kyverno SDK

Until recently, only the legacy path was wired to CLI credential flags. The CEL path received nil for auth options, causing image.GetMetadata() to fail with 401 Unauthorized against private registries.


The imagedataloader SDK Module (PR #15450)#

PR #15450 (merged March 2026) migrated all image data loading from an internal package (pkg/imageverification/imagedataloader/*, ~1000 lines) to the shared SDK module github.com/kyverno/sdk/extensions/imagedataloader . This affected 19 files across CLI commands, CEL libraries, and image verification evaluators.

The SDK module is now the canonical source for image fetching logic. All previously internal types (Fetcher, ImageData, option constructors) are provided by the SDK.

Key entry points after migration:

  • pkg/cel/libs/context.goNewContextProvider accepts []imagedataloader.Option and passes them to imagedataloader.New()
  • pkg/cel/libs/imageverify/utils.goGetRemoteOptsFromPolicy converts policy-level Credentials into []imagedataloader.Option via imagedataloader.BuildRemoteOpts

The Auth Gap in CEL Context Provider (Issue #15776)#

After the SDK migration, NewContextProvider in all three controller entry points (cmd/kyverno/main.go, cmd/background-controller/main.go, cmd/cleanup-controller/main.go) passed nil for the imageOpts argument :

contextProvider, err := libs.NewContextProvider(
    setup.KyvernoDynamicClient,
    nil, // <-- no credentials passed
    gcstore,
    restMapper,
    false,
)

This meant any image.GetMetadata() call in a MutatingPolicy or ValidatingPolicy variable expression would attempt registry pulls anonymously. Private registries would return 401 Unauthorized; with failurePolicy: Ignore the policy silently no-ops, and with failurePolicy: Fail it blocks admission .

The CEL-based MutatingPolicy had no per-policy credentials field (unlike ImageValidatingPolicy), so there was no policy-level workaround available either .


The Fix: Wiring CLI Flags into the CEL Context Provider (PR #16491)#

PR #16491 (filed July 2026) closes this gap by threading the existing registry CLI flags through to the CEL image loader :

1. New helper in cmd/internal/registry.go

imageLoaderOptions() calls imagedataloader.BuildRemoteOpts using the three global CLI flag variables already parsed by cmd/internal/flag.go:

  • imagePullSecrets — comma-separated Kubernetes secret names
  • registryCredentialHelpers — cloud credential helper names (e.g., ECR via IRSA)
  • allowInsecureRegistry — insecure registry flag

A companion splitAndTrim() utility normalizes the comma-separated strings.

2. ImageLoaderOptions field on SetupResult

cmd/internal/setup.go gains an ImageLoaderOptions []imagedataloader.Option field, populated during Setup() by calling imageLoaderOptions(). This distributes the options consistently to all controllers.

3. Context provider calls updated

libs.NewContextProvider(...) in all three controller mains now passes setup.ImageLoaderOptions instead of nil, ensuring the imagedataloader.Fetcher stored in contextProvider carries full registry credentials.

The authentication flow after the fix:

CLI flags (--imagePullSecrets, --registryCredentialHelpers, --allowInsecureRegistry)
  → imageLoaderOptions() [cmd/internal/registry.go]
  → SetupResult.ImageLoaderOptions [cmd/internal/setup.go]
  → libs.NewContextProvider(...) [cmd/kyverno/main.go, background-controller, cleanup-controller]
  → imagedataloader.New() [pkg/cel/libs/context.go:88]
  → contextProvider.imagedata (Fetcher)
  → image.GetMetadata() in CEL expressions

No new user-facing configuration is needed — the same flags that configure image verification already control CEL image data access after this fix .


Credential Sources Supported#

The imagedataloader.BuildRemoteOpts function (consumed by both paths) supports:

SourceCLI Flag / Config
Kubernetes image pull secrets--imagePullSecrets
Cloud credential helpers (ECR, GCR, ACR, etc.)--registryCredentialHelpers
Insecure (HTTP) registries--allowInsecureRegistry
Policy-level secrets (ImageValidatingPolicy only)credentials.secrets in policy spec, via GetRemoteOptsFromPolicy

Key Files#

FilePurpose
pkg/cel/libs/context.goNewContextProvider — accepts and stores imagedataloader.Option
pkg/cel/libs/imageverify/utils.goGetRemoteOptsFromPolicy — policy-level credentials → options
cmd/internal/registry.goimageLoaderOptions() and setupRegistryClient()
cmd/internal/setup.goSetupResult struct — shared config for all controllers
cmd/kyverno/main.goAdmission controller context provider initialization