diff --git a/pkg/api/kyverno/v1alpha1/types.go b/pkg/api/kyverno/v1alpha1/types.go index 54a1f7f093..4d33f62941 100644 --- a/pkg/api/kyverno/v1alpha1/types.go +++ b/pkg/api/kyverno/v1alpha1/types.go @@ -45,10 +45,10 @@ type ExcludeResources struct { // ResourceDescription describes the resource to which the PolicyRule will be applied. type ResourceDescription struct { - Kinds []string `json:"kinds"` - Name string `json:"name"` - Namespace string `json:"namespace,omitempty"` - Selector *metav1.LabelSelector `json:"selector"` + Kinds []string `json:"kinds"` + Name string `json:"name"` + Namespaces []string `json:"namespace,omitempty"` + Selector *metav1.LabelSelector `json:"selector"` } // Mutation describes the way how Mutating Webhook will react on resource creation diff --git a/pkg/api/kyverno/v1alpha1/zz_generated.deepcopy.go b/pkg/api/kyverno/v1alpha1/zz_generated.deepcopy.go index 16fa7b7f56..cfc34d4a24 100644 --- a/pkg/api/kyverno/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/api/kyverno/v1alpha1/zz_generated.deepcopy.go @@ -280,6 +280,11 @@ func (in *ResourceDescription) DeepCopyInto(out *ResourceDescription) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.Namespaces != nil { + in, out := &in.Namespaces, &out.Namespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } if in.Selector != nil { in, out := &in.Selector, &out.Selector *out = new(v1.LabelSelector) diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go deleted file mode 100644 index 93ca34e1b5..0000000000 --- a/pkg/engine/engine.go +++ /dev/null @@ -1,105 +0,0 @@ -package engine - -import ( - kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1" - client "github.com/nirmata/kyverno/pkg/dclient" - "github.com/nirmata/kyverno/pkg/info" - "github.com/nirmata/kyverno/pkg/utils" -) - -// ProcessExisting checks for mutation and validation violations of existing resources -func ProcessExisting(client *client.Client, policy *kyverno.Policy, filterK8Resources []utils.K8Resource) []info.PolicyInfo { - return nil - // glog.Infof("Applying policy %s on existing resources", policy.Name) - // // key uid - // resourceMap := ListResourcesThatApplyToPolicy(client, policy, filterK8Resources) - // policyInfos := []info.PolicyInfo{} - // // for the filtered resource apply policy - // for _, v := range resourceMap { - - // policyInfo, err := applyPolicy(client, policy, v) - // if err != nil { - // glog.Errorf("unable to apply policy %s on resource %s/%s", policy.Name, v.Resource.GetName(), v.Resource.GetNamespace()) - // glog.Error(err) - // continue - // } - // policyInfos = append(policyInfos, policyInfo) - // } - - // return policyInfos -} - -// func applyPolicy(client *client.Client, policy *kyverno.Policy, res resourceInfo) (info.PolicyInfo, error) { -// var policyInfo info.PolicyInfo -// glog.Infof("Applying policy %s with %d rules\n", policy.ObjectMeta.Name, len(policy.Spec.Rules)) -// rawResource, err := res.Resource.MarshalJSON() -// if err != nil { -// return policyInfo, err -// } -// // Mutate -// mruleInfos, err := mutation(policy, rawResource, res.Gvk) -// policyInfo.AddRuleInfos(mruleInfos) -// if err != nil { -// return policyInfo, err -// } -// // Validation -// //TODO check by value or pointer -// vruleInfos, err := Validate(*policy, rawResource, *res.Gvk) -// if err != nil { -// return policyInfo, err -// } -// policyInfo.AddRuleInfos(vruleInfos) -// policyInfo = info.NewPolicyInfo(policy.Name, res.Gvk.Kind, res.Resource.GetName(), res.Resource.GetNamespace(), policy.Spec.ValidationFailureAction) - -// if res.Gvk.Kind == "Namespace" { - -// // Generation -// gruleInfos := Generate(client, policy, res.Resource) -// policyInfo.AddRuleInfos(gruleInfos) -// } - -// return policyInfo, nil -// } - -// func mutation(p *kyverno.Policy, rawResource []byte, gvk *metav1.GroupVersionKind) ([]*info.RuleInfo, error) { -// patches, ruleInfos := Mutate(*p, rawResource, *gvk) -// if len(ruleInfos) == 0 { -// // no rules were processed -// return nil, nil -// } -// // if there are any errors return -// for _, r := range ruleInfos { -// if !r.IsSuccessful() { -// return ruleInfos, nil -// } -// } -// // if there are no patches // for overlay -// if len(patches) == 0 { -// return ruleInfos, nil -// } -// // option 2: (original Resource + patch) compare with (original resource) -// mergePatches := JoinPatches(patches) -// // merge the patches -// patch, err := jsonpatch.DecodePatch(mergePatches) -// if err != nil { -// return nil, err -// } -// // apply the patches returned by mutate to the original resource -// patchedResource, err := patch.Apply(rawResource) -// if err != nil { -// return nil, err -// } -// // compare (original Resource + patch) vs (original resource) -// // to verify if they are equal -// ruleInfo := info.NewRuleInfo("over-all mutation", info.Mutation) -// if !jsonpatch.Equal(patchedResource, rawResource) { -// //resource does not match so there was a mutation rule violated -// // TODO : check the rule name "mutation rules" -// ruleInfo.Fail() -// ruleInfo.Add("resource does not satisfy mutation rules") -// } else { -// ruleInfo.Add("resource satisfys the mutation rule") -// } -// ruleInfos = append(ruleInfos, ruleInfo) -// return ruleInfos, nil -// } diff --git a/pkg/engine/overlay.go b/pkg/engine/overlay.go index 1ae274bb8c..a48a2c5b5f 100644 --- a/pkg/engine/overlay.go +++ b/pkg/engine/overlay.go @@ -31,11 +31,9 @@ func processOverlay(resourceUnstr unstructured.Unstructured, rule kyverno.Rule) return nil, err } - // resourceInfo := ParseResourceInfoFromObject(rawResource) patches, err := processOverlayPatches(resource, rule.Mutation.Overlay) if err != nil && strings.Contains(err.Error(), "Conditions are not met") { glog.V(4).Infof("overlay pattern %s does not match resource %s/%s", rule.Mutation.Overlay, resourceUnstr.GetNamespace(), resourceUnstr.GetName()) - // glog.Infof("Resource does not meet conditions in overlay pattern, resource=%s, rule=%s\n", resourceInfo, rule.Name) return nil, nil } diff --git a/pkg/engine/overlayPatch.go b/pkg/engine/overlayPatch.go index d71896b5c7..9f4df0ce90 100644 --- a/pkg/engine/overlayPatch.go +++ b/pkg/engine/overlayPatch.go @@ -13,7 +13,7 @@ func patchOverlay(rule kyverno.Rule, rawResource []byte) ([][]byte, error) { if err := json.Unmarshal(rawResource, &resource); err != nil { return nil, err } - + //TODO: evaluate, Unmarshall called thrice resourceInfo := ParseResourceInfoFromObject(rawResource) patches, err := processOverlayPatches(resource, rule.Mutation.Overlay) if err != nil && strings.Contains(err.Error(), "Conditions are not met") { diff --git a/pkg/engine/utils.go b/pkg/engine/utils.go index de13961155..167d0bf208 100644 --- a/pkg/engine/utils.go +++ b/pkg/engine/utils.go @@ -10,145 +10,13 @@ import ( "github.com/minio/minio/pkg/wildcard" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/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" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" ) -//ListResourcesThatApplyToPolicy returns list of resources that are filtered by policy rules -func ListResourcesThatApplyToPolicy(client *client.Client, policy *kyverno.Policy, filterK8Resources []utils.K8Resource) map[string]resourceInfo { - // key uid - resourceMap := map[string]resourceInfo{} - for _, rule := range policy.Spec.Rules { - // Match - for _, k := range rule.MatchResources.Kinds { - namespaces := []string{} - if k == "Namespace" { - namespaces = []string{""} - } else { - if rule.MatchResources.Namespace != "" { - // if namespace is specified then we add the namespace - namespaces = append(namespaces, rule.MatchResources.Namespace) - } else { - // no namespace specified, refer to all namespaces - namespaces = getAllNamespaces(client) - } - - // Check if exclude namespace is not clashing - namespaces = excludeNamespaces(namespaces, rule.ExcludeResources.Namespace) - } - - // If kind is namespace then namespace is "", override - // Get resources in the namespace - for _, ns := range namespaces { - rMap := getResourcesPerNamespace(k, client, ns, rule, filterK8Resources) - mergeresources(resourceMap, rMap) - } - } - } - return resourceMap -} - -func getResourcesPerNamespace(kind string, client *client.Client, namespace string, rule kyverno.Rule, filterK8Resources []utils.K8Resource) map[string]resourceInfo { - resourceMap := map[string]resourceInfo{} - // List resources - list, err := client.ListResource(kind, namespace, rule.MatchResources.Selector) - if err != nil { - glog.Errorf("unable to list resource for %s with label selector %s", kind, rule.MatchResources.Selector.String()) - return nil - } - var selector labels.Selector - // exclude label selector - if rule.ExcludeResources.Selector != nil { - selector, err = v1helper.LabelSelectorAsSelector(rule.ExcludeResources.Selector) - if err != nil { - glog.Error(err) - } - } - for _, res := range list.Items { - // exclude label selectors - if selector != nil { - set := labels.Set(res.GetLabels()) - if selector.Matches(set) { - // if matches - continue - } - } - var name string - // match - // name - // wild card matching - name = rule.MatchResources.Name - if name != "" { - // if does not match then we skip - if !wildcard.Match(name, res.GetName()) { - continue - } - } - // exclude - // name - // wild card matching - name = rule.ExcludeResources.Name - if name != "nil" { - // if matches then we skip - if wildcard.Match(name, res.GetName()) { - continue - } - } - gvk := res.GroupVersionKind() - - 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 - } - return resourceMap -} - -// merge b into a map -func mergeresources(a, b map[string]resourceInfo) { - for k, v := range b { - a[k] = v - } -} - -func getAllNamespaces(client *client.Client) []string { - namespaces := []string{} - // get all namespaces - nsList, err := client.ListResource("Namespace", "", nil) - if err != nil { - glog.Error(err) - return namespaces - } - for _, ns := range nsList.Items { - namespaces = append(namespaces, ns.GetName()) - } - return namespaces -} - -func excludeNamespaces(namespaces []string, excludeNs string) []string { - if excludeNs == "" { - return namespaces - } - filteredNamespaces := []string{} - for _, n := range namespaces { - if n == excludeNs { - continue - } - filteredNamespaces = append(filteredNamespaces, n) - } - return filteredNamespaces -} - //MatchesResourceDescription checks if the resource matches resource desription of the rule or not func MatchesResourceDescription(resource unstructured.Unstructured, rule kyverno.Rule) bool { matches := rule.MatchResources.ResourceDescription @@ -158,8 +26,8 @@ func MatchesResourceDescription(resource unstructured.Unstructured, rule kyverno return false } - // meta := parseMetadataFromObject(resourceRaw) name := resource.GetName() + namespace := resource.GetNamespace() if matches.Name != "" { @@ -175,14 +43,18 @@ func MatchesResourceDescription(resource unstructured.Unstructured, rule kyverno return false } } + // Matches - if matches.Namespace != "" && matches.Namespace != namespace { + // check if the resource namespace is defined in the list of namespaces for inclusion + if len(matches.Namespaces) > 0 && !utils.Contains(matches.Namespaces, namespace) { return false } // Exclude - if exclude.Namespace != "" && exclude.Namespace == namespace { + // check if the resource namespace is defined in the list of namespace for exclusion + if len(exclude.Namespaces) > 0 && utils.Contains(exclude.Namespaces, namespace) { return false } + // Matches if matches.Selector != nil { selector, err := metav1.LabelSelectorAsSelector(matches.Selector) @@ -209,82 +81,74 @@ func MatchesResourceDescription(resource unstructured.Unstructured, rule kyverno return true } -// ResourceMeetsDescription checks requests kind, name and labels to fit the policy rule -func ResourceMeetsDescription(resourceRaw []byte, matches kyverno.ResourceDescription, exclude kyverno.ResourceDescription, gvk metav1.GroupVersionKind) bool { - if !findKind(matches.Kinds, gvk.Kind) { - return false - } +// // ResourceMeetsDescription checks requests kind, name and labels to fit the policy rule +// func ResourceMeetsDescription(resourceRaw []byte, matches kyverno.ResourceDescription, exclude kyverno.ResourceDescription, gvk metav1.GroupVersionKind) bool { +// if !findKind(matches.Kinds, gvk.Kind) { +// return false +// } - if resourceRaw != nil { - meta := parseMetadataFromObject(resourceRaw) - name := ParseNameFromObject(resourceRaw) - namespace := ParseNamespaceFromObject(resourceRaw) +// if resourceRaw != nil { +// meta := parseMetadataFromObject(resourceRaw) +// name := ParseNameFromObject(resourceRaw) +// namespace := ParseNamespaceFromObject(resourceRaw) - if matches.Name != "" { - // Matches - if !wildcard.Match(matches.Name, name) { - return false - } - } - // Exclude - // the resource name matches the exclude resource name then reject - if exclude.Name != "" { - if wildcard.Match(exclude.Name, name) { - return false - } - } - // Matches - if matches.Namespace != "" && matches.Namespace != namespace { - return false - } - // Exclude - if exclude.Namespace != "" && exclude.Namespace == namespace { - return false - } - // Matches - if matches.Selector != nil { - selector, err := metav1.LabelSelectorAsSelector(matches.Selector) - if err != nil { - glog.Error(err) - return false - } - if meta != nil { - labelMap := parseLabelsFromMetadata(meta) - if !selector.Matches(labelMap) { - return false - } - } - } - // Exclude - if exclude.Selector != nil { - selector, err := metav1.LabelSelectorAsSelector(exclude.Selector) - // if the label selector is incorrect, should be fail or - if err != nil { - glog.Error(err) - return false - } +// if matches.Name != "" { +// // Matches +// if !wildcard.Match(matches.Name, name) { +// return false +// } +// } +// // Exclude +// // the resource name matches the exclude resource name then reject +// if exclude.Name != "" { +// if wildcard.Match(exclude.Name, name) { +// return false +// } +// } +// // Matches +// // check if the resource namespace is defined in the list of namespaces for inclusion +// if len(matches.Namespaces) > 0 && !utils.Contains(matches.Namespaces, namespace) { +// return false +// } +// // Exclude +// // check if the resource namespace is defined in the list of namespace for exclusion +// if len(exclude.Namespaces) > 0 && utils.Contains(exclude.Namespaces, namespace) { +// return false +// } +// // Matches +// if matches.Selector != nil { +// selector, err := metav1.LabelSelectorAsSelector(matches.Selector) +// if err != nil { +// glog.Error(err) +// return false +// } +// if meta != nil { +// labelMap := parseLabelsFromMetadata(meta) +// if !selector.Matches(labelMap) { +// return false +// } +// } +// } +// // Exclude +// if exclude.Selector != nil { +// selector, err := metav1.LabelSelectorAsSelector(exclude.Selector) +// // if the label selector is incorrect, should be fail or +// if err != nil { +// glog.Error(err) +// return false +// } - if meta != nil { - labelMap := parseLabelsFromMetadata(meta) - if selector.Matches(labelMap) { - return false - } - } - } +// if meta != nil { +// labelMap := parseLabelsFromMetadata(meta) +// if selector.Matches(labelMap) { +// return false +// } +// } +// } - } - return true -} - -func parseMetadataFromObject(bytes []byte) map[string]interface{} { - var objectJSON map[string]interface{} - json.Unmarshal(bytes, &objectJSON) - meta, ok := objectJSON["metadata"].(map[string]interface{}) - if !ok { - return nil - } - return meta -} +// } +// return true +// } // ParseResourceInfoFromObject get kind/namepace/name from resource func ParseResourceInfoFromObject(rawResource []byte) string { @@ -303,18 +167,6 @@ func ParseKindFromObject(bytes []byte) string { return objectJSON["kind"].(string) } -func parseLabelsFromMetadata(meta map[string]interface{}) labels.Set { - if interfaceMap, ok := meta["labels"].(map[string]interface{}); ok { - labelMap := make(labels.Set, len(interfaceMap)) - - for key, value := range interfaceMap { - labelMap[key] = value.(string) - } - return labelMap - } - return nil -} - //ParseNameFromObject extracts resource name from JSON obj func ParseNameFromObject(bytes []byte) string { var objectJSON map[string]interface{} @@ -354,15 +206,6 @@ func ParseNamespaceFromObject(bytes []byte) string { return "" } -// ParseRegexPolicyResourceName returns true if policyResourceName is a regexp -func ParseRegexPolicyResourceName(policyResourceName string) (string, bool) { - regex := strings.Split(policyResourceName, "regex:") - if len(regex) == 1 { - return regex[0], false - } - return strings.Trim(regex[1], " "), true -} - func getAnchorsFromMap(anchorsMap map[string]interface{}) map[string]interface{} { result := make(map[string]interface{}) @@ -512,8 +355,3 @@ func convertToFloat(value interface{}) (float64, error) { return 0, fmt.Errorf("Could not convert %T to float64", value) } } - -type resourceInfo struct { - Resource unstructured.Unstructured - Gvk *metav1.GroupVersionKind -} diff --git a/pkg/engine/utils_test.go b/pkg/engine/utils_test.go index 0373209a48..fa3959f480 100644 --- a/pkg/engine/utils_test.go +++ b/pkg/engine/utils_test.go @@ -3,341 +3,339 @@ package engine import ( "testing" - types "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" "gotest.tools/assert" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func TestResourceMeetsDescription_Kind(t *testing.T) { - resourceName := "test-config-map" - resourceDescription := types.ResourceDescription{ - Kinds: []string{"ConfigMap"}, - Name: &resourceName, - Selector: &metav1.LabelSelector{ - MatchLabels: nil, - MatchExpressions: nil, - }, - } - excludeResourcesResourceDesc := types.ResourceDescription{} - groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} +// func TestResourceMeetsDescription_Kind(t *testing.T) { +// resourceName := "test-config-map" +// resourceDescription := types.ResourceDescription{ +// Kinds: []string{"ConfigMap"}, +// Name: &resourceName, +// Selector: &metav1.LabelSelector{ +// MatchLabels: nil, +// MatchExpressions: nil, +// }, +// } +// excludeResourcesResourceDesc := types.ResourceDescription{} +// groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} - rawResource := []byte(`{ - "metadata":{ - "name":"test-config-map", - "namespace":"default", - "creationTimestamp":null, - "labels":{ - "label1":"test1", - "label2":"test2" - } - } - }`) +// rawResource := []byte(`{ +// "metadata":{ +// "name":"test-config-map", +// "namespace":"default", +// "creationTimestamp":null, +// "labels":{ +// "label1":"test1", +// "label2":"test2" +// } +// } +// }`) - assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) - resourceDescription.Kinds[0] = "Deployment" - assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) - resourceDescription.Kinds[0] = "ConfigMap" - groupVersionKind.Kind = "Deployment" - assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) -} +// assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// resourceDescription.Kinds[0] = "Deployment" +// assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// resourceDescription.Kinds[0] = "ConfigMap" +// groupVersionKind.Kind = "Deployment" +// assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// } -func TestResourceMeetsDescription_Name(t *testing.T) { - resourceName := "test-config-map" - resourceDescription := types.ResourceDescription{ - Kinds: []string{"ConfigMap"}, - Name: &resourceName, - Selector: &metav1.LabelSelector{ - MatchLabels: nil, - MatchExpressions: nil, - }, - } - excludeResourcesResourceDesc := types.ResourceDescription{} +// func TestResourceMeetsDescription_Name(t *testing.T) { +// resourceName := "test-config-map" +// resourceDescription := types.ResourceDescription{ +// Kinds: []string{"ConfigMap"}, +// Name: &resourceName, +// Selector: &metav1.LabelSelector{ +// MatchLabels: nil, +// MatchExpressions: nil, +// }, +// } +// excludeResourcesResourceDesc := types.ResourceDescription{} - groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} +// groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} - rawResource := []byte(`{ - "metadata":{ - "name":"test-config-map", - "namespace":"default", - "creationTimestamp":null, - "labels":{ - "label1":"test1", - "label2":"test2" - } - } - }`) +// rawResource := []byte(`{ +// "metadata":{ +// "name":"test-config-map", +// "namespace":"default", +// "creationTimestamp":null, +// "labels":{ +// "label1":"test1", +// "label2":"test2" +// } +// } +// }`) - assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) - resourceName = "test-config-map-new" - assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// resourceName = "test-config-map-new" +// assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) - rawResource = []byte(`{ - "metadata":{ - "name":"test-config-map-new", - "namespace":"default", - "creationTimestamp":null, - "labels":{ - "label1":"test1", - "label2":"test2" - } - } - }`) - assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// rawResource = []byte(`{ +// "metadata":{ +// "name":"test-config-map-new", +// "namespace":"default", +// "creationTimestamp":null, +// "labels":{ +// "label1":"test1", +// "label2":"test2" +// } +// } +// }`) +// assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) - rawResource = []byte(`{ - "metadata":{ - "name":"", - "namespace":"default", - "creationTimestamp":null, - "labels":{ - "label1":"test1", - "label2":"test2" - } - } - }`) - assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) -} +// rawResource = []byte(`{ +// "metadata":{ +// "name":"", +// "namespace":"default", +// "creationTimestamp":null, +// "labels":{ +// "label1":"test1", +// "label2":"test2" +// } +// } +// }`) +// assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// } -func TestResourceMeetsDescription_MatchExpressions(t *testing.T) { - resourceName := "test-config-map" - resourceDescription := types.ResourceDescription{ - Kinds: []string{"ConfigMap"}, - Name: &resourceName, - Selector: &metav1.LabelSelector{ - MatchLabels: nil, - MatchExpressions: []metav1.LabelSelectorRequirement{ - metav1.LabelSelectorRequirement{ - Key: "label2", - Operator: "NotIn", - Values: []string{ - "sometest1", - }, - }, - metav1.LabelSelectorRequirement{ - Key: "label1", - Operator: "In", - Values: []string{ - "test1", - "test8", - "test201", - }, - }, - metav1.LabelSelectorRequirement{ - Key: "label3", - Operator: "DoesNotExist", - Values: nil, - }, - metav1.LabelSelectorRequirement{ - Key: "label2", - Operator: "In", - Values: []string{ - "test2", - }, - }, - }, - }, - } - excludeResourcesResourceDesc := types.ResourceDescription{} +// func TestResourceMeetsDescription_MatchExpressions(t *testing.T) { +// resourceName := "test-config-map" +// resourceDescription := types.ResourceDescription{ +// Kinds: []string{"ConfigMap"}, +// Name: &resourceName, +// Selector: &metav1.LabelSelector{ +// MatchLabels: nil, +// MatchExpressions: []metav1.LabelSelectorRequirement{ +// metav1.LabelSelectorRequirement{ +// Key: "label2", +// Operator: "NotIn", +// Values: []string{ +// "sometest1", +// }, +// }, +// metav1.LabelSelectorRequirement{ +// Key: "label1", +// Operator: "In", +// Values: []string{ +// "test1", +// "test8", +// "test201", +// }, +// }, +// metav1.LabelSelectorRequirement{ +// Key: "label3", +// Operator: "DoesNotExist", +// Values: nil, +// }, +// metav1.LabelSelectorRequirement{ +// Key: "label2", +// Operator: "In", +// Values: []string{ +// "test2", +// }, +// }, +// }, +// }, +// } +// excludeResourcesResourceDesc := types.ResourceDescription{} - groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} - rawResource := []byte(`{ - "metadata":{ - "name":"test-config-map", - "namespace":"default", - "creationTimestamp":null, - "labels":{ - "label1":"test1", - "label2":"test2" - } - } - }`) +// groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} +// rawResource := []byte(`{ +// "metadata":{ +// "name":"test-config-map", +// "namespace":"default", +// "creationTimestamp":null, +// "labels":{ +// "label1":"test1", +// "label2":"test2" +// } +// } +// }`) - assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) - rawResource = []byte(`{ - "metadata":{ - "name":"test-config-map", - "namespace":"default", - "creationTimestamp":null, - "labels":{ - "label1":"test1234567890", - "label2":"test2" - } - } - }`) +// rawResource = []byte(`{ +// "metadata":{ +// "name":"test-config-map", +// "namespace":"default", +// "creationTimestamp":null, +// "labels":{ +// "label1":"test1234567890", +// "label2":"test2" +// } +// } +// }`) - assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) -} +// assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// } -func TestResourceMeetsDescription_MatchLabels(t *testing.T) { - resourceName := "test-config-map" - resourceDescription := types.ResourceDescription{ - Kinds: []string{"ConfigMap"}, - Name: &resourceName, - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "label1": "test1", - "label2": "test2", - }, - MatchExpressions: nil, - }, - } - groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} - excludeResourcesResourceDesc := types.ResourceDescription{} +// func TestResourceMeetsDescription_MatchLabels(t *testing.T) { +// resourceName := "test-config-map" +// resourceDescription := types.ResourceDescription{ +// Kinds: []string{"ConfigMap"}, +// Name: &resourceName, +// Selector: &metav1.LabelSelector{ +// MatchLabels: map[string]string{ +// "label1": "test1", +// "label2": "test2", +// }, +// MatchExpressions: nil, +// }, +// } +// groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} +// excludeResourcesResourceDesc := types.ResourceDescription{} - rawResource := []byte(`{ - "metadata":{ - "name":"test-config-map", - "namespace":"default", - "creationTimestamp":null, - "labels":{ - "label1":"test1", - "label2":"test2" - } - } - }`) - assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// rawResource := []byte(`{ +// "metadata":{ +// "name":"test-config-map", +// "namespace":"default", +// "creationTimestamp":null, +// "labels":{ +// "label1":"test1", +// "label2":"test2" +// } +// } +// }`) +// assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) - rawResource = []byte(`{ - "metadata":{ - "name":"test-config-map", - "namespace":"default", - "creationTimestamp":null, - "labels":{ - "label3":"test1", - "label2":"test2" - } - } - }`) - assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// rawResource = []byte(`{ +// "metadata":{ +// "name":"test-config-map", +// "namespace":"default", +// "creationTimestamp":null, +// "labels":{ +// "label3":"test1", +// "label2":"test2" +// } +// } +// }`) +// assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) - resourceDescription = types.ResourceDescription{ - Kinds: []string{"ConfigMap"}, - Name: &resourceName, - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "label3": "test1", - "label2": "test2", - }, - MatchExpressions: nil, - }, - } +// resourceDescription = types.ResourceDescription{ +// Kinds: []string{"ConfigMap"}, +// Name: &resourceName, +// Selector: &metav1.LabelSelector{ +// MatchLabels: map[string]string{ +// "label3": "test1", +// "label2": "test2", +// }, +// MatchExpressions: nil, +// }, +// } - assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) -} +// assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// } -func TestResourceMeetsDescription_MatchLabelsAndMatchExpressions(t *testing.T) { - resourceName := "test-config-map" - resourceDescription := types.ResourceDescription{ - Kinds: []string{"ConfigMap"}, - Name: &resourceName, - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "label1": "test1", - }, - MatchExpressions: []metav1.LabelSelectorRequirement{ - metav1.LabelSelectorRequirement{ - Key: "label2", - Operator: "In", - Values: []string{ - "test2", - }, - }, - }, - }, - } - groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} - excludeResourcesResourceDesc := types.ResourceDescription{} +// func TestResourceMeetsDescription_MatchLabelsAndMatchExpressions(t *testing.T) { +// resourceName := "test-config-map" +// resourceDescription := types.ResourceDescription{ +// Kinds: []string{"ConfigMap"}, +// Name: &resourceName, +// Selector: &metav1.LabelSelector{ +// MatchLabels: map[string]string{ +// "label1": "test1", +// }, +// MatchExpressions: []metav1.LabelSelectorRequirement{ +// metav1.LabelSelectorRequirement{ +// Key: "label2", +// Operator: "In", +// Values: []string{ +// "test2", +// }, +// }, +// }, +// }, +// } +// groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} +// excludeResourcesResourceDesc := types.ResourceDescription{} - rawResource := []byte(`{ - "metadata":{ - "name":"test-config-map", - "namespace":"default", - "creationTimestamp":null, - "labels":{ - "label1":"test1", - "label2":"test2" - } - } - }`) +// rawResource := []byte(`{ +// "metadata":{ +// "name":"test-config-map", +// "namespace":"default", +// "creationTimestamp":null, +// "labels":{ +// "label1":"test1", +// "label2":"test2" +// } +// } +// }`) - assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) - resourceDescription = types.ResourceDescription{ - Kinds: []string{"ConfigMap"}, - Name: &resourceName, - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "label1": "test1", - }, - MatchExpressions: []metav1.LabelSelectorRequirement{ - metav1.LabelSelectorRequirement{ - Key: "label2", - Operator: "NotIn", - Values: []string{ - "sometest1", - }, - }, - }, - }, - } +// resourceDescription = types.ResourceDescription{ +// Kinds: []string{"ConfigMap"}, +// Name: &resourceName, +// Selector: &metav1.LabelSelector{ +// MatchLabels: map[string]string{ +// "label1": "test1", +// }, +// MatchExpressions: []metav1.LabelSelectorRequirement{ +// metav1.LabelSelectorRequirement{ +// Key: "label2", +// Operator: "NotIn", +// Values: []string{ +// "sometest1", +// }, +// }, +// }, +// }, +// } - rawResource = []byte(`{ - "metadata":{ - "name":"test-config-map", - "namespace":"default", - "creationTimestamp":null, - "labels":{ - "label1":"test1", - "label2":"test2" - } - } - }`) - assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// rawResource = []byte(`{ +// "metadata":{ +// "name":"test-config-map", +// "namespace":"default", +// "creationTimestamp":null, +// "labels":{ +// "label1":"test1", +// "label2":"test2" +// } +// } +// }`) +// assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) - resourceDescription = types.ResourceDescription{ - Kinds: []string{"ConfigMap"}, - Name: &resourceName, - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "label1": "test1", - }, - MatchExpressions: []metav1.LabelSelectorRequirement{ - metav1.LabelSelectorRequirement{ - Key: "label2", - Operator: "In", - Values: []string{ - "sometest1", - }, - }, - }, - }, - } +// resourceDescription = types.ResourceDescription{ +// Kinds: []string{"ConfigMap"}, +// Name: &resourceName, +// Selector: &metav1.LabelSelector{ +// MatchLabels: map[string]string{ +// "label1": "test1", +// }, +// MatchExpressions: []metav1.LabelSelectorRequirement{ +// metav1.LabelSelectorRequirement{ +// Key: "label2", +// Operator: "In", +// Values: []string{ +// "sometest1", +// }, +// }, +// }, +// }, +// } - assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) - resourceDescription = types.ResourceDescription{ - Kinds: []string{"ConfigMap"}, - Name: &resourceName, - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "label1": "test1", - "label3": "test3", - }, - MatchExpressions: []metav1.LabelSelectorRequirement{ - metav1.LabelSelectorRequirement{ - Key: "label2", - Operator: "In", - Values: []string{ - "test2", - }, - }, - }, - }, - } +// resourceDescription = types.ResourceDescription{ +// Kinds: []string{"ConfigMap"}, +// Name: &resourceName, +// Selector: &metav1.LabelSelector{ +// MatchLabels: map[string]string{ +// "label1": "test1", +// "label3": "test3", +// }, +// MatchExpressions: []metav1.LabelSelectorRequirement{ +// metav1.LabelSelectorRequirement{ +// Key: "label2", +// Operator: "In", +// Values: []string{ +// "test2", +// }, +// }, +// }, +// }, +// } - assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) -} +// assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind)) +// } func TestWrappedWithParentheses_StringIsWrappedWithParentheses(t *testing.T) { str := "(something)" diff --git a/pkg/policy/existing.go b/pkg/policy/existing.go index b61ec78fd5..cf376dfc92 100644 --- a/pkg/policy/existing.go +++ b/pkg/policy/existing.go @@ -64,16 +64,15 @@ func listResources(client *client.Client, policy kyverno.Policy, filterK8Resourc glog.V(4).Infof("skipping processing policy %s rule %s for kind Namespace", policy.Name, rule.Name) continue } - //TODO: if namespace is not define can we default to * - if rule.MatchResources.Namespace != "" { - namespaces = append(namespaces, rule.MatchResources.Namespace) + if len(rule.MatchResources.Namespaces) > 0 { + namespaces = append(namespaces, rule.MatchResources.Namespaces...) } else { glog.V(4).Infof("processing policy %s rule %s, namespace not defined, getting all namespaces ", policy.Name, rule.Name) // get all namespaces namespaces = getAllNamespaces(client) } // check if exclude namespace is not clashing - namespaces = excludeNamespaces(namespaces, rule.ExcludeResources.Namespace) + namespaces = excludeNamespaces(namespaces, rule.ExcludeResources.Namespaces) // get resources in the namespaces for _, ns := range namespaces { @@ -158,13 +157,13 @@ func kindIsExcluded(kind string, list []string) bool { return false } -func excludeNamespaces(namespaces []string, excludeNs string) []string { - if excludeNs == "" { +func excludeNamespaces(namespaces, excludeNs []string) []string { + if len(excludeNs) == 0 { return namespaces } filteredNamespaces := []string{} for _, n := range namespaces { - if n == excludeNs { + if utils.Contains(excludeNs, n) { continue } filteredNamespaces = append(filteredNamespaces, n) diff --git a/pkg/webhooks/mutation.go b/pkg/webhooks/mutation.go index 64e7e94128..a5e5482762 100644 --- a/pkg/webhooks/mutation.go +++ b/pkg/webhooks/mutation.go @@ -4,6 +4,7 @@ import ( "github.com/golang/glog" engine "github.com/nirmata/kyverno/pkg/engine" "github.com/nirmata/kyverno/pkg/info" + "github.com/nirmata/kyverno/pkg/utils" v1beta1 "k8s.io/api/admission/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -42,7 +43,7 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be for _, policy := range policies { // check if policy has a rule for the admission request kind - if !StringInSlice(request.Kind.Kind, getApplicableKindsForPolicy(policy)) { + if !utils.Contains(getApplicableKindsForPolicy(policy), request.Kind.Kind) { continue } policyInfo := info.NewPolicyInfo(policy.Name, resource.GetKind(), resource.GetName(), resource.GetNamespace(), policy.Spec.ValidationFailureAction) diff --git a/pkg/webhooks/utils.go b/pkg/webhooks/utils.go index 7d6d9b5df2..e2406ac229 100644 --- a/pkg/webhooks/utils.go +++ b/pkg/webhooks/utils.go @@ -27,16 +27,6 @@ func isAdmSuccesful(policyInfos []info.PolicyInfo) (bool, string) { return admSuccess, strings.Join(errMsgs, ";") } -//StringInSlice checks if string is present in slice of strings -func StringInSlice(kind string, list []string) bool { - for _, b := range list { - if b == kind { - return true - } - } - return false -} - //ArrayFlags to store filterkinds type ArrayFlags []string diff --git a/pkg/webhooks/validation.go b/pkg/webhooks/validation.go index 2e67548949..cf5c04d64f 100644 --- a/pkg/webhooks/validation.go +++ b/pkg/webhooks/validation.go @@ -5,6 +5,7 @@ import ( engine "github.com/nirmata/kyverno/pkg/engine" "github.com/nirmata/kyverno/pkg/info" "github.com/nirmata/kyverno/pkg/policyviolation" + "github.com/nirmata/kyverno/pkg/utils" v1beta1 "k8s.io/api/admission/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -42,7 +43,7 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1 for _, policy := range policies { - if !StringInSlice(request.Kind.Kind, getApplicableKindsForPolicy(policy)) { + if !utils.Contains(getApplicableKindsForPolicy(policy), request.Kind.Kind) { continue }