mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-28 10:28:36 +00:00
refactor: cleanup controller validating webhook (#5756)
Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
0f5a0d492f
commit
3c997d88a8
4 changed files with 36 additions and 203 deletions
|
@ -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
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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().
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue