1
0
Fork 0
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:
Shuting Zhao 2019-08-07 18:01:28 -07:00
parent a4217de1a2
commit 6c12a76ab2
7 changed files with 141 additions and 94 deletions

23
main.go
View file

@ -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)

View file

@ -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{

View file

@ -42,7 +42,6 @@ func (f *fixture) runControler(policyName string) {
policyInformerFactory,
violationBuilder,
eventController,
nil,
"")
stopCh := signals.SetupSignalHandler()

View file

@ -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)

View file

@ -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,

View file

@ -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)

View 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
}