diff --git a/cmd/cleanup-controller/controller.go b/cmd/cleanup-controller/controller.go deleted file mode 100644 index f7eb8ec57b..0000000000 --- a/cmd/cleanup-controller/controller.go +++ /dev/null @@ -1,190 +0,0 @@ -package main - -import ( - "context" - "fmt" - "time" - - "github.com/go-logr/logr" - kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" - "github.com/kyverno/kyverno/pkg/config" - "github.com/kyverno/kyverno/pkg/controllers" - "github.com/kyverno/kyverno/pkg/logging" - "github.com/kyverno/kyverno/pkg/tls" - controllerutils "github.com/kyverno/kyverno/pkg/utils/controller" - admissionregistrationv1 "k8s.io/api/admissionregistration/v1" - corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - admissionregistrationv1informers "k8s.io/client-go/informers/admissionregistration/v1" - corev1informers "k8s.io/client-go/informers/core/v1" - admissionregistrationv1listers "k8s.io/client-go/listers/admissionregistration/v1" - corev1listers "k8s.io/client-go/listers/core/v1" - "k8s.io/client-go/util/workqueue" -) - -const ( - // Workers is the number of workers for this controller - Workers = 2 - ControllerName = "webhook-controller" - maxRetries = 10 - managedByLabel = "webhook.kyverno.io/managed-by" -) - -var ( - none = admissionregistrationv1.SideEffectClassNone - fail = admissionregistrationv1.Fail -) - -var logger = logging.ControllerLogger(ControllerName) - -type controller struct { - // clients - vwcClient controllerutils.ObjectClient[*admissionregistrationv1.ValidatingWebhookConfiguration] - - // listers - vwcLister admissionregistrationv1listers.ValidatingWebhookConfigurationLister - secretLister corev1listers.SecretNamespaceLister - - // queue - queue workqueue.RateLimitingInterface - - // config - webhookName string - server string -} - -func NewController( - vwcClient controllerutils.ObjectClient[*admissionregistrationv1.ValidatingWebhookConfiguration], - vwcInformer admissionregistrationv1informers.ValidatingWebhookConfigurationInformer, - secretInformer corev1informers.SecretInformer, - webhookName string, - server string, -) controllers.Controller { - queue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), ControllerName) - c := controller{ - vwcClient: vwcClient, - vwcLister: vwcInformer.Lister(), - secretLister: secretInformer.Lister().Secrets(config.KyvernoNamespace()), - queue: queue, - webhookName: webhookName, - server: server, - } - controllerutils.AddDefaultEventHandlers(logger, vwcInformer.Informer(), queue) - controllerutils.AddEventHandlersT( - secretInformer.Informer(), - func(obj *corev1.Secret) { - if obj.GetNamespace() == config.KyvernoNamespace() && obj.GetName() == tls.GenerateRootCASecretName() { - c.enqueue() - } - }, - func(_, obj *corev1.Secret) { - if obj.GetNamespace() == config.KyvernoNamespace() && obj.GetName() == tls.GenerateRootCASecretName() { - c.enqueue() - } - }, - func(obj *corev1.Secret) { - if obj.GetNamespace() == config.KyvernoNamespace() && obj.GetName() == tls.GenerateRootCASecretName() { - c.enqueue() - } - }, - ) - return &c -} - -func (c *controller) Run(ctx context.Context, workers int) { - c.enqueue() - controllerutils.Run(ctx, logger, ControllerName, time.Second, c.queue, workers, maxRetries, c.reconcile) -} - -func (c *controller) enqueue() { - c.queue.Add(c.webhookName) -} - -func (c *controller) reconcile(ctx context.Context, logger logr.Logger, key, _, _ string) error { - if key != c.webhookName { - return nil - } - caData, err := tls.ReadRootCASecret(c.secretLister) - if err != nil { - return err - } - desired, err := c.build(caData) - if err != nil { - return err - } - observed, err := c.vwcLister.Get(desired.Name) - if err != nil { - if apierrors.IsNotFound(err) { - _, err := c.vwcClient.Create(ctx, desired, metav1.CreateOptions{}) - return err - } - return err - } - _, err = controllerutils.Update(ctx, observed, c.vwcClient, func(w *admissionregistrationv1.ValidatingWebhookConfiguration) error { - w.Labels = desired.Labels - w.OwnerReferences = desired.OwnerReferences - w.Webhooks = desired.Webhooks - return nil - }) - return err -} - -func objectMeta(name string, owner ...metav1.OwnerReference) metav1.ObjectMeta { - return metav1.ObjectMeta{ - Name: name, - Labels: map[string]string{ - managedByLabel: kyvernov1.ValueKyvernoApp, - }, - OwnerReferences: owner, - } -} - -func (c *controller) build(caBundle []byte) (*admissionregistrationv1.ValidatingWebhookConfiguration, error) { - return &admissionregistrationv1.ValidatingWebhookConfiguration{ - ObjectMeta: objectMeta(c.webhookName), - Webhooks: []admissionregistrationv1.ValidatingWebhook{{ - Name: fmt.Sprintf("%s.%s.svc", config.KyvernoServiceName(), config.KyvernoNamespace()), - ClientConfig: c.clientConfig(caBundle, validatingWebhookServicePath), - Rules: []admissionregistrationv1.RuleWithOperations{{ - Rule: admissionregistrationv1.Rule{ - APIGroups: []string{ - "kyverno.io", - }, - APIVersions: []string{ - "v2alpha1", - }, - Resources: []string{ - "cleanuppolicies/*", - "clustercleanuppolicies/*", - }, - }, - Operations: []admissionregistrationv1.OperationType{ - admissionregistrationv1.Create, - admissionregistrationv1.Update, - }, - }}, - FailurePolicy: &fail, - SideEffects: &none, - AdmissionReviewVersions: []string{"v1"}, - }}, - }, - nil -} - -func (c *controller) clientConfig(caBundle []byte, path string) admissionregistrationv1.WebhookClientConfig { - clientConfig := admissionregistrationv1.WebhookClientConfig{ - CABundle: caBundle, - } - if c.server == "" { - clientConfig.Service = &admissionregistrationv1.ServiceReference{ - Namespace: config.KyvernoNamespace(), - Name: config.KyvernoServiceName(), - Path: &path, - } - } else { - url := fmt.Sprintf("https://%s%s", c.server, path) - clientConfig.URL = &url - } - return clientConfig -} diff --git a/cmd/cleanup-controller/main.go b/cmd/cleanup-controller/main.go index 990a69739e..59913eacc6 100644 --- a/cmd/cleanup-controller/main.go +++ b/cmd/cleanup-controller/main.go @@ -18,16 +18,20 @@ import ( "github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/controllers/certmanager" "github.com/kyverno/kyverno/pkg/controllers/cleanup" + genericwebhookcontroller "github.com/kyverno/kyverno/pkg/controllers/generic/webhook" "github.com/kyverno/kyverno/pkg/leaderelection" "github.com/kyverno/kyverno/pkg/metrics" "github.com/kyverno/kyverno/pkg/tls" "github.com/kyverno/kyverno/pkg/webhooks" + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" corev1 "k8s.io/api/core/v1" kubeinformers "k8s.io/client-go/informers" ) const ( - resyncPeriod = 15 * time.Minute + resyncPeriod = 15 * time.Minute + webhookWorkers = 2 + webhookControllerName = "webhook-controller" ) // TODO: @@ -49,10 +53,12 @@ func main() { var ( leaderElectionRetryPeriod time.Duration dumpPayload bool + serverIP string ) flagset := flag.NewFlagSet("cleanup-controller", flag.ExitOnError) flagset.BoolVar(&dumpPayload, "dumpPayload", false, "Set this flag to activate/deactivate debug mode.") flagset.DurationVar(&leaderElectionRetryPeriod, "leaderElectionRetryPeriod", leaderelection.DefaultRetryPeriod, "Configure leader election retry period.") + flagset.StringVar(&serverIP, "serverIP", "", "IP address where Kyverno controller runs. Only required if out-of-cluster.") // config appConfig := internal.NewConfiguration( internal.WithProfiling(), @@ -109,15 +115,33 @@ func main() { certmanager.Workers, ) webhookController := internal.NewController( - ControllerName, - NewController( + webhookControllerName, + genericwebhookcontroller.NewController( + webhookControllerName, kubeClient.AdmissionregistrationV1().ValidatingWebhookConfigurations(), kubeInformer.Admissionregistration().V1().ValidatingWebhookConfigurations(), kubeKyvernoInformer.Core().V1().Secrets(), - "kyverno-cleanup-policies", - "", + config.CleanupValidatingWebhookConfigurationName, + config.CleanupValidatingWebhookServicePath, + serverIP, + []admissionregistrationv1.RuleWithOperations{{ + Rule: admissionregistrationv1.Rule{ + APIGroups: []string{"kyverno.io"}, + APIVersions: []string{"v2alpha1"}, + Resources: []string{ + "cleanuppolicies/*", + "clustercleanuppolicies/*", + }, + }, + Operations: []admissionregistrationv1.OperationType{ + admissionregistrationv1.Create, + admissionregistrationv1.Update, + }, + }}, + genericwebhookcontroller.Fail, + genericwebhookcontroller.None, ), - Workers, + webhookWorkers, ) cleanupController := internal.NewController( cleanup.ControllerName, diff --git a/cmd/cleanup-controller/server.go b/cmd/cleanup-controller/server.go index c98790813f..0bd6230379 100644 --- a/cmd/cleanup-controller/server.go +++ b/cmd/cleanup-controller/server.go @@ -18,11 +18,6 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" ) -const ( - // validatingWebhookServicePath is the path for validation webhook - validatingWebhookServicePath = "/validate" -) - type Server interface { // Run TLS server in separate thread and returns control immediately Run(<-chan struct{}) @@ -73,7 +68,7 @@ func NewServer( mux := httprouter.New() mux.HandlerFunc( "POST", - validatingWebhookServicePath, + config.CleanupValidatingWebhookServicePath, handlers.FromAdmissionFunc("VALIDATE", validationHandler). WithDump(debugModeOpts.DumpPayload). WithSubResourceFilter(). diff --git a/pkg/config/config.go b/pkg/config/config.go index 5961beef68..97637212a9 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -21,8 +21,10 @@ const ( PolicyValidatingWebhookConfigurationName = "kyverno-policy-validating-webhook-cfg" // ValidatingWebhookConfigurationName ... ValidatingWebhookConfigurationName = "kyverno-resource-validating-webhook-cfg" - // PolicyValidatingWebhookConfigurationName default policy validating webhook configuration name + // ExceptionValidatingWebhookConfigurationName ... ExceptionValidatingWebhookConfigurationName = "kyverno-exception-validating-webhook-cfg" + // CleanupValidatingWebhookConfigurationName ... + CleanupValidatingWebhookConfigurationName = "kyverno-cleanup-validating-webhook-cfg" // PolicyMutatingWebhookConfigurationName default policy mutating webhook configuration name PolicyMutatingWebhookConfigurationName = "kyverno-policy-mutating-webhook-cfg" // MutatingWebhookConfigurationName default resource mutating webhook configuration name @@ -53,6 +55,8 @@ const ( ValidatingWebhookServicePath = "/validate" // ExceptionValidatingWebhookServicePath is the path for policy exception validation webhook(used to validate policy exception resource) ExceptionValidatingWebhookServicePath = "/exceptionvalidate" + // CleanupValidatingWebhookServicePath is the path for cleanup policy validation webhook(used to validate cleanup policy resource) + CleanupValidatingWebhookServicePath = "/validate" // PolicyMutatingWebhookServicePath is the path for policy mutation webhook(used to default) PolicyMutatingWebhookServicePath = "/policymutate" // MutatingWebhookServicePath is the path for mutation webhook