mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
fix pr comments
This commit is contained in:
parent
e83cb51313
commit
dcc851dee2
5 changed files with 76 additions and 25 deletions
20
main.go
20
main.go
|
@ -13,8 +13,9 @@ import (
|
||||||
"github.com/nirmata/kyverno/pkg/namespace"
|
"github.com/nirmata/kyverno/pkg/namespace"
|
||||||
"github.com/nirmata/kyverno/pkg/policy"
|
"github.com/nirmata/kyverno/pkg/policy"
|
||||||
"github.com/nirmata/kyverno/pkg/policyviolation"
|
"github.com/nirmata/kyverno/pkg/policyviolation"
|
||||||
|
"github.com/nirmata/kyverno/pkg/utils"
|
||||||
"github.com/nirmata/kyverno/pkg/webhooks"
|
"github.com/nirmata/kyverno/pkg/webhooks"
|
||||||
"k8s.io/client-go/informers"
|
kubeinformer "k8s.io/client-go/informers"
|
||||||
"k8s.io/sample-controller/pkg/signals"
|
"k8s.io/sample-controller/pkg/signals"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ var (
|
||||||
webhookTimeout int
|
webhookTimeout int
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: tune resync time differently for each informer
|
||||||
const defaultReSyncTime = 10 * time.Second
|
const defaultReSyncTime = 10 * time.Second
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -48,6 +50,7 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Error creating client: %v\n", err)
|
glog.Fatalf("Error creating client: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DYNAMIC CLIENT
|
// DYNAMIC CLIENT
|
||||||
// - client for all registered resources
|
// - client for all registered resources
|
||||||
client, err := client.NewClient(clientConfig)
|
client, err := client.NewClient(clientConfig)
|
||||||
|
@ -65,9 +68,16 @@ func main() {
|
||||||
// - generate event with retry
|
// - generate event with retry
|
||||||
egen := event.NewEventGenerator(client, pInformer.Kyverno().V1alpha1().Policies())
|
egen := event.NewEventGenerator(client, pInformer.Kyverno().V1alpha1().Policies())
|
||||||
|
|
||||||
// mutatingWebhookConfiguration Informer
|
kubeClient, err := utils.NewKubeClient(clientConfig)
|
||||||
kubeInformer := informers.NewSharedInformerFactory(client.Kclient, defaultReSyncTime)
|
if err != nil {
|
||||||
mutatingWebhookConfigurationLister := kubeInformer.Admissionregistration().V1beta1().MutatingWebhookConfigurations().Lister()
|
glog.Fatalf("Error creating kubernetes client: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// - cache resync time: 10 seconds
|
||||||
|
kubeInformer := kubeinformer.NewSharedInformerFactoryWithOptions(kubeClient, defaultReSyncTime)
|
||||||
|
|
||||||
|
// MutatingWebhookConfiguration Informer
|
||||||
|
mutatingWebhookConfigurationInformer := kubeInformer.Admissionregistration().V1beta1().MutatingWebhookConfigurations()
|
||||||
|
|
||||||
tlsPair, err := initTLSPemPair(clientConfig, client)
|
tlsPair, err := initTLSPemPair(clientConfig, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -91,7 +101,7 @@ func main() {
|
||||||
// - process policy on existing resources
|
// - process policy on existing resources
|
||||||
// - status: violation count
|
// - status: violation count
|
||||||
|
|
||||||
pc, err := policy.NewPolicyController(pclient, client, pInformer.Kyverno().V1alpha1().Policies(), pInformer.Kyverno().V1alpha1().PolicyViolations(), egen, mutatingWebhookConfigurationLister, webhookRegistrationClient)
|
pc, err := policy.NewPolicyController(pclient, client, pInformer.Kyverno().V1alpha1().Policies(), pInformer.Kyverno().V1alpha1().PolicyViolations(), egen, mutatingWebhookConfigurationInformer, webhookRegistrationClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("error creating policy controller: %v\n", err)
|
glog.Fatalf("error creating policy controller: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ type Client struct {
|
||||||
client dynamic.Interface
|
client dynamic.Interface
|
||||||
cachedClient discovery.CachedDiscoveryInterface
|
cachedClient discovery.CachedDiscoveryInterface
|
||||||
clientConfig *rest.Config
|
clientConfig *rest.Config
|
||||||
Kclient kubernetes.Interface
|
kclient kubernetes.Interface
|
||||||
DiscoveryClient IDiscovery
|
DiscoveryClient IDiscovery
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ func NewClient(config *rest.Config) (*Client, error) {
|
||||||
client := Client{
|
client := Client{
|
||||||
client: dclient,
|
client: dclient,
|
||||||
clientConfig: config,
|
clientConfig: config,
|
||||||
Kclient: kclient,
|
kclient: kclient,
|
||||||
}
|
}
|
||||||
// Set discovery client
|
// Set discovery client
|
||||||
//
|
//
|
||||||
|
@ -75,12 +75,12 @@ func (c *Client) GetKubePolicyDeployment() (*apps.Deployment, error) {
|
||||||
//TODO: can we use dynamic client to fetch the typed interface
|
//TODO: can we use dynamic client to fetch the typed interface
|
||||||
// or generate a kube client value to access the interface
|
// or generate a kube client value to access the interface
|
||||||
func (c *Client) GetEventsInterface() (event.EventInterface, error) {
|
func (c *Client) GetEventsInterface() (event.EventInterface, error) {
|
||||||
return c.Kclient.CoreV1().Events(""), nil
|
return c.kclient.CoreV1().Events(""), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetCSRInterface provides type interface for CSR
|
//GetCSRInterface provides type interface for CSR
|
||||||
func (c *Client) GetCSRInterface() (csrtype.CertificateSigningRequestInterface, error) {
|
func (c *Client) GetCSRInterface() (csrtype.CertificateSigningRequestInterface, error) {
|
||||||
return c.Kclient.CertificatesV1beta1().CertificateSigningRequests(), nil
|
return c.kclient.CertificatesV1beta1().CertificateSigningRequests(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) getInterface(resource string) dynamic.NamespaceableResourceInterface {
|
func (c *Client) getInterface(resource string) dynamic.NamespaceableResourceInterface {
|
||||||
|
|
|
@ -32,7 +32,7 @@ func NewMockClient(scheme *runtime.Scheme, objects ...runtime.Object) (*Client,
|
||||||
kclient := kubernetesfake.NewSimpleClientset(objects...)
|
kclient := kubernetesfake.NewSimpleClientset(objects...)
|
||||||
return &Client{
|
return &Client{
|
||||||
client: client,
|
client: client,
|
||||||
Kclient: kclient,
|
kclient: kclient,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,9 @@ import (
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
webhookinformer "k8s.io/client-go/informers/admissionregistration/v1beta1"
|
||||||
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
v1beta1 "k8s.io/client-go/listers/admissionregistration/v1beta1"
|
webhooklister "k8s.io/client-go/listers/admissionregistration/v1beta1"
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
"k8s.io/client-go/util/workqueue"
|
"k8s.io/client-go/util/workqueue"
|
||||||
|
@ -67,8 +68,8 @@ type PolicyController struct {
|
||||||
pListerSynced cache.InformerSynced
|
pListerSynced cache.InformerSynced
|
||||||
// pvListerSynced returns true if the Policy store has been synced at least once
|
// pvListerSynced returns true if the Policy store has been synced at least once
|
||||||
pvListerSynced cache.InformerSynced
|
pvListerSynced cache.InformerSynced
|
||||||
// mutationwebhookInformer can list/get mutatingwebhookconfigurations
|
// mutationwebhookLister can list/get mutatingwebhookconfigurations
|
||||||
mutationwebhookInformer v1beta1.MutatingWebhookConfigurationLister
|
mutationwebhookLister webhooklister.MutatingWebhookConfigurationLister
|
||||||
// WebhookRegistrationClient
|
// WebhookRegistrationClient
|
||||||
webhookRegistrationClient *webhooks.WebhookRegistrationClient
|
webhookRegistrationClient *webhooks.WebhookRegistrationClient
|
||||||
// Resource manager, manages the mapping for already processed resource
|
// Resource manager, manages the mapping for already processed resource
|
||||||
|
@ -79,7 +80,7 @@ type PolicyController struct {
|
||||||
|
|
||||||
// NewPolicyController create a new PolicyController
|
// NewPolicyController create a new PolicyController
|
||||||
func NewPolicyController(kyvernoClient *kyvernoclient.Clientset, client *client.Client, pInformer kyvernoinformer.PolicyInformer, pvInformer kyvernoinformer.PolicyViolationInformer,
|
func NewPolicyController(kyvernoClient *kyvernoclient.Clientset, client *client.Client, pInformer kyvernoinformer.PolicyInformer, pvInformer kyvernoinformer.PolicyViolationInformer,
|
||||||
eventGen event.Interface, mutationwebhookInformer v1beta1.MutatingWebhookConfigurationLister, webhookRegistrationClient *webhooks.WebhookRegistrationClient) (*PolicyController, error) {
|
eventGen event.Interface, webhookInformer webhookinformer.MutatingWebhookConfigurationInformer, webhookRegistrationClient *webhooks.WebhookRegistrationClient) (*PolicyController, error) {
|
||||||
// Event broad caster
|
// Event broad caster
|
||||||
eventBroadcaster := record.NewBroadcaster()
|
eventBroadcaster := record.NewBroadcaster()
|
||||||
eventBroadcaster.StartLogging(glog.Infof)
|
eventBroadcaster.StartLogging(glog.Infof)
|
||||||
|
@ -95,7 +96,6 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset, client *client.
|
||||||
eventGen: eventGen,
|
eventGen: eventGen,
|
||||||
eventRecorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "policy_controller"}),
|
eventRecorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "policy_controller"}),
|
||||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "policy"),
|
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "policy"),
|
||||||
mutationwebhookInformer: mutationwebhookInformer,
|
|
||||||
webhookRegistrationClient: webhookRegistrationClient,
|
webhookRegistrationClient: webhookRegistrationClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +121,8 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset, client *client.
|
||||||
pc.pListerSynced = pInformer.Informer().HasSynced
|
pc.pListerSynced = pInformer.Informer().HasSynced
|
||||||
pc.pvListerSynced = pInformer.Informer().HasSynced
|
pc.pvListerSynced = pInformer.Informer().HasSynced
|
||||||
|
|
||||||
|
pc.mutationwebhookLister = webhookInformer.Lister()
|
||||||
|
|
||||||
// resource manager
|
// resource manager
|
||||||
// rebuild after 300 seconds/ 5 mins
|
// rebuild after 300 seconds/ 5 mins
|
||||||
//TODO: pass the time in seconds instead of converting it internally
|
//TODO: pass the time in seconds instead of converting it internally
|
||||||
|
@ -394,7 +396,9 @@ func (pc *PolicyController) syncPolicy(key string) error {
|
||||||
policy, err := pc.pLister.Get(key)
|
policy, err := pc.pLister.Get(key)
|
||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
glog.V(2).Infof("Policy %v has been deleted", key)
|
glog.V(2).Infof("Policy %v has been deleted", key)
|
||||||
err = pc.handleWebhookRegistration(true)
|
if err := pc.handleWebhookRegistration(true, nil); err != nil {
|
||||||
|
glog.Errorln(err)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,7 +406,7 @@ func (pc *PolicyController) syncPolicy(key string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pc.handleWebhookRegistration(false); err != nil {
|
if err := pc.handleWebhookRegistration(false, policy); err != nil {
|
||||||
glog.Errorln(err)
|
glog.Errorln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,28 +425,40 @@ func (pc *PolicyController) syncPolicy(key string) error {
|
||||||
return pc.syncStatusOnly(p, pvList)
|
return pc.syncStatusOnly(p, pvList)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc *PolicyController) handleWebhookRegistration(emptyPolicy bool) error {
|
// TODO: here checks mutatingwebhook only
|
||||||
|
// as 'kubectl scale' is not funtional with validatingwebhook
|
||||||
|
// refer to https://github.com/nirmata/kyverno/issues/250
|
||||||
|
func (pc *PolicyController) handleWebhookRegistration(delete bool, policy *kyverno.Policy) error {
|
||||||
|
policies, _ := pc.pLister.List(labels.NewSelector())
|
||||||
selector := &metav1.LabelSelector{MatchLabels: config.KubePolicyAppLabels}
|
selector := &metav1.LabelSelector{MatchLabels: config.KubePolicyAppLabels}
|
||||||
webhookSelector, err := metav1.LabelSelectorAsSelector(selector)
|
webhookSelector, err := metav1.LabelSelectorAsSelector(selector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid label selector: %v", err)
|
return fmt.Errorf("invalid label selector: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := pc.mutationwebhookInformer.List(webhookSelector)
|
webhookList, err := pc.mutationwebhookLister.List(webhookSelector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to list mutatingwebhookconfigurations, err %v", err)
|
return fmt.Errorf("failed to list mutatingwebhookconfigurations, err %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if emptyPolicy {
|
if delete {
|
||||||
// deregister webhookconfigurations it it exists
|
if webhookList == nil {
|
||||||
if list != nil {
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// webhook exist, deregister webhookconfigurations on condition
|
||||||
|
// check empty policy first, then rule type in terms of O(time)
|
||||||
|
if policies == nil {
|
||||||
glog.V(3).Infoln("No policy found in the cluster, deregistering webhook")
|
glog.V(3).Infoln("No policy found in the cluster, deregistering webhook")
|
||||||
pc.webhookRegistrationClient.DeregisterMutatingWebhook()
|
pc.webhookRegistrationClient.DeregisterMutatingWebhook()
|
||||||
|
} else if !webhooks.HasMutateOrValidatePolicies(policies) {
|
||||||
|
glog.V(3).Infoln("No muatate/validate policy found in the cluster, deregistering webhook")
|
||||||
|
pc.webhookRegistrationClient.DeregisterMutatingWebhook()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if list == nil {
|
if webhookList == nil && webhooks.HasMutateOrValidate(*policy) {
|
||||||
glog.V(3).Infoln("Found policy without mutatingwebhook, registering webhook")
|
glog.V(3).Infoln("Found policy without mutatingwebhook, registering webhook")
|
||||||
pc.webhookRegistrationClient.RegisterMutatingWebhook()
|
pc.webhookRegistrationClient.RegisterMutatingWebhook()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package webhooks
|
package webhooks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
|
||||||
v1beta1 "k8s.io/api/admission/v1beta1"
|
v1beta1 "k8s.io/api/admission/v1beta1"
|
||||||
|
@ -26,6 +28,10 @@ func (ws *WebhookServer) manageWebhookConfigurations(policy kyverno.Policy, op v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *WebhookServer) registerWebhookConfigurations(policy kyverno.Policy) error {
|
func (ws *WebhookServer) registerWebhookConfigurations(policy kyverno.Policy) error {
|
||||||
|
if !HasMutateOrValidate(policy) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if !ws.webhookRegistrationClient.MutationRegistered.IsSet() {
|
if !ws.webhookRegistrationClient.MutationRegistered.IsSet() {
|
||||||
if err := ws.webhookRegistrationClient.RegisterMutatingWebhook(); err != nil {
|
if err := ws.webhookRegistrationClient.RegisterMutatingWebhook(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -39,11 +45,30 @@ func (ws *WebhookServer) registerWebhookConfigurations(policy kyverno.Policy) er
|
||||||
func (ws *WebhookServer) deregisterWebhookConfigurations(policy kyverno.Policy) error {
|
func (ws *WebhookServer) deregisterWebhookConfigurations(policy kyverno.Policy) error {
|
||||||
policies, _ := ws.pLister.List(labels.NewSelector())
|
policies, _ := ws.pLister.List(labels.NewSelector())
|
||||||
|
|
||||||
// deregister webhook if no policy found in cluster
|
// deregister webhook if no mutate/validate policy found in cluster
|
||||||
if len(policies) == 1 {
|
if !HasMutateOrValidatePolicies(policies) {
|
||||||
ws.webhookRegistrationClient.DeregisterMutatingWebhook()
|
ws.webhookRegistrationClient.DeregisterMutatingWebhook()
|
||||||
glog.Infoln("Mutating webhook deregistered")
|
glog.Infoln("Mutating webhook deregistered")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HasMutateOrValidatePolicies(policies []*kyverno.Policy) bool {
|
||||||
|
for _, policy := range policies {
|
||||||
|
if HasMutateOrValidate(*policy) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func HasMutateOrValidate(policy kyverno.Policy) bool {
|
||||||
|
for _, rule := range policy.Spec.Rules {
|
||||||
|
if !reflect.DeepEqual(rule.Mutation, kyverno.Mutation{}) || !reflect.DeepEqual(rule.Validation, kyverno.Validation{}) {
|
||||||
|
glog.Infoln(rule.Name)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue