diff --git a/charts/kyverno/README.md b/charts/kyverno/README.md index 16d9c145c4..b1d56402f0 100644 --- a/charts/kyverno/README.md +++ b/charts/kyverno/README.md @@ -335,6 +335,7 @@ The chart values are organised per component. | features.forceFailurePolicyIgnore.enabled | bool | `false` | Enables the feature | | features.generateValidatingAdmissionPolicy.enabled | bool | `false` | Enables the feature | | features.globalContext.enabled | bool | `true` | Enables the feature | +| features.globalContext.maxApiCallResponseLength | int | `2000000` | Maximum allowed response size from API Calls. A value of 0 bypasses checks (not recommended) | | features.logging.format | string | `"text"` | Logging format | | features.logging.verbosity | int | `2` | Logging verbosity | | features.omitEvents.eventTypes | list | `["PolicyApplied","PolicySkipped"]` | Events which should not be emitted (possible values `PolicyViolation`, `PolicyApplied`, `PolicyError`, and `PolicySkipped`) | diff --git a/charts/kyverno/templates/_helpers.tpl b/charts/kyverno/templates/_helpers.tpl index b3a440c3a9..5c4d04de47 100644 --- a/charts/kyverno/templates/_helpers.tpl +++ b/charts/kyverno/templates/_helpers.tpl @@ -48,6 +48,7 @@ {{- end -}} {{- with .globalContext -}} {{- $flags = append $flags (print "--enableGlobalContext=" .enabled) -}} + {{- $flags = append $flags (print "--maxAPICallResponseLength=" (int .maxApiCallResponseLength)) -}} {{- end -}} {{- with .logging -}} {{- $flags = append $flags (print "--loggingFormat=" .format) -}} diff --git a/charts/kyverno/values.yaml b/charts/kyverno/values.yaml index b79e3326c5..3a459ef6d7 100644 --- a/charts/kyverno/values.yaml +++ b/charts/kyverno/values.yaml @@ -632,6 +632,8 @@ features: globalContext: # -- Enables the feature enabled: true + # -- Maximum allowed response size from API Calls. A value of 0 bypasses checks (not recommended) + maxApiCallResponseLength: 2000000 logging: # -- Logging format format: text diff --git a/cmd/background-controller/main.go b/cmd/background-controller/main.go index 010f4af64d..7a7819550a 100644 --- a/cmd/background-controller/main.go +++ b/cmd/background-controller/main.go @@ -161,6 +161,7 @@ func main() { kyvernoInformer.Kyverno().V2alpha1().GlobalContextEntries(), setup.KyvernoDynamicClient, store.New(), + maxAPICallResponseLength, ), globalcontextcontroller.Workers, ) // this controller only subscribe to events, nothing is returned... diff --git a/cmd/cleanup-controller/main.go b/cmd/cleanup-controller/main.go index 3a20f735e0..3649ead3b6 100644 --- a/cmd/cleanup-controller/main.go +++ b/cmd/cleanup-controller/main.go @@ -70,13 +70,14 @@ func sanityChecks(apiserverClient apiserver.Interface) error { func main() { var ( - dumpPayload bool - serverIP string - servicePort int - webhookServerPort int - maxQueuedEvents int - interval time.Duration - renewBefore time.Duration + dumpPayload bool + serverIP string + servicePort int + webhookServerPort int + maxQueuedEvents int + interval time.Duration + renewBefore time.Duration + maxAPICallResponseLength int64 ) flagset := flag.NewFlagSet("cleanup-controller", flag.ExitOnError) flagset.BoolVar(&dumpPayload, "dumpPayload", false, "Set this flag to activate/deactivate debug mode.") @@ -89,6 +90,7 @@ func main() { flagset.StringVar(&caSecretName, "caSecretName", "", "Name of the secret containing CA.") flagset.StringVar(&tlsSecretName, "tlsSecretName", "", "Name of the secret containing TLS pair.") flagset.DurationVar(&renewBefore, "renewBefore", 15*24*time.Hour, "The certificate renewal time before expiration") + flagset.Int64Var(&maxAPICallResponseLength, "maxAPICallResponseLength", 2*1000*1000, "Maximum allowed response size from API Calls. A value of 0 bypasses checks (not recommended).") // config appConfig := internal.NewConfiguration( internal.WithProfiling(), @@ -165,6 +167,7 @@ func main() { kyvernoInformer.Kyverno().V2alpha1().GlobalContextEntries(), setup.KyvernoDynamicClient, store.New(), + maxAPICallResponseLength, ), globalcontextcontroller.Workers, ) diff --git a/cmd/kyverno/main.go b/cmd/kyverno/main.go index b964fdcd5e..63b4c10058 100644 --- a/cmd/kyverno/main.go +++ b/cmd/kyverno/main.go @@ -331,6 +331,7 @@ func main() { kyvernoInformer.Kyverno().V2alpha1().GlobalContextEntries(), setup.KyvernoDynamicClient, store.New(), + maxAPICallResponseLength, ), globalcontextcontroller.Workers, ) diff --git a/cmd/reports-controller/main.go b/cmd/reports-controller/main.go index 06c6ee7c6d..ce7ad14eb2 100644 --- a/cmd/reports-controller/main.go +++ b/cmd/reports-controller/main.go @@ -291,6 +291,7 @@ func main() { kyvernoInformer.Kyverno().V2alpha1().GlobalContextEntries(), setup.KyvernoDynamicClient, store.New(), + maxAPICallResponseLength, ), globalcontextcontroller.Workers, ) diff --git a/config/install-latest-testing.yaml b/config/install-latest-testing.yaml index 264af4f4d3..b6557c2e97 100644 --- a/config/install-latest-testing.yaml +++ b/config/install-latest-testing.yaml @@ -51837,6 +51837,7 @@ spec: - --forceFailurePolicyIgnore=false - --generateValidatingAdmissionPolicy=false - --enableGlobalContext=true + - --maxAPICallResponseLength=2000000 - --loggingFormat=text - --v=2 - --omitEvents=PolicyApplied,PolicySkipped @@ -51989,6 +51990,7 @@ spec: - --enableConfigMapCaching=true - --enableDeferredLoading=true - --enableGlobalContext=true + - --maxAPICallResponseLength=2000000 - --loggingFormat=text - --v=2 - --omitEvents=PolicyApplied,PolicySkipped @@ -52097,6 +52099,7 @@ spec: - --enableDeferredLoading=true - --dumpPayload=false - --enableGlobalContext=true + - --maxAPICallResponseLength=2000000 - --loggingFormat=text - --v=2 - --protectManagedResources=false @@ -52238,6 +52241,7 @@ spec: - --enableConfigMapCaching=true - --enableDeferredLoading=true - --enableGlobalContext=true + - --maxAPICallResponseLength=2000000 - --loggingFormat=text - --v=2 - --omitEvents=PolicyApplied,PolicySkipped diff --git a/pkg/controllers/globalcontext/controller.go b/pkg/controllers/globalcontext/controller.go index 8ec5edeebe..b376294201 100644 --- a/pkg/controllers/globalcontext/controller.go +++ b/pkg/controllers/globalcontext/controller.go @@ -35,14 +35,16 @@ type controller struct { queue workqueue.RateLimitingInterface // state - dclient dclient.Interface - store store.Store + dclient dclient.Interface + store store.Store + maxResponseLength int64 } func NewController( gceInformer kyvernov2alpha1informers.GlobalContextEntryInformer, dclient dclient.Interface, storage store.Store, + maxResponseLength int64, ) controllers.Controller { queue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), ControllerName) _, _, err := controllerutils.AddDefaultEventHandlers(logger, gceInformer.Informer(), queue) @@ -50,10 +52,11 @@ func NewController( logger.Error(err, "failed to register event handlers") } return &controller{ - gceLister: gceInformer.Lister(), - queue: queue, - dclient: dclient, - store: storage, + gceLister: gceInformer.Lister(), + queue: queue, + dclient: dclient, + store: storage, + maxResponseLength: maxResponseLength, } } @@ -98,5 +101,12 @@ func (c *controller) makeStoreEntry(ctx context.Context, gce *kyvernov2alpha1.Gl } return k8sresource.New(ctx, c.dclient.GetDynamicInterface(), gvr, gce.Spec.KubernetesResource.Namespace) } - return externalapi.New(ctx, logger, adapters.Client(c.dclient), gce.Spec.APICall.APICall, gce.Spec.APICall.RefreshInterval.Duration) + return externalapi.New( + ctx, + logger, + adapters.Client(c.dclient), + gce.Spec.APICall.APICall, + gce.Spec.APICall.RefreshInterval.Duration, + c.maxResponseLength, + ) } diff --git a/pkg/globalcontext/externalapi/entry.go b/pkg/globalcontext/externalapi/entry.go index 57c464ff14..8e3098ac9b 100644 --- a/pkg/globalcontext/externalapi/entry.go +++ b/pkg/globalcontext/externalapi/entry.go @@ -17,7 +17,14 @@ type entry struct { stop func() } -func New(ctx context.Context, logger logr.Logger, client apicall.ClientInterface, call kyvernov1.APICall, period time.Duration) (*entry, error) { +func New( + ctx context.Context, + logger logr.Logger, + client apicall.ClientInterface, + call kyvernov1.APICall, + period time.Duration, + maxResponseLength int64, +) (*entry, error) { var group wait.Group ctx, cancel := context.WithCancel(ctx) stop := func() { @@ -31,11 +38,9 @@ func New(ctx context.Context, logger logr.Logger, client apicall.ClientInterface } group.StartWithContext(ctx, func(ctx context.Context) { // TODO: make sure we have called it at least once before returning - // TODO: config - config := apicall.NewAPICallConfiguration(10000) + config := apicall.NewAPICallConfiguration(maxResponseLength) caller := apicall.NewCaller(logger, "TODO", client, config) wait.UntilWithContext(ctx, func(ctx context.Context) { - // TODO if data, err := doCall(ctx, caller, call); err != nil { logger.Error(err, "failed to get data from api caller") } else {