mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
commit
4d684fca51
9 changed files with 102 additions and 22 deletions
|
@ -227,7 +227,7 @@ spec:
|
|||
containers:
|
||||
- name: kyverno
|
||||
image: nirmata/kyverno:latest
|
||||
args: ["--filterKind","Node,Event,APIService,Policy,TokenReview,SubjectAccessReview"]
|
||||
args: ["--filterK8Resources","[Event,*,*][*,kube-system,*][*,kube-public,*][*,kube-node-lease,*]Node,*,*][APIService,*,*][TokenReview,*,*][SubjectAccessReview,*,*][Deployment,default,nginx-deployment]"]
|
||||
ports:
|
||||
- containerPort: 443
|
||||
securityContext:
|
||||
|
|
13
main.go
13
main.go
|
@ -18,9 +18,9 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
kubeconfig string
|
||||
serverIP string
|
||||
filterK8Kinds webhooks.ArrayFlags
|
||||
kubeconfig string
|
||||
serverIP string
|
||||
filterK8Resources string
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -49,14 +49,15 @@ func main() {
|
|||
policyInformerFactory,
|
||||
violationBuilder,
|
||||
eventController,
|
||||
annotationsController)
|
||||
annotationsController,
|
||||
filterK8Resources)
|
||||
|
||||
genControler := gencontroller.NewGenController(client, eventController, policyInformerFactory, violationBuilder, kubeInformer.Core().V1().Namespaces(), annotationsController)
|
||||
tlsPair, err := initTLSPemPair(clientConfig, client)
|
||||
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, filterK8Kinds)
|
||||
server, err := webhooks.NewWebhookServer(client, tlsPair, policyInformerFactory, eventController, violationBuilder, annotationsController, filterK8Resources)
|
||||
if err != nil {
|
||||
glog.Fatalf("Unable to create webhook server: %v\n", err)
|
||||
}
|
||||
|
@ -93,7 +94,7 @@ func main() {
|
|||
func init() {
|
||||
flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
|
||||
flag.StringVar(&serverIP, "serverIP", "", "IP address where Kyverno controller runs. Only required if out-of-cluster.")
|
||||
flag.Var(&filterK8Kinds, "filterKind", "k8 kind where policy is not evaluated by the admission webhook. example --filterKind \"Event\" --filterKind \"TokenReview,ClusterRole\"")
|
||||
flag.StringVar(&filterK8Resources, "filterK8Resources", "", "k8 resource in format [kind,namespace,name] where policy is not evaluated by the admission webhook. example --filterKind \"[Deployment, kyverno, kyverno]\" --filterKind \"[Deployment, kyverno, kyverno],[Events, *, *]\"")
|
||||
config.LogDefaultFlags()
|
||||
flag.Parse()
|
||||
}
|
||||
|
|
|
@ -6,10 +6,11 @@ import (
|
|||
v1alpha1 "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
|
||||
client "github.com/nirmata/kyverno/pkg/dclient"
|
||||
"github.com/nirmata/kyverno/pkg/engine"
|
||||
"github.com/nirmata/kyverno/pkg/utils"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
func cleanAnnotations(client *client.Client, obj interface{}) {
|
||||
func cleanAnnotations(client *client.Client, obj interface{}, filterK8Resources []utils.K8Resource) {
|
||||
// get the policy struct from interface
|
||||
unstr, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
|
||||
if err != nil {
|
||||
|
@ -22,7 +23,7 @@ func cleanAnnotations(client *client.Client, obj interface{}) {
|
|||
return
|
||||
}
|
||||
// Get the resources that apply to the policy
|
||||
resourceMap := engine.ListResourcesThatApplyToPolicy(client, &policy)
|
||||
resourceMap := engine.ListResourcesThatApplyToPolicy(client, &policy, filterK8Resources)
|
||||
// remove annotations for the resources
|
||||
for _, obj := range resourceMap {
|
||||
// get annotations
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"github.com/nirmata/kyverno/pkg/annotations"
|
||||
"github.com/nirmata/kyverno/pkg/info"
|
||||
"github.com/nirmata/kyverno/pkg/utils"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/engine"
|
||||
|
||||
|
@ -36,6 +37,7 @@ type PolicyController struct {
|
|||
eventController event.Generator
|
||||
annotationsController annotations.Controller
|
||||
queue workqueue.RateLimitingInterface
|
||||
filterK8Resources []utils.K8Resource
|
||||
}
|
||||
|
||||
// NewPolicyController from cmd args
|
||||
|
@ -43,7 +45,8 @@ func NewPolicyController(client *client.Client,
|
|||
policyInformer sharedinformer.PolicyInformer,
|
||||
violationBuilder violation.Generator,
|
||||
eventController event.Generator,
|
||||
annotationsController annotations.Controller) *PolicyController {
|
||||
annotationsController annotations.Controller,
|
||||
filterK8Resources string) *PolicyController {
|
||||
|
||||
controller := &PolicyController{
|
||||
client: client,
|
||||
|
@ -52,6 +55,7 @@ func NewPolicyController(client *client.Client,
|
|||
violationBuilder: violationBuilder,
|
||||
eventController: eventController,
|
||||
annotationsController: annotationsController,
|
||||
filterK8Resources: utils.ParseKinds(filterK8Resources),
|
||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), policyWorkQueueName),
|
||||
}
|
||||
|
||||
|
@ -87,7 +91,7 @@ func (pc *PolicyController) deletePolicyHandler(resource interface{}) {
|
|||
glog.Error("error decoding object, invalid type")
|
||||
return
|
||||
}
|
||||
cleanAnnotations(pc.client, resource)
|
||||
cleanAnnotations(pc.client, resource, pc.filterK8Resources)
|
||||
glog.Infof("policy deleted: %s", object.GetName())
|
||||
}
|
||||
|
||||
|
@ -187,7 +191,7 @@ func (pc *PolicyController) syncHandler(obj interface{}) error {
|
|||
|
||||
glog.Infof("process policy %s on existing resources", policy.GetName())
|
||||
// Process policy on existing resources
|
||||
policyInfos := engine.ProcessExisting(pc.client, policy)
|
||||
policyInfos := engine.ProcessExisting(pc.client, policy, pc.filterK8Resources)
|
||||
|
||||
events, violations := pc.createEventsAndViolations(policyInfos)
|
||||
// Events, Violations
|
||||
|
|
|
@ -42,7 +42,8 @@ func (f *fixture) runControler(policyName string) {
|
|||
policyInformerFactory,
|
||||
violationBuilder,
|
||||
eventController,
|
||||
nil)
|
||||
nil,
|
||||
"")
|
||||
|
||||
stopCh := signals.SetupSignalHandler()
|
||||
// start informer & controller
|
||||
|
|
|
@ -6,14 +6,15 @@ import (
|
|||
types "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
|
||||
client "github.com/nirmata/kyverno/pkg/dclient"
|
||||
"github.com/nirmata/kyverno/pkg/info"
|
||||
"github.com/nirmata/kyverno/pkg/utils"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// ProcessExisting checks for mutation and validation violations of existing resources
|
||||
func ProcessExisting(client *client.Client, policy *types.Policy) []*info.PolicyInfo {
|
||||
func ProcessExisting(client *client.Client, policy *types.Policy, filterK8Resources []utils.K8Resource) []*info.PolicyInfo {
|
||||
glog.Infof("Applying policy %s on existing resources", policy.Name)
|
||||
// key uid
|
||||
resourceMap := ListResourcesThatApplyToPolicy(client, policy)
|
||||
resourceMap := ListResourcesThatApplyToPolicy(client, policy, filterK8Resources)
|
||||
policyInfos := []*info.PolicyInfo{}
|
||||
// for the filtered resource apply policy
|
||||
for _, v := range resourceMap {
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
types "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
|
||||
v1alpha1 "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
|
||||
client "github.com/nirmata/kyverno/pkg/dclient"
|
||||
"github.com/nirmata/kyverno/pkg/utils"
|
||||
v1helper "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
|
@ -20,7 +21,7 @@ import (
|
|||
)
|
||||
|
||||
//ListResourcesThatApplyToPolicy returns list of resources that are filtered by policy rules
|
||||
func ListResourcesThatApplyToPolicy(client *client.Client, policy *types.Policy) map[string]resourceInfo {
|
||||
func ListResourcesThatApplyToPolicy(client *client.Client, policy *types.Policy, filterK8Resources []utils.K8Resource) map[string]resourceInfo {
|
||||
// key uid
|
||||
resourceMap := map[string]resourceInfo{}
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
|
@ -45,7 +46,7 @@ func ListResourcesThatApplyToPolicy(client *client.Client, policy *types.Policy)
|
|||
// If kind is namespace then namespace is "", override
|
||||
// Get resources in the namespace
|
||||
for _, ns := range namespaces {
|
||||
rMap := getResourcesPerNamespace(k, client, ns, rule)
|
||||
rMap := getResourcesPerNamespace(k, client, ns, rule, filterK8Resources)
|
||||
mergeresources(resourceMap, rMap)
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +54,7 @@ func ListResourcesThatApplyToPolicy(client *client.Client, policy *types.Policy)
|
|||
return resourceMap
|
||||
}
|
||||
|
||||
func getResourcesPerNamespace(kind string, client *client.Client, namespace string, rule types.Rule) map[string]resourceInfo {
|
||||
func getResourcesPerNamespace(kind string, client *client.Client, namespace string, rule types.Rule, filterK8Resources []utils.K8Resource) map[string]resourceInfo {
|
||||
resourceMap := map[string]resourceInfo{}
|
||||
// List resources
|
||||
list, err := client.ListResource(kind, namespace, rule.MatchResources.Selector)
|
||||
|
@ -104,6 +105,10 @@ func getResourcesPerNamespace(kind string, client *client.Client, namespace stri
|
|||
ri := resourceInfo{Resource: res, Gvk: &metav1.GroupVersionKind{Group: gvk.Group,
|
||||
Version: gvk.Version,
|
||||
Kind: gvk.Kind}}
|
||||
// Skip the filtered resources
|
||||
if utils.SkipFilteredResources(gvk.Kind, res.GetNamespace(), res.GetName(), filterK8Resources) {
|
||||
continue
|
||||
}
|
||||
|
||||
resourceMap[string(res.GetUID())] = ri
|
||||
}
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/minio/minio/pkg/wildcard"
|
||||
"k8s.io/api/admission/v1beta1"
|
||||
)
|
||||
|
||||
func Contains(list []string, element string) bool {
|
||||
for _, e := range list {
|
||||
if e == element {
|
||||
|
@ -8,3 +17,60 @@ func Contains(list []string, element string) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type K8Resource struct {
|
||||
Kind string //TODO: as we currently only support one GVK version, we use the kind only. But if we support multiple GVK, then GV need to be added
|
||||
Namespace string
|
||||
Name string
|
||||
}
|
||||
|
||||
func SkipFilteredResourcesReq(request *v1beta1.AdmissionRequest, filterK8Resources []K8Resource) bool {
|
||||
kind := request.Kind.Kind
|
||||
namespace := request.Namespace
|
||||
name := request.Name
|
||||
for _, r := range filterK8Resources {
|
||||
if wildcard.Match(r.Kind, kind) && wildcard.Match(r.Namespace, namespace) && wildcard.Match(r.Name, name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func SkipFilteredResources(kind, namespace, name string, filterK8Resources []K8Resource) bool {
|
||||
for _, r := range filterK8Resources {
|
||||
if wildcard.Match(r.Kind, kind) && wildcard.Match(r.Namespace, namespace) && wildcard.Match(r.Name, name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//parseKinds parses the kinds if a single string contains comma seperated kinds
|
||||
// {"1,2,3","4","5"} => {"1","2","3","4","5"}
|
||||
func ParseKinds(list string) []K8Resource {
|
||||
resources := []K8Resource{}
|
||||
var resource K8Resource
|
||||
re := regexp.MustCompile(`\[([^\[\]]*)\]`)
|
||||
submatchall := re.FindAllString(list, -1)
|
||||
for _, element := range submatchall {
|
||||
element = strings.Trim(element, "[")
|
||||
element = strings.Trim(element, "]")
|
||||
elements := strings.Split(element, ",")
|
||||
//TODO: wildcards for namespace and name
|
||||
if len(elements) == 0 {
|
||||
continue
|
||||
}
|
||||
if len(elements) == 3 {
|
||||
resource = K8Resource{Kind: elements[0], Namespace: elements[1], Name: elements[2]}
|
||||
}
|
||||
if len(elements) == 2 {
|
||||
resource = K8Resource{Kind: elements[0], Namespace: elements[1]}
|
||||
}
|
||||
if len(elements) == 1 {
|
||||
resource = K8Resource{Kind: elements[0]}
|
||||
}
|
||||
fmt.Println(resource)
|
||||
resources = append(resources, resource)
|
||||
}
|
||||
return resources
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/nirmata/kyverno/pkg/event"
|
||||
"github.com/nirmata/kyverno/pkg/sharedinformer"
|
||||
tlsutils "github.com/nirmata/kyverno/pkg/tls"
|
||||
"github.com/nirmata/kyverno/pkg/utils"
|
||||
"github.com/nirmata/kyverno/pkg/violation"
|
||||
v1beta1 "k8s.io/api/admission/v1beta1"
|
||||
)
|
||||
|
@ -31,7 +32,7 @@ type WebhookServer struct {
|
|||
eventController event.Generator
|
||||
violationBuilder violation.Generator
|
||||
annotationsController annotations.Controller
|
||||
filterKinds []string
|
||||
filterK8Resources []utils.K8Resource
|
||||
}
|
||||
|
||||
// NewWebhookServer creates new instance of WebhookServer accordingly to given configuration
|
||||
|
@ -43,7 +44,7 @@ func NewWebhookServer(
|
|||
eventController event.Generator,
|
||||
violationBuilder violation.Generator,
|
||||
annotationsController annotations.Controller,
|
||||
filterKinds []string) (*WebhookServer, error) {
|
||||
filterK8Resources string) (*WebhookServer, error) {
|
||||
|
||||
if tlsPair == nil {
|
||||
return nil, errors.New("NewWebhookServer is not initialized properly")
|
||||
|
@ -62,7 +63,7 @@ func NewWebhookServer(
|
|||
eventController: eventController,
|
||||
violationBuilder: violationBuilder,
|
||||
annotationsController: annotationsController,
|
||||
filterKinds: parseKinds(filterKinds),
|
||||
filterK8Resources: utils.ParseKinds(filterK8Resources),
|
||||
}
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc(config.MutatingWebhookServicePath, ws.serve)
|
||||
|
@ -92,7 +93,7 @@ func (ws *WebhookServer) serve(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// Do not process the admission requests for kinds that are in filterKinds for filtering
|
||||
if !StringInSlice(admissionReview.Request.Kind.Kind, ws.filterKinds) {
|
||||
if !utils.SkipFilteredResourcesReq(admissionReview.Request, ws.filterK8Resources) {
|
||||
// if the resource is being deleted we need to clear any existing Policy Violations
|
||||
// TODO: can report to the user that we clear the violation corresponding to this resource
|
||||
if admissionReview.Request.Operation == v1beta1.Delete {
|
||||
|
|
Loading…
Reference in a new issue