mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-28 10:28:36 +00:00
register webhookconfigurations when policy first applied
This commit is contained in:
parent
a4217de1a2
commit
6c12a76ab2
7 changed files with 141 additions and 94 deletions
23
main.go
23
main.go
|
@ -45,6 +45,16 @@ func main() {
|
|||
if err != nil {
|
||||
glog.Fatalf("Error creating policy sharedinformer: %v\n", err)
|
||||
}
|
||||
|
||||
webhookRegistrationClient, err := webhooks.NewWebhookRegistrationClient(clientConfig, client, serverIP, int32(webhookTimeout))
|
||||
if err != nil {
|
||||
glog.Fatalf("Unable to register admission webhooks on cluster: %v\n", err)
|
||||
}
|
||||
|
||||
if err = webhookRegistrationClient.Register(); err != nil {
|
||||
glog.Fatalf("Failed registering Admission Webhooks: %v\n", err)
|
||||
}
|
||||
|
||||
kubeInformer := utils.NewKubeInformerFactory(clientConfig)
|
||||
eventController := event.NewEventController(client, policyInformerFactory)
|
||||
violationBuilder := violation.NewPolicyViolationBuilder(client, policyInformerFactory, eventController)
|
||||
|
@ -54,7 +64,6 @@ func main() {
|
|||
policyInformerFactory,
|
||||
violationBuilder,
|
||||
eventController,
|
||||
annotationsController,
|
||||
filterK8Resources)
|
||||
|
||||
genControler := gencontroller.NewGenController(client, eventController, policyInformerFactory, violationBuilder, kubeInformer.Core().V1().Namespaces(), annotationsController)
|
||||
|
@ -62,22 +71,14 @@ func main() {
|
|||
if err != nil {
|
||||
glog.Fatalf("Failed to initialize TLS key/certificate pair: %v\n", err)
|
||||
}
|
||||
server, err := webhooks.NewWebhookServer(client, tlsPair, policyInformerFactory, eventController, violationBuilder, annotationsController, filterK8Resources)
|
||||
|
||||
server, err := webhooks.NewWebhookServer(client, tlsPair, policyInformerFactory, eventController, violationBuilder, annotationsController, webhookRegistrationClient, filterK8Resources)
|
||||
if err != nil {
|
||||
glog.Fatalf("Unable to create webhook server: %v\n", err)
|
||||
}
|
||||
|
||||
webhookRegistrationClient, err := webhooks.NewWebhookRegistrationClient(clientConfig, client, serverIP, int32(webhookTimeout))
|
||||
if err != nil {
|
||||
glog.Fatalf("Unable to register admission webhooks on cluster: %v\n", err)
|
||||
}
|
||||
|
||||
stopCh := signals.SetupSignalHandler()
|
||||
|
||||
if err = webhookRegistrationClient.Register(); err != nil {
|
||||
glog.Fatalf("Failed registering Admission Webhooks: %v\n", err)
|
||||
}
|
||||
|
||||
policyInformerFactory.Run(stopCh)
|
||||
kubeInformer.Start(stopCh)
|
||||
eventController.Run(stopCh)
|
||||
|
|
|
@ -30,14 +30,13 @@ import (
|
|||
|
||||
//PolicyController to manage Policy CRD
|
||||
type PolicyController struct {
|
||||
client *client.Client
|
||||
policyLister lister.PolicyLister
|
||||
policySynced cache.InformerSynced
|
||||
violationBuilder violation.Generator
|
||||
eventController event.Generator
|
||||
annotationsController annotations.Controller
|
||||
queue workqueue.RateLimitingInterface
|
||||
filterK8Resources []utils.K8Resource
|
||||
client *client.Client
|
||||
policyLister lister.PolicyLister
|
||||
policySynced cache.InformerSynced
|
||||
violationBuilder violation.Generator
|
||||
eventController event.Generator
|
||||
queue workqueue.RateLimitingInterface
|
||||
filterK8Resources []utils.K8Resource
|
||||
}
|
||||
|
||||
// NewPolicyController from cmd args
|
||||
|
@ -45,18 +44,16 @@ func NewPolicyController(client *client.Client,
|
|||
policyInformer sharedinformer.PolicyInformer,
|
||||
violationBuilder violation.Generator,
|
||||
eventController event.Generator,
|
||||
annotationsController annotations.Controller,
|
||||
filterK8Resources string) *PolicyController {
|
||||
|
||||
controller := &PolicyController{
|
||||
client: client,
|
||||
policyLister: policyInformer.GetLister(),
|
||||
policySynced: policyInformer.GetInfomer().HasSynced,
|
||||
violationBuilder: violationBuilder,
|
||||
eventController: eventController,
|
||||
annotationsController: annotationsController,
|
||||
filterK8Resources: utils.ParseKinds(filterK8Resources),
|
||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), policyWorkQueueName),
|
||||
client: client,
|
||||
policyLister: policyInformer.GetLister(),
|
||||
policySynced: policyInformer.GetInfomer().HasSynced,
|
||||
violationBuilder: violationBuilder,
|
||||
eventController: eventController,
|
||||
filterK8Resources: utils.ParseKinds(filterK8Resources),
|
||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), policyWorkQueueName),
|
||||
}
|
||||
|
||||
policyInformer.GetInfomer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
|
|
|
@ -42,7 +42,6 @@ func (f *fixture) runControler(policyName string) {
|
|||
policyInformerFactory,
|
||||
violationBuilder,
|
||||
eventController,
|
||||
nil,
|
||||
"")
|
||||
|
||||
stopCh := signals.SetupSignalHandler()
|
||||
|
|
|
@ -13,16 +13,21 @@ import (
|
|||
|
||||
//HandlePolicyValidation performs the validation check on policy resource
|
||||
func (ws *WebhookServer) HandlePolicyValidation(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse {
|
||||
return ws.validateUniqueRuleName(request.Object.Raw)
|
||||
var policy *policyv1.Policy
|
||||
json.Unmarshal(request.Object.Raw, &policy)
|
||||
|
||||
admissionResp := ws.validateUniqueRuleName(policy)
|
||||
|
||||
if admissionResp.Allowed {
|
||||
ws.registerWebhookConfigurations(*policy)
|
||||
}
|
||||
return admissionResp
|
||||
}
|
||||
|
||||
// Verify if the Rule names are unique within a policy
|
||||
func (ws *WebhookServer) validateUniqueRuleName(rawPolicy []byte) *v1beta1.AdmissionResponse {
|
||||
var policy *policyv1.Policy
|
||||
func (ws *WebhookServer) validateUniqueRuleName(policy *policyv1.Policy) *v1beta1.AdmissionResponse {
|
||||
var ruleNames []string
|
||||
|
||||
json.Unmarshal(rawPolicy, &policy)
|
||||
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
if utils.Contains(ruleNames, rule.Name) {
|
||||
msg := fmt.Sprintf(`The policy "%s" is invalid: duplicate rule name: "%s"`, policy.Name, rule.Name)
|
||||
|
|
|
@ -9,10 +9,9 @@ import (
|
|||
"github.com/golang/glog"
|
||||
"github.com/nirmata/kyverno/pkg/config"
|
||||
client "github.com/nirmata/kyverno/pkg/dclient"
|
||||
|
||||
"github.com/tevino/abool"
|
||||
admregapi "k8s.io/api/admissionregistration/v1beta1"
|
||||
errorsapi "k8s.io/apimachinery/pkg/api/errors"
|
||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
admregclient "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
@ -23,8 +22,10 @@ type WebhookRegistrationClient struct {
|
|||
client *client.Client
|
||||
clientConfig *rest.Config
|
||||
// serverIP should be used if running Kyverno out of clutser
|
||||
serverIP string
|
||||
timeoutSeconds int32
|
||||
serverIP string
|
||||
timeoutSeconds int32
|
||||
MutationRegistered *abool.AtomicBool
|
||||
ValidationRegistered *abool.AtomicBool
|
||||
}
|
||||
|
||||
// NewWebhookRegistrationClient creates new WebhookRegistrationClient instance
|
||||
|
@ -37,11 +38,13 @@ func NewWebhookRegistrationClient(clientConfig *rest.Config, client *client.Clie
|
|||
glog.V(3).Infof("Registering webhook client using serverIP %s\n", serverIP)
|
||||
|
||||
return &WebhookRegistrationClient{
|
||||
registrationClient: registrationClient,
|
||||
client: client,
|
||||
clientConfig: clientConfig,
|
||||
serverIP: serverIP,
|
||||
timeoutSeconds: webhookTimeout,
|
||||
registrationClient: registrationClient,
|
||||
client: client,
|
||||
clientConfig: clientConfig,
|
||||
serverIP: serverIP,
|
||||
timeoutSeconds: webhookTimeout,
|
||||
MutationRegistered: abool.New(),
|
||||
ValidationRegistered: abool.New(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -50,39 +53,51 @@ func (wrc *WebhookRegistrationClient) Register() error {
|
|||
if wrc.serverIP != "" {
|
||||
glog.Infof("Registering webhook with url https://%s\n", wrc.serverIP)
|
||||
}
|
||||
|
||||
// For the case if cluster already has this configs
|
||||
wrc.Deregister()
|
||||
|
||||
// register policy validating webhook during inital start
|
||||
return wrc.RegisterPolicyValidatingWebhook()
|
||||
}
|
||||
|
||||
func (wrc *WebhookRegistrationClient) RegisterMutatingWebhook() error {
|
||||
mutatingWebhookConfig, err := wrc.constructMutatingWebhookConfig(wrc.clientConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = wrc.registrationClient.MutatingWebhookConfigurations().Create(mutatingWebhookConfig)
|
||||
if err != nil {
|
||||
if _, err = wrc.registrationClient.MutatingWebhookConfigurations().Create(mutatingWebhookConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (wrc *WebhookRegistrationClient) RegisterValidatingWebhook() error {
|
||||
validationWebhookConfig, err := wrc.constructValidatingWebhookConfig(wrc.clientConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = wrc.registrationClient.ValidatingWebhookConfigurations().Create(validationWebhookConfig)
|
||||
if err != nil {
|
||||
if _, err = wrc.registrationClient.ValidatingWebhookConfigurations().Create(validationWebhookConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (wrc *WebhookRegistrationClient) RegisterPolicyValidatingWebhook() error {
|
||||
policyValidationWebhookConfig, err := wrc.contructPolicyValidatingWebhookConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = wrc.registrationClient.ValidatingWebhookConfigurations().Create(policyValidationWebhookConfig)
|
||||
if err != nil {
|
||||
if _, err = wrc.registrationClient.ValidatingWebhookConfigurations().Create(policyValidationWebhookConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
glog.V(3).Infoln("Policy validating webhook registered")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -90,28 +105,25 @@ func (wrc *WebhookRegistrationClient) Register() error {
|
|||
// This function does not fail on error:
|
||||
// Register will fail if the config exists, so there is no need to fail on error
|
||||
func (wrc *WebhookRegistrationClient) Deregister() {
|
||||
if wrc.serverIP != "" {
|
||||
if err := wrc.registrationClient.MutatingWebhookConfigurations().Delete(config.MutatingWebhookConfigurationDebug, &meta.DeleteOptions{}); err != nil {
|
||||
if !errorsapi.IsNotFound(err) {
|
||||
glog.Errorf("Failed to deregister debug mutatingWebhookConfiguratinos, err: %v\n", err)
|
||||
}
|
||||
listOpt := v1.ListOptions{LabelSelector: "app=kyverno"}
|
||||
|
||||
// cleanup MutatingWebhookConfigurations
|
||||
mutatingWebhookConfigList, _ := wrc.registrationClient.MutatingWebhookConfigurations().List(listOpt)
|
||||
|
||||
for _, mwc := range mutatingWebhookConfigList.Items {
|
||||
if err := wrc.registrationClient.MutatingWebhookConfigurations().Delete(mwc.ObjectMeta.Name, &v1.DeleteOptions{}); err != nil {
|
||||
glog.Errorf("Failed to delete mutatingWebhookConfiguration, %s, err: %v\n", mwc.ObjectMeta.Name, err)
|
||||
}
|
||||
if err := wrc.registrationClient.ValidatingWebhookConfigurations().Delete(config.ValidatingWebhookConfigurationDebug, &meta.DeleteOptions{}); err != nil {
|
||||
if !errorsapi.IsNotFound(err) {
|
||||
glog.Errorf("Failed to deregister debug validatingWebhookConfiguratinos, err: %v\n", err)
|
||||
}
|
||||
}
|
||||
if err := wrc.registrationClient.ValidatingWebhookConfigurations().Delete(config.PolicyValidatingWebhookConfigurationDebug, &meta.DeleteOptions{}); err != nil {
|
||||
if !errorsapi.IsNotFound(err) {
|
||||
glog.Errorf("Failed to deregister debug policyValidatingWebhookConfiguratinos, err: %v\n", err)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
wrc.registrationClient.MutatingWebhookConfigurations().Delete(config.MutatingWebhookConfigurationName, &meta.DeleteOptions{})
|
||||
wrc.registrationClient.ValidatingWebhookConfigurations().Delete(config.ValidatingWebhookConfigurationName, &meta.DeleteOptions{})
|
||||
wrc.registrationClient.ValidatingWebhookConfigurations().Delete(config.PolicyValidatingWebhookConfigurationName, &meta.DeleteOptions{})
|
||||
// cleanup validatingWebhookConfiguratinos
|
||||
validatingWebhookConfigList, _ := wrc.registrationClient.ValidatingWebhookConfigurations().List(listOpt)
|
||||
|
||||
for _, mwc := range validatingWebhookConfigList.Items {
|
||||
if err := wrc.registrationClient.ValidatingWebhookConfigurations().Delete(mwc.ObjectMeta.Name, &v1.DeleteOptions{}); err != nil {
|
||||
glog.Errorf("Failed to delete validatingWebhookConfiguration, %s, err: %v\n", mwc.ObjectMeta.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wrc *WebhookRegistrationClient) constructMutatingWebhookConfig(configuration *rest.Config) (*admregapi.MutatingWebhookConfiguration, error) {
|
||||
|
@ -132,10 +144,10 @@ func (wrc *WebhookRegistrationClient) constructMutatingWebhookConfig(configurati
|
|||
}
|
||||
|
||||
return &admregapi.MutatingWebhookConfiguration{
|
||||
ObjectMeta: meta.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: config.MutatingWebhookConfigurationName,
|
||||
Labels: config.KubePolicyAppLabels,
|
||||
OwnerReferences: []meta.OwnerReference{
|
||||
OwnerReferences: []v1.OwnerReference{
|
||||
wrc.constructOwner(),
|
||||
},
|
||||
},
|
||||
|
@ -156,7 +168,7 @@ func (wrc *WebhookRegistrationClient) contructDebugMutatingWebhookConfig(caData
|
|||
glog.V(3).Infof("Debug MutatingWebhookConfig is registered with url %s\n", url)
|
||||
|
||||
return &admregapi.MutatingWebhookConfiguration{
|
||||
ObjectMeta: meta.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: config.MutatingWebhookConfigurationDebug,
|
||||
Labels: config.KubePolicyAppLabels,
|
||||
},
|
||||
|
@ -188,10 +200,10 @@ func (wrc *WebhookRegistrationClient) constructValidatingWebhookConfig(configura
|
|||
}
|
||||
|
||||
return &admregapi.ValidatingWebhookConfiguration{
|
||||
ObjectMeta: meta.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: config.ValidatingWebhookConfigurationName,
|
||||
Labels: config.KubePolicyAppLabels,
|
||||
OwnerReferences: []meta.OwnerReference{
|
||||
OwnerReferences: []v1.OwnerReference{
|
||||
wrc.constructOwner(),
|
||||
},
|
||||
},
|
||||
|
@ -211,7 +223,7 @@ func (wrc *WebhookRegistrationClient) contructDebugValidatingWebhookConfig(caDat
|
|||
glog.V(3).Infof("Debug ValidatingWebhookConfig is registered with url %s\n", url)
|
||||
|
||||
return &admregapi.ValidatingWebhookConfiguration{
|
||||
ObjectMeta: meta.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: config.ValidatingWebhookConfigurationDebug,
|
||||
Labels: config.KubePolicyAppLabels,
|
||||
},
|
||||
|
@ -243,10 +255,10 @@ func (wrc *WebhookRegistrationClient) contructPolicyValidatingWebhookConfig() (*
|
|||
}
|
||||
|
||||
return &admregapi.ValidatingWebhookConfiguration{
|
||||
ObjectMeta: meta.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: config.PolicyValidatingWebhookConfigurationName,
|
||||
Labels: config.KubePolicyAppLabels,
|
||||
OwnerReferences: []meta.OwnerReference{
|
||||
OwnerReferences: []v1.OwnerReference{
|
||||
wrc.constructOwner(),
|
||||
},
|
||||
},
|
||||
|
@ -266,7 +278,7 @@ func (wrc *WebhookRegistrationClient) contructDebugPolicyValidatingWebhookConfig
|
|||
glog.V(3).Infof("Debug PolicyValidatingWebhookConfig is registered with url %s\n", url)
|
||||
|
||||
return &admregapi.ValidatingWebhookConfiguration{
|
||||
ObjectMeta: meta.ObjectMeta{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: config.PolicyValidatingWebhookConfigurationDebug,
|
||||
Labels: config.KubePolicyAppLabels,
|
||||
},
|
||||
|
@ -375,15 +387,15 @@ func constructDebugWebhook(name, url string, caData []byte, validation bool, tim
|
|||
}
|
||||
}
|
||||
|
||||
func (wrc *WebhookRegistrationClient) constructOwner() meta.OwnerReference {
|
||||
func (wrc *WebhookRegistrationClient) constructOwner() v1.OwnerReference {
|
||||
kubePolicyDeployment, err := wrc.client.GetKubePolicyDeployment()
|
||||
|
||||
if err != nil {
|
||||
glog.Errorf("Error when constructing OwnerReference, err: %v\n", err)
|
||||
return meta.OwnerReference{}
|
||||
return v1.OwnerReference{}
|
||||
}
|
||||
|
||||
return meta.OwnerReference{
|
||||
return v1.OwnerReference{
|
||||
APIVersion: config.DeploymentAPIVersion,
|
||||
Kind: config.DeploymentKind,
|
||||
Name: kubePolicyDeployment.ObjectMeta.Name,
|
||||
|
|
|
@ -26,13 +26,14 @@ import (
|
|||
// WebhookServer contains configured TLS server with MutationWebhook.
|
||||
// MutationWebhook gets policies from policyController and takes control of the cluster with kubeclient.
|
||||
type WebhookServer struct {
|
||||
server http.Server
|
||||
client *client.Client
|
||||
policyLister v1alpha1.PolicyLister
|
||||
eventController event.Generator
|
||||
violationBuilder violation.Generator
|
||||
annotationsController annotations.Controller
|
||||
filterK8Resources []utils.K8Resource
|
||||
server http.Server
|
||||
client *client.Client
|
||||
policyLister v1alpha1.PolicyLister
|
||||
eventController event.Generator
|
||||
violationBuilder violation.Generator
|
||||
annotationsController annotations.Controller
|
||||
webhookRegistrationClient *WebhookRegistrationClient
|
||||
filterK8Resources []utils.K8Resource
|
||||
}
|
||||
|
||||
// NewWebhookServer creates new instance of WebhookServer accordingly to given configuration
|
||||
|
@ -44,6 +45,7 @@ func NewWebhookServer(
|
|||
eventController event.Generator,
|
||||
violationBuilder violation.Generator,
|
||||
annotationsController annotations.Controller,
|
||||
webhookRegistrationClient *WebhookRegistrationClient,
|
||||
filterK8Resources string) (*WebhookServer, error) {
|
||||
|
||||
if tlsPair == nil {
|
||||
|
@ -58,12 +60,13 @@ func NewWebhookServer(
|
|||
tlsConfig.Certificates = []tls.Certificate{pair}
|
||||
|
||||
ws := &WebhookServer{
|
||||
client: client,
|
||||
policyLister: shareInformer.GetLister(),
|
||||
eventController: eventController,
|
||||
violationBuilder: violationBuilder,
|
||||
annotationsController: annotationsController,
|
||||
filterK8Resources: utils.ParseKinds(filterK8Resources),
|
||||
client: client,
|
||||
policyLister: shareInformer.GetLister(),
|
||||
eventController: eventController,
|
||||
violationBuilder: violationBuilder,
|
||||
annotationsController: annotationsController,
|
||||
webhookRegistrationClient: webhookRegistrationClient,
|
||||
filterK8Resources: utils.ParseKinds(filterK8Resources),
|
||||
}
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc(config.MutatingWebhookServicePath, ws.serve)
|
||||
|
|
30
pkg/webhooks/webhookManager.go
Normal file
30
pkg/webhooks/webhookManager.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package webhooks
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
v1alpha1 "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
|
||||
)
|
||||
|
||||
func (ws *WebhookServer) registerWebhookConfigurations(policy v1alpha1.Policy) error {
|
||||
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
if rule.Mutation != nil && !ws.webhookRegistrationClient.MutationRegistered.IsSet() {
|
||||
if err := ws.webhookRegistrationClient.RegisterMutatingWebhook(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ws.webhookRegistrationClient.MutationRegistered.Set()
|
||||
glog.Infof("Mutating webhook registered")
|
||||
}
|
||||
|
||||
if rule.Validation != nil && !ws.webhookRegistrationClient.ValidationRegistered.IsSet() {
|
||||
if err := ws.webhookRegistrationClient.RegisterValidatingWebhook(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ws.webhookRegistrationClient.ValidationRegistered.Set()
|
||||
glog.Infof("Validating webhook registered")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Add table
Reference in a new issue