diff --git a/pkg/controlplane/components/kyverno_component.go b/pkg/controlplane/components/kyverno_component.go index 52544df..6b3fd5c 100644 --- a/pkg/controlplane/components/kyverno_component.go +++ b/pkg/controlplane/components/kyverno_component.go @@ -2,11 +2,15 @@ package components import ( "context" + "encoding/json" + "fmt" + "os" "strings" helmv2 "github.com/fluxcd/helm-controller/api/v2" sourcev1 "github.com/fluxcd/source-controller/api/v1" rbacv1 "k8s.io/api/rbac/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" @@ -21,6 +25,8 @@ const ( kyvernoRelease = "kyverno" kyvernoNamespace = "kyverno-system" ComponentNameKyverno = "Kyverno" + + EnvEnableKyvernoDefaultValues = "ENABLE_KYVERNO_DEFAULT_VALUES" ) var _ fluxcd.FluxComponent = &Kyverno{} @@ -173,6 +179,17 @@ func (k *Kyverno) applyDefaultChartSpec(rfn v1beta1.VersionResolverFn) { } func (k *Kyverno) BuildManifesto(ctx context.Context) (fluxcd.Manifesto, error) { + values := k.Config.Values + + // If default values are enabled, use them instead + if os.Getenv(EnvEnableKyvernoDefaultValues) == "true" { + defaultValues, err := k.getDefaultValues() + if err != nil { + return nil, fmt.Errorf("failed to get default Kyverno values: %w", err) + } + values = defaultValues + } + release := &helmv2.HelmRelease{ ObjectMeta: metav1.ObjectMeta{ Name: strings.ToLower(ComponentNameKyverno), @@ -193,7 +210,7 @@ func (k *Kyverno) BuildManifesto(ctx context.Context) (fluxcd.Manifesto, error) TargetNamespace: kyvernoNamespace, StorageNamespace: kyvernoNamespace, KubeConfig: rcontext.FluxKubeconfigRef(ctx), - Values: k.Config.Values, + Values: values, }, } @@ -201,3 +218,47 @@ func (k *Kyverno) BuildManifesto(ctx context.Context) (fluxcd.Manifesto, error) adapter.ApplyDefaults() return adapter, nil } + +func (k *Kyverno) getDefaultValues() (*apiextensionsv1.JSON, error) { + defaults := map[string]interface{}{ + "config": map[string]interface{}{ + "preserve": false, + "resourceFilters": []string{ + "[*/*,kyverno,*]", + "[*/*,istio-system,*]", + "[*/*,kyma-system,*]", + "[*/*,kube-system,*]", + "[*/*,kube-public,*]", + "[*/*,neo-core,*]", + }, + "updateRequestThreshold": 5000, + "excludeGroups": []string{ + "system:nodes", + }, + "webhooks": map[string]interface{}{ + "namespaceSelector": map[string]interface{}{ + "matchExpressions": []map[string]interface{}{ + { + "key": "kubernetes.io/metadata.name", + "operator": "NotIn", + "values": []string{ + "kube-system", + "kyverno", + "istio-system", + "kube-public", + "kyma-system", + "neo-core", + }, + }, + }, + }, + }, + }, + } + + raw, err := json.Marshal(defaults) + if err != nil { + return nil, fmt.Errorf("failed to marshal default values: %w", err) + } + return &apiextensionsv1.JSON{Raw: raw}, nil +} diff --git a/pkg/controlplane/components/kyverno_component_test.go b/pkg/controlplane/components/kyverno_component_test.go index 90c82ca..d54c5d4 100644 --- a/pkg/controlplane/components/kyverno_component_test.go +++ b/pkg/controlplane/components/kyverno_component_test.go @@ -13,6 +13,7 @@ func Test_Kyverno(t *testing.T) { testCases := []struct { desc string config *v1beta1.KyvernoConfig + enableDefaults bool versionResolver v1beta1.VersionResolverFn validationFuncs []validationFunc }{ @@ -63,10 +64,70 @@ func Test_Kyverno(t *testing.T) { ), }, }, + { + desc: "should use default values instad of values from config when enabled via env", + enableDefaults: true, + config: &v1beta1.KyvernoConfig{ + Version: "1.2.3", + Values: &apiextensionsv1.JSON{Raw: []byte(`{"crds":{"install":true}}`)}, + }, + versionResolver: fakeVersionResolver(false), + validationFuncs: []validationFunc{ + hasName("Kyverno"), + isEnabled(true), + isAllowed(true), + hasPreUninstallHook(), + hasDependencies(0), + isTargetComponent( + hasNamespace("kyverno-system"), + ), + isFluxComponent( + returnsHelmRepo(), + returnsHelmRelease( + hasKubeconfigRef(), + hasHelmValue(false, "config", "preserve"), + hasHelmValue([]interface{}{ + "[*/*,kyverno,*]", + "[*/*,istio-system,*]", + "[*/*,kyma-system,*]", + "[*/*,kube-system,*]", + "[*/*,kube-public,*]", + "[*/*,neo-core,*]", + }, "config", "resourceFilters"), + hasHelmValue(5000, "config", "updateRequestThreshold"), + hasHelmValue([]interface{}{ + "system:nodes", + }, "config", "excludeGroups"), + hasHelmValue(map[string]interface{}{ + "matchExpressions": []interface{}{ + map[string]interface{}{ + "key": "kubernetes.io/metadata.name", + "operator": "NotIn", + "values": []interface{}{ + "kube-system", + "kyverno", + "istio-system", + "kube-public", + "kyma-system", + "neo-core", + }, + }, + }, + }, "config", "webhooks", "namespaceSelector"), + ), + ), + isPolicyRulesComponent( + hasPolicyRules(), + ), + }, + }, } for _, tC := range testCases { t.Run(tC.desc, func(t *testing.T) { ctx := newContext(nil, tC.versionResolver) + if tC.enableDefaults { + t.Setenv(EnvEnableKyvernoDefaultValues, "true") + } c := &Kyverno{Config: tC.config} for _, vfn := range tC.validationFuncs { vfn(t, ctx, c)