From 302090cd86e0e90c99101dff1ed068616f354677 Mon Sep 17 00:00:00 2001 From: Maxim Goncharenko Date: Tue, 21 May 2019 18:27:56 +0300 Subject: [PATCH 01/19] Implemented base for Mutation Overlay --- pkg/engine/mutation.go | 13 +-- pkg/engine/mutation/overlay.go | 6 - pkg/engine/overlay.go | 133 ++++++++++++++++++++++ pkg/engine/overlay_test.go | 11 ++ pkg/engine/{mutation => }/patches.go | 2 +- pkg/engine/{mutation => }/patches_test.go | 2 +- pkg/engine/utils.go | 12 ++ pkg/engine/validation.go | 21 +--- pkg/engine/validation_test.go | 6 +- pkg/webhooks/server.go | 5 +- 10 files changed, 171 insertions(+), 40 deletions(-) delete mode 100644 pkg/engine/mutation/overlay.go create mode 100644 pkg/engine/overlay.go create mode 100644 pkg/engine/overlay_test.go rename pkg/engine/{mutation => }/patches.go (99%) rename pkg/engine/{mutation => }/patches_test.go (99%) diff --git a/pkg/engine/mutation.go b/pkg/engine/mutation.go index 1474c4364f..02bdfdeb9a 100644 --- a/pkg/engine/mutation.go +++ b/pkg/engine/mutation.go @@ -4,15 +4,14 @@ import ( "log" kubepolicy "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1" - "github.com/nirmata/kube-policy/pkg/engine/mutation" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // Mutate performs mutation. Overlay first and then mutation patches // TODO: return events and violations -func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) ([]mutation.PatchBytes, []byte) { - var policyPatches []mutation.PatchBytes - var processedPatches []mutation.PatchBytes +func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) ([]PatchBytes, []byte) { + var policyPatches []PatchBytes + var processedPatches []PatchBytes var err error patchedDocument := rawResource @@ -30,18 +29,18 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio // Process Overlay if rule.Mutation.Overlay != nil { - overlayPatches, err := mutation.ProcessOverlay(rule.Mutation.Overlay, rawResource) + //overlayPatches, err := ProcessOverlay(rule.Mutation.Overlay, rawResource) if err != nil { log.Printf("Overlay application has failed for rule %s in policy %s, err: %v\n", rule.Name, policy.ObjectMeta.Name, err) } else { - policyPatches = append(policyPatches, overlayPatches...) + //policyPatches = append(policyPatches, overlayPatches...) } } // Process Patches if rule.Mutation.Patches != nil { - processedPatches, patchedDocument, err = mutation.ProcessPatches(rule.Mutation.Patches, patchedDocument) + processedPatches, patchedDocument, err = ProcessPatches(rule.Mutation.Patches, patchedDocument) if err != nil { log.Printf("Patches application has failed for rule %s in policy %s, err: %v\n", rule.Name, policy.ObjectMeta.Name, err) } else { diff --git a/pkg/engine/mutation/overlay.go b/pkg/engine/mutation/overlay.go deleted file mode 100644 index 308596e1bc..0000000000 --- a/pkg/engine/mutation/overlay.go +++ /dev/null @@ -1,6 +0,0 @@ -package mutation - -func ProcessOverlay(overlay interface{}, rawResource []byte) ([]PatchBytes, error) { - // TODO: Overlay to be implemented - return nil, nil -} diff --git a/pkg/engine/overlay.go b/pkg/engine/overlay.go new file mode 100644 index 0000000000..4bac976dc3 --- /dev/null +++ b/pkg/engine/overlay.go @@ -0,0 +1,133 @@ +package engine + +import ( + "encoding/json" + "fmt" + "log" + "strconv" + + kubepolicy "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ProcessOverlay handles validating admission request +// Checks the target resourse for rules defined in the policy +func ProcessOverlay(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) ([]PatchBytes, []byte) { + var resource interface{} + json.Unmarshal(rawResource, &resource) + + for _, rule := range policy.Spec.Rules { + if rule.Mutation == nil || rule.Mutation.Overlay == nil { + continue + } + + ok := ResourceMeetsDescription(rawResource, rule.ResourceDescription, gvk) + if !ok { + log.Printf("Rule \"%s\" is not applicable to resource\n", rule.Name) + continue + } + + overlay := *rule.Mutation.Overlay + if err, _ := applyOverlay(resource, overlay, ""); err != nil { + //return fmt.Errorf("%s: %s", *rule.Validation.Message, err.Error()) + } + } + + return nil, nil +} + +func applyOverlay(resource, overlay interface{}, path string) ([]PatchBytes, error) { + switch typedOverlay := overlay.(type) { + case map[string]interface{}: + typedResource := resource.(map[string]interface{}) + + for key, value := range typedOverlay { + path += "/" + key + resourcePart, ok := typedResource[key] + + if ok { + applyOverlay(resourcePart, value, path) + } else { + createSubtree(value, path) + } + } + case []interface{}: + typedResource := resource.([]interface{}) + applyOverlayToArray(typedResource, typedOverlay, path) + case string: + typedResource, ok := resource.(string) + if !ok { + return nil, fmt.Errorf("Expected string, found %T", resource) + } + replaceResource(typedResource, typedOverlay, path) + case float64: + typedResource, ok := resource.(float64) + if !ok { + return nil, fmt.Errorf("Expected string, found %T", resource) + } + replaceResource(typedResource, typedOverlay, path) + case int64: + typedResource, ok := resource.(int64) + if !ok { + return nil, fmt.Errorf("Expected string, found %T", resource) + } + replaceResource(typedResource, typedOverlay, path) + } + + return nil, nil +} + +func applyOverlayToArray(resource, overlay []interface{}, path string) { + switch overlay[0].(type) { + case map[string]interface{}: + for _, overlayElement := range overlay { + typedOverlay := overlayElement.(map[string]interface{}) + + anchors := GetAnchorsFromMap(typedOverlay) + + if len(anchors) > 0 { + // Try to replace + for i, resourceElement := range resource { + path += "/" + strconv.Itoa(i) + typedResource := resourceElement.(map[string]interface{}) + if !skipArrayObject(typedResource, anchors) { + replaceResource(typedResource, typedOverlay, path) + } + } + } else { + // Add new item to the front + path += "/0" + createSubtree(typedOverlay, path) + } + } + default: + path += "/0" + for _, value := range overlay { + createSubtree(value, path) + } + } +} + +func skipArrayObject(object, anchors map[string]interface{}) bool { + for key, pattern := range anchors { + key = key[1 : len(key)-1] + + value, ok := object[key] + if !ok { + return true + } + + return value != pattern + } + + return false +} + +func replaceResource(resource, overlay interface{}, path string) { + +} + +func createSubtree(overlayPart interface{}, path string) []PatchBytes { + + return nil +} diff --git a/pkg/engine/overlay_test.go b/pkg/engine/overlay_test.go new file mode 100644 index 0000000000..a35f183ae6 --- /dev/null +++ b/pkg/engine/overlay_test.go @@ -0,0 +1,11 @@ +package engine + +import ( + "testing" + + "gotest.tools/assert" +) + +func TestApplyOverlay_BaseCase(t *testing.T) { + assert.Assert(t, true) +} diff --git a/pkg/engine/mutation/patches.go b/pkg/engine/patches.go similarity index 99% rename from pkg/engine/mutation/patches.go rename to pkg/engine/patches.go index 068125c4fa..0d56a08432 100644 --- a/pkg/engine/mutation/patches.go +++ b/pkg/engine/patches.go @@ -1,4 +1,4 @@ -package mutation +package engine import ( "encoding/json" diff --git a/pkg/engine/mutation/patches_test.go b/pkg/engine/patches_test.go similarity index 99% rename from pkg/engine/mutation/patches_test.go rename to pkg/engine/patches_test.go index e4d26e5a1a..ea27ec77c3 100644 --- a/pkg/engine/mutation/patches_test.go +++ b/pkg/engine/patches_test.go @@ -1,4 +1,4 @@ -package mutation +package engine import ( "testing" diff --git a/pkg/engine/utils.go b/pkg/engine/utils.go index 0646bf33e3..40fb634b2b 100644 --- a/pkg/engine/utils.go +++ b/pkg/engine/utils.go @@ -104,3 +104,15 @@ func ParseRegexPolicyResourceName(policyResourceName string) (string, bool) { } return strings.Trim(regex[1], " "), true } + +func GetAnchorsFromMap(anchorsMap map[string]interface{}) map[string]interface{} { + result := make(map[string]interface{}) + + for key, value := range anchorsMap { + if wrappedWithParentheses(key) { + result[key] = value + } + } + + return result +} diff --git a/pkg/engine/validation.go b/pkg/engine/validation.go index c3f4d788cd..63e7f97e25 100644 --- a/pkg/engine/validation.go +++ b/pkg/engine/validation.go @@ -96,10 +96,7 @@ func validateArray(resourcePart, patternPart interface{}) error { switch pattern := patternArray[0].(type) { case map[string]interface{}: - anchors, err := getAnchorsFromMap(pattern) - if err != nil { - return err - } + anchors := GetAnchorsFromMap(pattern) for _, value := range resourceArray { resource, ok := value.(map[string]interface{}) @@ -107,7 +104,7 @@ func validateArray(resourcePart, patternPart interface{}) error { return fmt.Errorf("expected array, found %T", resourcePart) } - if skipArrayObject(resource, anchors) { + if skipValidatingObject(resource, anchors) { continue } @@ -177,19 +174,7 @@ func validateMapElement(resourcePart, patternPart interface{}) error { return nil } -func getAnchorsFromMap(pattern map[string]interface{}) (map[string]interface{}, error) { - result := make(map[string]interface{}) - - for key, value := range pattern { - if wrappedWithParentheses(key) { - result[key] = value - } - } - - return result, nil -} - -func skipArrayObject(object, anchors map[string]interface{}) bool { +func skipValidatingObject(object, anchors map[string]interface{}) bool { for key, pattern := range anchors { key = key[1 : len(key)-1] diff --git a/pkg/engine/validation_test.go b/pkg/engine/validation_test.go index eac1a884bf..3f3f483c8e 100644 --- a/pkg/engine/validation_test.go +++ b/pkg/engine/validation_test.go @@ -306,8 +306,7 @@ func TestGetAnchorsFromMap_ThereAreAnchors(t *testing.T) { var unmarshalled map[string]interface{} json.Unmarshal(rawMap, &unmarshalled) - actualMap, err := getAnchorsFromMap(unmarshalled) - assert.NilError(t, err) + actualMap := GetAnchorsFromMap(unmarshalled) assert.Equal(t, len(actualMap), 2) assert.Equal(t, actualMap["(name)"].(string), "nirmata-*") assert.Equal(t, actualMap["(namespace)"].(string), "kube-?olicy") @@ -319,8 +318,7 @@ func TestGetAnchorsFromMap_ThereAreNoAnchors(t *testing.T) { var unmarshalled map[string]interface{} json.Unmarshal(rawMap, &unmarshalled) - actualMap, err := getAnchorsFromMap(unmarshalled) - assert.NilError(t, err) + actualMap := GetAnchorsFromMap(unmarshalled) assert.Assert(t, len(actualMap) == 0) } diff --git a/pkg/webhooks/server.go b/pkg/webhooks/server.go index 209c9d4b7f..cd7c6e0499 100644 --- a/pkg/webhooks/server.go +++ b/pkg/webhooks/server.go @@ -16,7 +16,6 @@ import ( policylister "github.com/nirmata/kube-policy/pkg/client/listers/policy/v1alpha1" "github.com/nirmata/kube-policy/pkg/config" engine "github.com/nirmata/kube-policy/pkg/engine" - "github.com/nirmata/kube-policy/pkg/engine/mutation" tlsutils "github.com/nirmata/kube-policy/pkg/tls" v1beta1 "k8s.io/api/admission/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -143,7 +142,7 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be return nil } - var allPatches []mutation.PatchBytes + var allPatches []engine.PatchBytes for _, policy := range policies { ws.logger.Printf("Applying policy %s with %d rules\n", policy.ObjectMeta.Name, len(policy.Spec.Rules)) @@ -160,7 +159,7 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be patchType := v1beta1.PatchTypeJSONPatch return &v1beta1.AdmissionResponse{ Allowed: true, - Patch: mutation.JoinPatches(allPatches), + Patch: engine.JoinPatches(allPatches), PatchType: &patchType, } } From 31ce0875047c8474172a6351bc6d162fad727714 Mon Sep 17 00:00:00 2001 From: shivdudhani Date: Tue, 21 May 2019 15:43:43 -0700 Subject: [PATCH 02/19] support list of kind in resource, update the CRD openapischema & adapt the test and examples for the change --- definitions/install.yaml | 46 ++++++++++--------- examples/Validate/check_cpu_memory.yaml | 8 ++-- examples/Validate/check_hostpath.yaml | 5 +- examples/Validate/check_image_version.yaml | 5 +- examples/Validate/check_nodeport.yaml | 5 +- examples/Validate/check_probe_exists.yaml | 14 +++--- examples/Validate/check_probe_intervals.yaml | 9 ++-- .../Validate/check_whitelist_registries.yaml | 5 +- pkg/apis/policy/v1alpha1/types.go | 2 +- pkg/apis/policy/v1alpha1/utils.go | 8 ++-- pkg/apis/policy/v1alpha1/utils_test.go | 6 +-- pkg/engine/utils.go | 11 ++++- test/ConfigMap/policy-CM.yaml | 12 +++-- .../policy-cm-test.yaml | 5 +- .../policy-namespace-patch-cmgCG-sgCG.yaml | 23 ++++++---- test/CronJob/policy-cronjob-wldcrd.yaml | 7 +-- test/DaemonSet/policy-daemonset.yaml | 3 +- test/Deployment/policy-deployment-any.yaml | 4 +- test/Endpoint/policy-endpoints.yaml | 5 +- test/HorizontalPodAutoscaler/policy-hpa.yaml | 3 +- test/Ingress/policy-ingress.yaml | 3 +- test/Job/policy-job.yaml | 3 +- test/LimitRange/policy-limitrange.yaml | 5 +- test/Namespace/policy-namespace.yaml | 3 +- test/NetworkPolicy/policy-network-policy.yaml | 3 +- test/PersistentVolumeClaim/policy-PVC.yaml | 3 +- test/PodDisruptionBudget/policy-pdb.yaml | 3 +- test/PodTemplate/policy-PodTemplate.yaml | 3 +- .../policy-quota-validation.yaml | 15 +++--- test/ResourceQuota/policy-quota.yaml | 5 +- test/Secret/policy-secret.yaml | 3 +- test/Service/policy-service.yaml | 3 +- test/StatefulSet/policy-StatefulSet.yaml | 3 +- 33 files changed, 145 insertions(+), 96 deletions(-) diff --git a/definitions/install.yaml b/definitions/install.yaml index f23e12fad3..dd83e9fdb2 100644 --- a/definitions/install.yaml +++ b/definitions/install.yaml @@ -35,29 +35,31 @@ spec: resource: type: object required: - - kind + - kinds properties: - kind: - type: string - enum: - - ConfigMap - - CronJob - - DaemonSet - - Deployment - - Endpoints - - HorizontalPodAutoscaler - - Ingress - - Job - - LimitRange - - Namespace - - NetworkPolicy - - PersistentVolumeClaim - - PodDisruptionBudget - - PodTemplate - - ResourceQuota - - Secret - - Service - - StatefulSet + kinds: + type: array + items: + type: string + enum: + - ConfigMap + - CronJob + - DaemonSet + - Deployment + - Endpoints + - HorizontalPodAutoscaler + - Ingress + - Job + - LimitRange + - Namespace + - NetworkPolicy + - PersistentVolumeClaim + - PodDisruptionBudget + - PodTemplate + - ResourceQuota + - Secret + - Service + - StatefulSet name: type: string selector: diff --git a/examples/Validate/check_cpu_memory.yaml b/examples/Validate/check_cpu_memory.yaml index 61ab1d2b70..88b800d27d 100644 --- a/examples/Validate/check_cpu_memory.yaml +++ b/examples/Validate/check_cpu_memory.yaml @@ -1,4 +1,4 @@ -apiVersion: policy.nirmata.io/v1alpha1 +apiVersion : kubepolicy.nirmata.io/v1alpha1 kind: Policy metadata: name: check-cpu-memory @@ -6,7 +6,8 @@ spec: rules: - name: check-defined resource: - kind: Deployment + kinds: + - Deployment validate: message: "Resource requests and limits are required for CPU and memory" pattern: @@ -22,7 +23,8 @@ spec: cpu: "?" - name: check-memory-in-range resource: - kind: Deployment + kinds: + - Deployment validate: message: "Memory request cannot be greater than 10Gi" pattern: diff --git a/examples/Validate/check_hostpath.yaml b/examples/Validate/check_hostpath.yaml index 8ebe1d7817..db91e4c35a 100644 --- a/examples/Validate/check_hostpath.yaml +++ b/examples/Validate/check_hostpath.yaml @@ -1,4 +1,4 @@ -apiVersion: policy.nirmata.io/v1alpha1 +apiVersion : kubepolicy.nirmata.io/v1alpha1 kind: Policy metadata: name: check-host-path @@ -6,7 +6,8 @@ spec: rules: - name: check-host-path resource: - kind: Pod + kinds: + - Pod validate: message: "Host path volumes are not allowed" pattern: diff --git a/examples/Validate/check_image_version.yaml b/examples/Validate/check_image_version.yaml index e71335499e..3529c1cd26 100644 --- a/examples/Validate/check_image_version.yaml +++ b/examples/Validate/check_image_version.yaml @@ -1,4 +1,4 @@ -apiVersion: policy.nirmata.io/v1alpha1 +apiVersion : kubepolicy.nirmata.io/v1alpha1 kind: Policy metadata: name: image-pull-policy @@ -7,7 +7,8 @@ spec: - name: image-pull-policy message: "Image tag ':latest' requires imagePullPolicy 'Always'" resource: - kind: Deployment + kinds: + - Deployment overlay: template: spec: diff --git a/examples/Validate/check_nodeport.yaml b/examples/Validate/check_nodeport.yaml index 1a5fd25c05..0277405364 100644 --- a/examples/Validate/check_nodeport.yaml +++ b/examples/Validate/check_nodeport.yaml @@ -1,4 +1,4 @@ -apiVersion: policy.nirmata.io/v1alpha1 +apiVersion : kubepolicy.nirmata.io/v1alpha1 kind: Policy metadata: name: check-host-path @@ -6,7 +6,8 @@ spec: rules: - name: check-host-path resource: - kind: Service + kinds: + - Service validate: message: "Node port services are not allowed" pattern: diff --git a/examples/Validate/check_probe_exists.yaml b/examples/Validate/check_probe_exists.yaml index d055455bf5..7a1e30edcc 100644 --- a/examples/Validate/check_probe_exists.yaml +++ b/examples/Validate/check_probe_exists.yaml @@ -1,4 +1,4 @@ -apiVersion: policy.nirmata.io/v1alpha1 +apiVersion: kubepolicy.nirmata.io/v1alpha1 kind: Policy metadata: name: check-probe-exists @@ -6,7 +6,8 @@ spec: rules: - name: check-liveness-probe-exists resource: - kind: StatefulSet + kinds: + - StatefulSet validate: message: "a livenessProbe is required" pattern: @@ -14,10 +15,11 @@ spec: # In this case every object in containers list will be checked for pattern - name: "*" livenessProbe: - periodSeconds: ? + periodSeconds: "?" - resource: - kind: Deployment - name: check-readiness-probe-exists + kinds: + - Deployment + name: check-readinessprobe-exists validate: message: "a readinessProbe is required" pattern: @@ -25,4 +27,4 @@ spec: # In this case every object in containers list will be checked for pattern - name: "*" readinessProbe: - periodSeconds: ? + periodSeconds: "?" diff --git a/examples/Validate/check_probe_intervals.yaml b/examples/Validate/check_probe_intervals.yaml index 77bc50b9ce..c2e25aa78e 100644 --- a/examples/Validate/check_probe_intervals.yaml +++ b/examples/Validate/check_probe_intervals.yaml @@ -1,4 +1,4 @@ -apiVersion: policy.nirmata.io/v1alpha1 +apiVersion : kubepolicy.nirmata.io/v1alpha1 kind: Policy metadata: name: check-probe-intervals @@ -6,7 +6,8 @@ spec: rules: - name: check-probe-intervals resource: - kind: Deployment + kinds: + - Deployment validate: message: "livenessProbe must be > 10s" pattern: @@ -16,7 +17,9 @@ spec: livenessProbe: periodSeconds: ">10" - resource: - kind: Deployment + kinds: + - Deployment + name: check-readinessprobe-intervals validate: pattern: message: "readinessProbe must be > 10s" diff --git a/examples/Validate/check_whitelist_registries.yaml b/examples/Validate/check_whitelist_registries.yaml index 79aceab2e0..6875dd3ea2 100644 --- a/examples/Validate/check_whitelist_registries.yaml +++ b/examples/Validate/check_whitelist_registries.yaml @@ -1,4 +1,4 @@ -apiVersion: policy.nirmata.io/v1alpha1 +apiVersion : kubepolicy.nirmata.io/v1alpha1 kind: Policy metadata: name: check-whitelist-registries @@ -7,7 +7,8 @@ spec: - name: check-whitelist-registries message: "Registry is not allowed" resource: - kind: Deployment + kinds: + - Deployment validate: pattern: template: diff --git a/pkg/apis/policy/v1alpha1/types.go b/pkg/apis/policy/v1alpha1/types.go index 0e4374494c..12c0f7c9dd 100644 --- a/pkg/apis/policy/v1alpha1/types.go +++ b/pkg/apis/policy/v1alpha1/types.go @@ -33,7 +33,7 @@ type Rule struct { // ResourceDescription describes the resource to which the PolicyRule will be applied. type ResourceDescription struct { - Kind string `json:"kind"` + Kinds []string `json:"kinds"` Name *string `json:"name"` Selector *metav1.LabelSelector `json:"selector"` } diff --git a/pkg/apis/policy/v1alpha1/utils.go b/pkg/apis/policy/v1alpha1/utils.go index 65719ba360..3fe4bf570b 100644 --- a/pkg/apis/policy/v1alpha1/utils.go +++ b/pkg/apis/policy/v1alpha1/utils.go @@ -22,13 +22,11 @@ func (r *Rule) Validate() error { } // Validate checks if all necesarry fields are present and have values. Also checks a Selector. -// Returns error if resource definition is invalid. +// Returns error if +// - kinds is not defined func (pr *ResourceDescription) Validate() error { - // TBD: selector or name MUST be specified - if pr.Kind == "" { + if len(pr.Kinds) == 0 { return errors.New("The Kind is not specified") - } else if pr.Name == nil && pr.Selector == nil { - return errors.New("Neither Name nor Selector is specified") } if pr.Selector != nil { diff --git a/pkg/apis/policy/v1alpha1/utils_test.go b/pkg/apis/policy/v1alpha1/utils_test.go index 2d050ce3dc..867cfd729e 100644 --- a/pkg/apis/policy/v1alpha1/utils_test.go +++ b/pkg/apis/policy/v1alpha1/utils_test.go @@ -9,8 +9,8 @@ import ( var defaultResourceDescriptionName = "defaultResourceDescription" var defaultResourceDescription = ResourceDescription{ - Kind: "Deployment", - Name: &defaultResourceDescriptionName, + Kinds: []string{"Deployment"}, + Name: &defaultResourceDescriptionName, Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{"LabelForSelector": "defaultResourceDescription"}, }, @@ -43,7 +43,7 @@ func Test_ResourceDescription_EmptyKind(t *testing.T) { func Test_ResourceDescription_EmptyNameAndSelector(t *testing.T) { resourceDescription := ResourceDescription{ - Kind: "Deployment", + Kinds: []string{"Deployment"}, } err := resourceDescription.Validate() assert.Assert(t, err != nil) diff --git a/pkg/engine/utils.go b/pkg/engine/utils.go index f13f501f4d..0ba32f8949 100644 --- a/pkg/engine/utils.go +++ b/pkg/engine/utils.go @@ -13,7 +13,7 @@ import ( // ResourceMeetsDescription checks requests kind, name and labels to fit the policy rule func ResourceMeetsDescription(resourceRaw []byte, description kubepolicy.ResourceDescription, gvk metav1.GroupVersionKind) bool { - if description.Kind != gvk.Kind { + if !findKind(description.Kinds, gvk.Kind) { return false } @@ -104,3 +104,12 @@ func ParseRegexPolicyResourceName(policyResourceName string) (string, bool) { } return strings.Trim(regex[1], " "), true } + +func findKind(kinds []string, kindGVK string) bool { + for _, kind := range kinds { + if kind == kindGVK { + return true + } + } + return false +} diff --git a/test/ConfigMap/policy-CM.yaml b/test/ConfigMap/policy-CM.yaml index 843ff23f7e..e48ad9d4fa 100644 --- a/test/ConfigMap/policy-CM.yaml +++ b/test/ConfigMap/policy-CM.yaml @@ -6,7 +6,8 @@ spec : rules: - name: pCM1 resource: - kind : ConfigMap + kinds : + - ConfigMap name: "game-config" mutate: patches: @@ -15,7 +16,8 @@ spec : value : newValue - name: pCM2 resource: - kind : ConfigMap + kinds : + - ConfigMap name: "game-config" mutate: patches: @@ -26,7 +28,8 @@ spec : value : "data is replaced" - name: pCM3 resource: - kind : ConfigMap + kinds : + - ConfigMap name: "game-config" mutate: patches: @@ -40,7 +43,8 @@ spec : game.properties: "*enemies=aliens*" - name: pCM4 resource: - kind : ConfigMap + kinds : + - ConfigMap name: "game-config" validate: message: "This CM data is broken because it does not have ui.properties" diff --git a/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml b/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml index 3a0ce26477..84af6b62fb 100644 --- a/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml +++ b/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml @@ -6,12 +6,13 @@ spec: rules: - name: "copyCM" resource : - kind : Namespace + kinds : + - Namespace selector: matchLabels: LabelForSelector : "namespace2" generate : - kind: ConfigMap + - kind: ConfigMap name : copied-cm copyFrom : namespace : default diff --git a/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml b/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml index 56e21a4598..07ee04a2b8 100644 --- a/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml +++ b/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml @@ -11,7 +11,8 @@ spec : rules: - name: "patchNamespace2" resource : - kind : Namespace + kinds : + - Namespace selector: matchLabels: LabelForSelector : "namespace2" @@ -23,12 +24,13 @@ spec : - name: "copyCM" resource : - kind : Namespace + kinds : + - Namespace selector: matchLabels: LabelForSelector : "namespace2" generate : - kind: ConfigMap + - kind: ConfigMap name : copied-cm copyFrom : namespace : default @@ -38,12 +40,13 @@ spec : - name: "generateCM" resource : - kind : Namespace + kinds : + - Namespace selector: matchLabels: LabelForSelector : "namespace2" generate : - kind: ConfigMap + - kind: ConfigMap name : generated-cm data : secretData: "very sensitive data from cmg" @@ -56,10 +59,11 @@ spec : - name: "generateSecret" resource : - kind : Namespace + kinds : + - Namespace name: ns2 generate : - kind: Secret + - kind: Secret name : generated-secrets data : foo : bar @@ -72,10 +76,11 @@ spec : - name: "copySecret" resource : - kind : Namespace + kinds : + - Namespace name: ns2 generate : - kind: Secret + - kind: Secret name : copied-secrets copyFrom : namespace : default diff --git a/test/CronJob/policy-cronjob-wldcrd.yaml b/test/CronJob/policy-cronjob-wldcrd.yaml index 4ef1598c35..1078139d1e 100644 --- a/test/CronJob/policy-cronjob-wldcrd.yaml +++ b/test/CronJob/policy-cronjob-wldcrd.yaml @@ -1,12 +1,13 @@ -apiVersion: kubepolicy.nirmata.io/v1alpha1 +apiVersion : kubepolicy.nirmata.io/v1alpha1 kind: Policy metadata: name: policy-cronjob spec: rules: - - name: + - name: "rule" resource: - kind : CronJob + kinds : + - CronJob name: "?ell*" mutate: patches: diff --git a/test/DaemonSet/policy-daemonset.yaml b/test/DaemonSet/policy-daemonset.yaml index 47912c2795..62087e21d0 100644 --- a/test/DaemonSet/policy-daemonset.yaml +++ b/test/DaemonSet/policy-daemonset.yaml @@ -6,7 +6,8 @@ spec: rules: - name: "Patch and Volume validation" resource: - kind: DaemonSet + kinds: + - DaemonSet name: fluentd-elasticsearch mutate: patches: diff --git a/test/Deployment/policy-deployment-any.yaml b/test/Deployment/policy-deployment-any.yaml index 6a43ec225d..1b3b407e10 100644 --- a/test/Deployment/policy-deployment-any.yaml +++ b/test/Deployment/policy-deployment-any.yaml @@ -6,8 +6,8 @@ spec : rules: - name: "First policy v2" resource: - kind : Deployment - name: nginx-* + kinds : + - Deployment mutate: patches: - path: /metadata/labels/isMutated diff --git a/test/Endpoint/policy-endpoints.yaml b/test/Endpoint/policy-endpoints.yaml index 335573c6ba..55b2b826e9 100644 --- a/test/Endpoint/policy-endpoints.yaml +++ b/test/Endpoint/policy-endpoints.yaml @@ -4,9 +4,10 @@ metadata : name : policy-endpoints spec : rules: - - name: + - name: "rule" resource: - kind : Endpoints + kinds : + - Endpoints selector: matchLabels: label : test diff --git a/test/HorizontalPodAutoscaler/policy-hpa.yaml b/test/HorizontalPodAutoscaler/policy-hpa.yaml index 840c41fc46..a7fe847b9d 100644 --- a/test/HorizontalPodAutoscaler/policy-hpa.yaml +++ b/test/HorizontalPodAutoscaler/policy-hpa.yaml @@ -6,7 +6,8 @@ spec : rules: - name: hpa1 resource: - kind : HorizontalPodAutoscaler + kinds : + - HorizontalPodAutoscaler selector: matchLabels: originalLabel: isHere diff --git a/test/Ingress/policy-ingress.yaml b/test/Ingress/policy-ingress.yaml index e0c2abb1a7..e8eb03b690 100644 --- a/test/Ingress/policy-ingress.yaml +++ b/test/Ingress/policy-ingress.yaml @@ -6,7 +6,8 @@ spec : rules: - name: ingress1 resource: - kind : Ingress + kinds : + - Ingress selector: matchLabels: originalLabel: isHere diff --git a/test/Job/policy-job.yaml b/test/Job/policy-job.yaml index eb023a8bf4..58660646fd 100644 --- a/test/Job/policy-job.yaml +++ b/test/Job/policy-job.yaml @@ -6,7 +6,8 @@ spec : rules: - name: job1 resource: - kind: Job + kinds: + - Job name: pi mutate: patches: diff --git a/test/LimitRange/policy-limitrange.yaml b/test/LimitRange/policy-limitrange.yaml index 79d3c7bf45..c7bc58eac5 100644 --- a/test/LimitRange/policy-limitrange.yaml +++ b/test/LimitRange/policy-limitrange.yaml @@ -4,9 +4,10 @@ metadata : name : policy-limitrange spec : rules: - - name: + - name: "rule" resource: - kind : LimitRange + kinds : + - LimitRange selector: matchLabels: containerSize: minimal diff --git a/test/Namespace/policy-namespace.yaml b/test/Namespace/policy-namespace.yaml index 9ef999212f..5697b22a43 100644 --- a/test/Namespace/policy-namespace.yaml +++ b/test/Namespace/policy-namespace.yaml @@ -7,7 +7,8 @@ spec : rules: - name: ns1 resource: - kind : Namespace + kinds : + - Namespace selector: matchLabels: LabelForSelector : "namespace" diff --git a/test/NetworkPolicy/policy-network-policy.yaml b/test/NetworkPolicy/policy-network-policy.yaml index 3e105c687b..084bda2762 100644 --- a/test/NetworkPolicy/policy-network-policy.yaml +++ b/test/NetworkPolicy/policy-network-policy.yaml @@ -6,7 +6,8 @@ spec: rules: - name: np1 resource: - kind : NetworkPolicy + kinds : + - NetworkPolicy selector: matchLabels: originalLabel: isHere diff --git a/test/PersistentVolumeClaim/policy-PVC.yaml b/test/PersistentVolumeClaim/policy-PVC.yaml index 4a05f586af..47e3c9ace6 100644 --- a/test/PersistentVolumeClaim/policy-PVC.yaml +++ b/test/PersistentVolumeClaim/policy-PVC.yaml @@ -6,7 +6,8 @@ spec: rules: - name: pvc1 resource: - kind : PersistentVolumeClaim + kinds : + - PersistentVolumeClaim matchLabels: originalLabel: isHere mutate: diff --git a/test/PodDisruptionBudget/policy-pdb.yaml b/test/PodDisruptionBudget/policy-pdb.yaml index 736d0199d4..9af46f5fd0 100644 --- a/test/PodDisruptionBudget/policy-pdb.yaml +++ b/test/PodDisruptionBudget/policy-pdb.yaml @@ -6,7 +6,8 @@ spec: rules: - name: pdb1 resource: - kind : PodDisruptionBudget + kinds : + - PodDisruptionBudget name: "game-pdb" mutate: patches: diff --git a/test/PodTemplate/policy-PodTemplate.yaml b/test/PodTemplate/policy-PodTemplate.yaml index dbe7b01e2a..c3c789e082 100644 --- a/test/PodTemplate/policy-PodTemplate.yaml +++ b/test/PodTemplate/policy-PodTemplate.yaml @@ -6,7 +6,8 @@ spec: rules: - name: podtemplate1 resource: - kind : PodTemplate + kinds : + - PodTemplate selector: matchLabels: originalLabel: isHere diff --git a/test/ResourceQuota/policy-quota-validation.yaml b/test/ResourceQuota/policy-quota-validation.yaml index fcf59a5173..e813d7fb07 100644 --- a/test/ResourceQuota/policy-quota-validation.yaml +++ b/test/ResourceQuota/policy-quota-validation.yaml @@ -4,9 +4,10 @@ metadata : name : policy-quota-low-test-validation spec : rules: - - name: + - name: "rule1" resource: - kind : ResourceQuota + kinds : + - ResourceQuota selector: matchLabels: quota: low @@ -16,9 +17,10 @@ spec : spec: hard: memory: "8Gi|12Gi" - - name: + - name: "rule2" resource: - kind : ResourceQuota + kinds : + - ResourceQuota selector: matchLabels: quota: low @@ -28,9 +30,10 @@ spec : spec: hard: cpu: <3 - - name: + - name: "rule3" resource: - kind : ResourceQuota + kinds : + - ResourceQuota selector: matchLabels: quota: low diff --git a/test/ResourceQuota/policy-quota.yaml b/test/ResourceQuota/policy-quota.yaml index 89248787fe..e845eb56fb 100644 --- a/test/ResourceQuota/policy-quota.yaml +++ b/test/ResourceQuota/policy-quota.yaml @@ -4,9 +4,10 @@ metadata : name : policy-quota-low-test spec : rules: - - name: + - name: "rule" resource: - kind : ResourceQuota + kinds : + - ResourceQuota selector: matchLabels: quota: low diff --git a/test/Secret/policy-secret.yaml b/test/Secret/policy-secret.yaml index aeae51ad14..315c374754 100644 --- a/test/Secret/policy-secret.yaml +++ b/test/Secret/policy-secret.yaml @@ -6,7 +6,8 @@ spec: rules: - name: secret1 resource: - kind : Secret + kinds : + - Secret name: "mysecret" mutate: patches: diff --git a/test/Service/policy-service.yaml b/test/Service/policy-service.yaml index c92f4c6d21..8d2feb2200 100644 --- a/test/Service/policy-service.yaml +++ b/test/Service/policy-service.yaml @@ -6,7 +6,8 @@ spec : rules: - name: ps1 resource: - kind: Service + kinds: + - Service name: "game-service*" mutate: patches: diff --git a/test/StatefulSet/policy-StatefulSet.yaml b/test/StatefulSet/policy-StatefulSet.yaml index f9277c6016..71ab13295b 100644 --- a/test/StatefulSet/policy-StatefulSet.yaml +++ b/test/StatefulSet/policy-StatefulSet.yaml @@ -6,7 +6,8 @@ spec: rules: - name: statefulset1 resource: - kind : StatefulSet + kinds : + - StatefulSet selector: matchLabels: originalLabel: isHere From 15ce519cb993da179b68235fa446c0b0c64c5ed4 Mon Sep 17 00:00:00 2001 From: shivdudhani Date: Tue, 21 May 2019 15:49:48 -0700 Subject: [PATCH 03/19] update the example for CLI --- examples/CLI/deployment/policy-deployment.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/CLI/deployment/policy-deployment.yaml b/examples/CLI/deployment/policy-deployment.yaml index ef8ab8b9bf..0bc65723c6 100644 --- a/examples/CLI/deployment/policy-deployment.yaml +++ b/examples/CLI/deployment/policy-deployment.yaml @@ -6,7 +6,8 @@ spec : rules: - name: deployment-policy resource: - kind : Deployment + kinds : + - Deployment selector : matchLabels : cli: test From 09bfdc6ba3915c57c7d411de945540c8a1472ec8 Mon Sep 17 00:00:00 2001 From: shuting Date: Tue, 21 May 2019 18:36:24 -0700 Subject: [PATCH 04/19] - Change kube-policy to kyverno in install.yaml - Install in namespace kyverno --- definitions/MutatingWebhookConfiguration.yaml | 8 ++-- .../MutatingWebhookConfiguration_debug.yaml | 6 +-- definitions/install.yaml | 41 +++++++++++-------- documentation/installation.md | 10 ++--- pkg/apis/policy/register.go | 2 +- pkg/apis/policy/v1alpha1/doc.go | 2 +- pkg/config/config.go | 16 ++++---- pkg/kyverno/apply/apply.go | 2 +- pkg/sharedinformer/sharedinformerfactory.go | 2 +- scripts/README.md | 4 +- scripts/deploy-controller.sh | 4 +- test/README.md | 2 +- 12 files changed, 52 insertions(+), 47 deletions(-) diff --git a/definitions/MutatingWebhookConfiguration.yaml b/definitions/MutatingWebhookConfiguration.yaml index 420ee023d5..a45fc667c8 100644 --- a/definitions/MutatingWebhookConfiguration.yaml +++ b/definitions/MutatingWebhookConfiguration.yaml @@ -3,14 +3,14 @@ apiVersion: admissionregistration.k8s.io/v1beta1 kind: MutatingWebhookConfiguration metadata: - name: nirmata-kube-policy-webhook-cfg + name: nirmata-kyverno-webhook-cfg labels: - app: kube-policy + app: kyverno webhooks: - - name: webhook.nirmata.kube-policy + - name: webhook.nirmata.kyverno clientConfig: service: - name: kube-policy-svc + name: kyverno-svc namespace: default path: "/mutate" caBundle: ${CA_BUNDLE} diff --git a/definitions/MutatingWebhookConfiguration_debug.yaml b/definitions/MutatingWebhookConfiguration_debug.yaml index 713fb9cb40..e3be018429 100644 --- a/definitions/MutatingWebhookConfiguration_debug.yaml +++ b/definitions/MutatingWebhookConfiguration_debug.yaml @@ -3,11 +3,11 @@ apiVersion: admissionregistration.k8s.io/v1beta1 kind: MutatingWebhookConfiguration metadata: - name: nirmata-kube-policy-webhook-cfg-debug + name: nirmata-kyverno-webhook-cfg-debug labels: - app: kube-policy + app: kyverno webhooks: - - name: webhook.nirmata.kube-policy + - name: webhook.nirmata.kyverno clientConfig: url: "https://localhost/mutate" caBundle: ${CA_BUNDLE} diff --git a/definitions/install.yaml b/definitions/install.yaml index f23e12fad3..dd5d5068d0 100644 --- a/definitions/install.yaml +++ b/definitions/install.yaml @@ -1,9 +1,9 @@ apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: - name: policies.kubepolicy.nirmata.io + name: policies.kyverno.io spec: - group: kubepolicy.nirmata.io + group: kyverno.io versions: - name: v1alpha1 served: true @@ -143,57 +143,62 @@ spec: additionalProperties: type: string --- +kind: Namespace +apiVersion: v1 +metadata: + name: "kyverno" +--- apiVersion: v1 kind: Service metadata: - namespace: kube-system - name: kube-policy-svc + namespace: kyverno + name: kyverno-svc labels: - app: kube-policy + app: kyverno spec: ports: - port: 443 targetPort: 443 selector: - app: kube-policy + app: kyverno --- apiVersion: v1 kind: ServiceAccount metadata: - name: kube-policy-service-account - namespace: kube-system + name: kyverno-service-account + namespace: kyverno --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: - name: kube-policy-admin + name: kyverno-admin roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount - name: kube-policy-service-account - namespace: kube-system + name: kyverno-service-account + namespace: kyverno --- apiVersion: extensions/v1beta1 kind: Deployment metadata: - namespace: kube-system - name: kube-policy-deployment + namespace: kyverno + name: kyverno-deployment labels: - app: kube-policy + app: kyverno spec: replicas: 1 template: metadata: labels: - app: kube-policy + app: kyverno spec: - serviceAccountName: kube-policy-service-account + serviceAccountName: kyverno-service-account containers: - - name: kube-policy - image: nirmata/kube-policy:latest + - name: kyverno + image: nirmata/kyverno:latest imagePullPolicy: IfNotPresent ports: - containerPort: 443 diff --git a/documentation/installation.md b/documentation/installation.md index 97d88a591c..03cab883f3 100644 --- a/documentation/installation.md +++ b/documentation/installation.md @@ -9,15 +9,15 @@ Just execute the command for creating all necesarry resources: `kubectl create -f definitions/install.yaml` In this mode controller will get TLS key/certificate pair and loads in-cluster config automatically on start. -To check if the controller is working, find it in the list of kube-system pods: +To check if the controller is working, find it in the list of kyverno pods: -`kubectl get pods -n kube-system` +`kubectl get pods -n kyverno` -The pod with controller contains **'kube-policy'** in its name. The STATUS column will show the health state of the controller. If controller doesn't start, see its logs: +The pod with controller contains **'kyverno'** in its name. The STATUS column will show the health state of the controller. If controller doesn't start, see its logs: -`kubectl describe pod -n kube-system` +`kubectl describe pod -n kyverno` or -`kubectl logs -n kube-system` +`kubectl logs -n kyverno` diff --git a/pkg/apis/policy/register.go b/pkg/apis/policy/register.go index d55c28d2f6..eb0717d576 100644 --- a/pkg/apis/policy/register.go +++ b/pkg/apis/policy/register.go @@ -2,5 +2,5 @@ package policy const ( // GroupName must be the same as specified in Policy CRD - GroupName = "kubepolicy.nirmata.io" + GroupName = "kyverno.io" ) diff --git a/pkg/apis/policy/v1alpha1/doc.go b/pkg/apis/policy/v1alpha1/doc.go index d1cb706659..4fa2b53292 100644 --- a/pkg/apis/policy/v1alpha1/doc.go +++ b/pkg/apis/policy/v1alpha1/doc.go @@ -1,4 +1,4 @@ // +k8s:deepcopy-gen=package -// +groupName=kubepolicy.nirmata.io +// +groupName=kyverno.io package v1alpha1 diff --git a/pkg/config/config.go b/pkg/config/config.go index 8e0e8eb359..f6db7fc86c 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -2,28 +2,28 @@ package config const ( // These constants MUST be equal to the corresponding names in service definition in definitions/install.yaml - KubePolicyNamespace = "kube-system" - WebhookServiceName = "kube-policy-svc" + KubePolicyNamespace = "kyverno" + WebhookServiceName = "kyverno-svc" - MutatingWebhookConfigurationName = "kube-policy-mutating-webhook-cfg" - MutatingWebhookName = "nirmata.kube-policy.mutating-webhook" + MutatingWebhookConfigurationName = "kyverno-mutating-webhook-cfg" + MutatingWebhookName = "nirmata.kyverno.mutating-webhook" - ValidatingWebhookConfigurationName = "kube-policy-validating-webhook-cfg" - ValidatingWebhookName = "nirmata.kube-policy.validating-webhook" + ValidatingWebhookConfigurationName = "kyverno-validating-webhook-cfg" + ValidatingWebhookName = "nirmata.kyverno.validating-webhook" // Due to kubernetes issue, we must use next literal constants instead of deployment TypeMeta fields // Issue: https://github.com/kubernetes/kubernetes/pull/63972 // When the issue is closed, we should use TypeMeta struct instead of this constants DeploymentKind = "Deployment" DeploymentAPIVersion = "extensions/v1beta1" - KubePolicyDeploymentName = "kube-policy-deployment" + KubePolicyDeploymentName = "kyverno-deployment" ) var ( MutatingWebhookServicePath = "/mutate" ValidatingWebhookServicePath = "/validate" KubePolicyAppLabels = map[string]string{ - "app": "kube-policy", + "app": "kyverno", } SupportedKinds = []string{ diff --git a/pkg/kyverno/apply/apply.go b/pkg/kyverno/apply/apply.go index 1bdfd9d293..785cfc15bf 100644 --- a/pkg/kyverno/apply/apply.go +++ b/pkg/kyverno/apply/apply.go @@ -82,7 +82,7 @@ func complete(args []string) (*kubepolicy.Policy, []*resourceInfo) { func applyPolicy(policy *kubepolicy.Policy, rawResource []byte, gvk *metav1.GroupVersionKind) ([]byte, error) { _, patchedDocument := engine.Mutate(*policy, rawResource, *gvk) - if err := engine.Validate(*policy, rawResource, *gvk); err != nil { + if err := engine.Validate(*policy, patchedDocument, *gvk); err != nil { return nil, err } return patchedDocument, nil diff --git a/pkg/sharedinformer/sharedinformerfactory.go b/pkg/sharedinformer/sharedinformerfactory.go index 4400e38d38..16c1b722d6 100644 --- a/pkg/sharedinformer/sharedinformerfactory.go +++ b/pkg/sharedinformer/sharedinformerfactory.go @@ -44,7 +44,7 @@ func (si *sharedInfomer) Run(stopCh <-chan struct{}) { } func (si *sharedInfomer) getInfomer() infomertypes.PolicyInformer { - return si.policyInformerFactory.Kubepolicy().V1alpha1().Policies() + return si.policyInformerFactory.Kyverno().V1alpha1().Policies() } func (si *sharedInfomer) GetInfomer() cache.SharedIndexInformer { return si.getInfomer().Informer() diff --git a/scripts/README.md b/scripts/README.md index 9452b1796e..3db3daaab4 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -7,7 +7,7 @@ Compiles the project to go executable, generates docker image and pushes it to t ### generate-server-cert.sh ### Generates TLS certificate and key that used by webhook server. Example: -`scripts/generate-server-cert.sh --service=kube-policy-svc --namespace=my_namespace --serverIp=192.168.10.117` +`scripts/generate-server-cert.sh --service=kyverno-svc --namespace=my_namespace --serverIp=192.168.10.117` * `--service` identifies the service for in-cluster webhook server. Do not specify it if you plan to run webhook server outside the cluster, or cpecify 'localhost' if you want to run controller locally. * `--namespace` identifies the namespace for in-cluster webhook server. Do not specify it if you plan to run controller locally. * `--serverIp` is the IP of master node, it can be found in `~/.kube/config`: clusters.cluster[0].server. You should explicitly specify it. @@ -18,7 +18,7 @@ Prepares controller for free (local) or in-cluster use. Uses `generate-server-ce * `--namespace` - the target namespace to deploy the controller. Do not specify it if you want to depoloy controller locally. * `--serverIp` means the same as for `generate-server-cert.sh` Examples: -`scripts/deploy-controller.sh --service=my-kube-policy --namespace=my_namespace --serverIp=192.168.10.117` - deploy controller to the cluster with master node '192.168.10.117' to the namespace 'my_namespace' as a service 'my-kube-policy' +`scripts/deploy-controller.sh --service=my-kyverno --namespace=my_namespace --serverIp=192.168.10.117` - deploy controller to the cluster with master node '192.168.10.117' to the namespace 'my_namespace' as a service 'my-kyverno' `scripts/deploy-controller.sh --service=localhost --serverIp=192.168.10.117` - deploy controller locally for usage in cluster with mnaster node at '192.168.10.117' ### test-web-hook.sh ### diff --git a/scripts/deploy-controller.sh b/scripts/deploy-controller.sh index ff9bd3f0d5..5399d4b1f2 100755 --- a/scripts/deploy-controller.sh +++ b/scripts/deploy-controller.sh @@ -19,7 +19,7 @@ esac done hub_user_name="nirmata" -project_name="kube-policy" +project_name="kyverno" if [ -z "${service_name}" ]; then service_name="${project_name}-svc" @@ -40,7 +40,7 @@ if [ -z "${namespace}" ]; then # controller should be launched locally kubectl delete -f definitions/install.yaml kubectl create -f definitions/install.yaml || exit 3 - echo -e "\n### You can build and run kube-policy project locally.\n### To check its work, run it with parameters -cert, -key and -kubeconfig parameters (see paths of -cert and -key in the log above)." + echo -e "\n### You can build and run kyverno project locally.\n### To check its work, run it with parameters -cert, -key and -kubeconfig parameters (see paths of -cert and -key in the log above)." else # controller should be launched within a cluster diff --git a/test/README.md b/test/README.md index 83136b4cb8..1867123f85 100644 --- a/test/README.md +++ b/test/README.md @@ -1,5 +1,5 @@ # Examples -Examples of policies and resources with which you can play to see the kube-policy in action. There are definitions for each supported resource type and an example policy for the corresponding resource. +Examples of policies and resources with which you can play to see the kyverno in action. There are definitions for each supported resource type and an example policy for the corresponding resource. ## How to play First of all, **build and install the policy controller**: see README file in the project's root. Each folder contains a pair of files, one of which is the definition of the resource, and the second is the definition of the policy for this resource. Let's look at an example of the endpoints mutation. Endpoints are listed in file `examples/Endpoints/endpoints.yaml`: From dbd1bb4466a92ec73ce1ab8473f9a33171e9b098 Mon Sep 17 00:00:00 2001 From: shuting Date: Tue, 21 May 2019 18:38:52 -0700 Subject: [PATCH 05/19] update example due to crd name changed --- examples/CLI/deployment/policy-deployment.yaml | 2 +- test/ConfigMap/policy-CM.yaml | 2 +- test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml | 2 +- .../policy-namespace-patch-cmgCG-sgCG.yaml | 2 +- test/CronJob/policy-cronjob-wldcrd.yaml | 4 ++-- test/DaemonSet/policy-daemonset.yaml | 2 +- test/Deployment/policy-deployment-any.yaml | 2 +- test/Endpoint/policy-endpoints.yaml | 6 +++--- test/HorizontalPodAutoscaler/policy-hpa.yaml | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/CLI/deployment/policy-deployment.yaml b/examples/CLI/deployment/policy-deployment.yaml index ef8ab8b9bf..52b5ac0ee9 100644 --- a/examples/CLI/deployment/policy-deployment.yaml +++ b/examples/CLI/deployment/policy-deployment.yaml @@ -1,4 +1,4 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind : Policy metadata : name : policy-deployment diff --git a/test/ConfigMap/policy-CM.yaml b/test/ConfigMap/policy-CM.yaml index 843ff23f7e..e9449d118e 100644 --- a/test/ConfigMap/policy-CM.yaml +++ b/test/ConfigMap/policy-CM.yaml @@ -1,4 +1,4 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind : Policy metadata : name : policy-cm diff --git a/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml b/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml index 3a0ce26477..c51e727c52 100644 --- a/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml +++ b/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml @@ -1,4 +1,4 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind: Policy metadata : name: "policy-configmapgenerator-test" diff --git a/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml b/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml index 56e21a4598..009ab1d875 100644 --- a/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml +++ b/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml @@ -3,7 +3,7 @@ # To apply this policy you need to create secret and configMap in "default" namespace # and then create a namespace -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind : Policy metadata : name : "policy-ns-patch-cmg-sg" diff --git a/test/CronJob/policy-cronjob-wldcrd.yaml b/test/CronJob/policy-cronjob-wldcrd.yaml index 4ef1598c35..09f5991758 100644 --- a/test/CronJob/policy-cronjob-wldcrd.yaml +++ b/test/CronJob/policy-cronjob-wldcrd.yaml @@ -1,10 +1,10 @@ -apiVersion: kubepolicy.nirmata.io/v1alpha1 +apiVersion: kyverno.io/v1alpha1 kind: Policy metadata: name: policy-cronjob spec: rules: - - name: + - name: pCJ resource: kind : CronJob name: "?ell*" diff --git a/test/DaemonSet/policy-daemonset.yaml b/test/DaemonSet/policy-daemonset.yaml index 47912c2795..333b0daf81 100644 --- a/test/DaemonSet/policy-daemonset.yaml +++ b/test/DaemonSet/policy-daemonset.yaml @@ -1,4 +1,4 @@ -apiVersion: kubepolicy.nirmata.io/v1alpha1 +apiVersion: kyverno.io/v1alpha1 kind: Policy metadata: name: policy-daemonset diff --git a/test/Deployment/policy-deployment-any.yaml b/test/Deployment/policy-deployment-any.yaml index 6a43ec225d..20c7e3a4fd 100644 --- a/test/Deployment/policy-deployment-any.yaml +++ b/test/Deployment/policy-deployment-any.yaml @@ -1,4 +1,4 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind : Policy metadata : name : policy-deployment diff --git a/test/Endpoint/policy-endpoints.yaml b/test/Endpoint/policy-endpoints.yaml index 335573c6ba..d598d75329 100644 --- a/test/Endpoint/policy-endpoints.yaml +++ b/test/Endpoint/policy-endpoints.yaml @@ -1,10 +1,10 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind : Policy metadata : name : policy-endpoints spec : rules: - - name: + - name: pEP resource: kind : Endpoints selector: @@ -19,7 +19,7 @@ spec : op: add value: addresses: - - ip: "192.168.10.171" + - ip: "192.168.10.172" ports: - name: load-balancer-connection port: 80 diff --git a/test/HorizontalPodAutoscaler/policy-hpa.yaml b/test/HorizontalPodAutoscaler/policy-hpa.yaml index 840c41fc46..4ec2afb3ba 100644 --- a/test/HorizontalPodAutoscaler/policy-hpa.yaml +++ b/test/HorizontalPodAutoscaler/policy-hpa.yaml @@ -1,4 +1,4 @@ -apiVersion: kubepolicy.nirmata.io/v1alpha1 +apiVersion: kyverno.io/v1alpha1 kind: Policy metadata: name: policy-hpa From 268ed14dbc7e1f00deb35d51ec791b8530d08104 Mon Sep 17 00:00:00 2001 From: shivdudhani Date: Tue, 21 May 2019 18:50:51 -0700 Subject: [PATCH 06/19] pass addr of value instead of adr of ptr --- client/client.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/client/client.go b/client/client.go index cf3e1d266a..91483f0dd9 100644 --- a/client/client.go +++ b/client/client.go @@ -147,7 +147,7 @@ func (c *Client) UpdateStatusResource(kind string, namespace string, obj interfa } func convertToUnstructured(obj interface{}) *unstructured.Unstructured { - unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&obj) if err != nil { utilruntime.HandleError(fmt.Errorf("Unable to convert : %v", err)) return nil @@ -174,7 +174,7 @@ func ConvertToRuntimeObject(obj *unstructured.Unstructured) (*runtime.Object, er func (c *Client) GenerateSecret(generator types.Generation, namespace string) error { c.logger.Printf("Preparing to create secret %s/%s", namespace, generator.Name) - secret := &v1.Secret{} + secret := v1.Secret{} // if generator.CopyFrom != nil { c.logger.Printf("Copying data from secret %s/%s", generator.CopyFrom.Namespace, generator.CopyFrom.Name) @@ -206,7 +206,7 @@ func (c *Client) GenerateSecret(generator types.Generation, namespace string) er } } - go c.createSecretAfterNamespaceIsCreated(*secret, namespace) + go c.createSecretAfterNamespaceIsCreated(secret, namespace) return nil } @@ -214,7 +214,7 @@ func (c *Client) GenerateSecret(generator types.Generation, namespace string) er //GenerateConfigMap to generate configMap func (c *Client) GenerateConfigMap(generator types.Generation, namespace string) error { c.logger.Printf("Preparing to create configmap %s/%s", namespace, generator.Name) - configMap := &v1.ConfigMap{} + configMap := v1.ConfigMap{} // if generator.CopyFrom != nil { c.logger.Printf("Copying data from configmap %s/%s", generator.CopyFrom.Namespace, generator.CopyFrom.Name) @@ -245,24 +245,24 @@ func (c *Client) GenerateConfigMap(generator types.Generation, namespace string) configMap.Data[k] = v } } - go c.createConfigMapAfterNamespaceIsCreated(*configMap, namespace) + go c.createConfigMapAfterNamespaceIsCreated(configMap, namespace) return nil } -func convertToConfigMap(obj *unstructured.Unstructured) (*v1.ConfigMap, error) { +func convertToConfigMap(obj *unstructured.Unstructured) (v1.ConfigMap, error) { configMap := v1.ConfigMap{} if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &configMap); err != nil { - return nil, err + return configMap, err } - return &configMap, nil + return configMap, nil } -func convertToSecret(obj *unstructured.Unstructured) (*v1.Secret, error) { +func convertToSecret(obj *unstructured.Unstructured) (v1.Secret, error) { secret := v1.Secret{} if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &secret); err != nil { - return nil, err + return secret, err } - return &secret, nil + return secret, nil } func convertToCSR(obj *unstructured.Unstructured) (*certificates.CertificateSigningRequest, error) { From 60a8f7bc55bc67f74bdbbe4ab90d246d90abec83 Mon Sep 17 00:00:00 2001 From: shivdudhani Date: Tue, 21 May 2019 20:53:29 -0700 Subject: [PATCH 07/19] remove the checks on resouce kinds as we support everything --- client/client.go | 9 --------- pkg/webhooks/server.go | 12 +++++------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/client/client.go b/client/client.go index 91483f0dd9..bb9efd61e4 100644 --- a/client/client.go +++ b/client/client.go @@ -4,7 +4,6 @@ import ( "fmt" "log" "os" - "strings" "time" types "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" @@ -307,11 +306,3 @@ func (c *Client) waitUntilNamespaceIsCreated(name string) error { } return lastError } - -// KindIsSupported checks if the kind is a registerd GVK -func (c *Client) KindIsSupported(kind string) bool { - kind = strings.ToLower(kind) + "s" - buildGVKMapper(c.clientConfig, false) - _, ok := getValue(kind) - return ok -} diff --git a/pkg/webhooks/server.go b/pkg/webhooks/server.go index c588216ddf..fc21a0b9aa 100644 --- a/pkg/webhooks/server.go +++ b/pkg/webhooks/server.go @@ -87,13 +87,11 @@ func (ws *WebhookServer) serve(w http.ResponseWriter, r *http.Request) { admissionReview.Response = &v1beta1.AdmissionResponse{ Allowed: true, } - if ws.client.KindIsSupported(admissionReview.Request.Kind.Kind) { - switch r.URL.Path { - case config.MutatingWebhookServicePath: - admissionReview.Response = ws.HandleMutation(admissionReview.Request) - case config.ValidatingWebhookServicePath: - admissionReview.Response = ws.HandleValidation(admissionReview.Request) - } + switch r.URL.Path { + case config.MutatingWebhookServicePath: + admissionReview.Response = ws.HandleMutation(admissionReview.Request) + case config.ValidatingWebhookServicePath: + admissionReview.Response = ws.HandleValidation(admissionReview.Request) } admissionReview.Response.UID = admissionReview.Request.UID From c99e1dcc19376e00bbf8602981eb2aabe89de9c6 Mon Sep 17 00:00:00 2001 From: shivdudhani Date: Wed, 22 May 2019 00:16:22 -0700 Subject: [PATCH 08/19] redesign: introduce cache discovery interface --- client/certificates.go | 16 +++--- client/client.go | 108 ++++++++++++++++++++++----------------- client/utils.go | 93 ++------------------------------- pkg/violation/builder.go | 2 +- pkg/webhooks/server.go | 12 ++--- 5 files changed, 80 insertions(+), 151 deletions(-) diff --git a/client/certificates.go b/client/certificates.go index 740c2d5a79..d79f0eeb75 100644 --- a/client/certificates.go +++ b/client/certificates.go @@ -46,14 +46,14 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat if err != nil { return nil, err } - csrList, err := c.ListResource(CSR, "") + csrList, err := c.ListResource(CSRs, "") if err != nil { return nil, errors.New(fmt.Sprintf("Unable to list existing certificate requests: %v", err)) } for _, csr := range csrList.Items { if csr.GetName() == req.ObjectMeta.Name { - err := c.DeleteResouce(CSR, "", csr.GetName()) + err := c.DeleteResouce(CSRs, "", csr.GetName()) if err != nil { return nil, errors.New(fmt.Sprintf("Unable to delete existing certificate request: %v", err)) } @@ -62,7 +62,7 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat } } - unstrRes, err := c.CreateResource(CSR, "", req) + unstrRes, err := c.CreateResource(CSRs, "", req) if err != nil { return nil, err } @@ -91,7 +91,7 @@ func (c *Client) fetchCertificateFromRequest(req *certificates.CertificateSignin // TODO: react of SIGINT and SIGTERM timeStart := time.Now() for time.Now().Sub(timeStart) < time.Duration(maxWaitSeconds)*time.Second { - unstrR, err := c.GetResource(CSR, "", req.ObjectMeta.Name) + unstrR, err := c.GetResource(CSRs, "", req.ObjectMeta.Name) if err != nil { return nil, err } @@ -119,7 +119,7 @@ const certificateField string = "certificate" // Reads the pair of TLS certificate and key from the specified secret. func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair { name := generateSecretName(props) - unstrSecret, err := c.GetResource(Secret, props.Namespace, name) + unstrSecret, err := c.GetResource(Secrets, props.Namespace, name) if err != nil { c.logger.Printf("Unable to get secret %s/%s: %s", props.Namespace, name, err) return nil @@ -147,7 +147,7 @@ func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair { // Updates existing secret or creates new one. func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPemPair) error { name := generateSecretName(props) - unstrSecret, err := c.GetResource(Secret, props.Namespace, name) + unstrSecret, err := c.GetResource(Secrets, props.Namespace, name) if err == nil { secret, err := convertToSecret(unstrSecret) if err != nil { @@ -159,7 +159,7 @@ func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPem } secret.Data[certificateField] = pemPair.Certificate secret.Data[privateKeyField] = pemPair.PrivateKey - _, err = c.UpdateResource(Secret, props.Namespace, secret) + _, err = c.UpdateResource(Secrets, props.Namespace, secret) if err == nil { c.logger.Printf("Secret %s is updated", name) } @@ -181,7 +181,7 @@ func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPem }, } - _, err := c.CreateResource(Secret, props.Namespace, secret) + _, err := c.CreateResource(Secrets, props.Namespace, secret) if err == nil { c.logger.Printf("Secret %s is created", name) } diff --git a/client/client.go b/client/client.go index 91483f0dd9..3b5a39cb7f 100644 --- a/client/client.go +++ b/client/client.go @@ -4,7 +4,6 @@ import ( "fmt" "log" "os" - "strings" "time" types "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" @@ -17,16 +16,21 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/client-go/discovery" + "k8s.io/client-go/discovery/cached/memory" "k8s.io/client-go/dynamic" + "k8s.io/client-go/kubernetes" csrtype "k8s.io/client-go/kubernetes/typed/certificates/v1beta1" event "k8s.io/client-go/kubernetes/typed/core/v1" "k8s.io/client-go/rest" ) type Client struct { - logger *log.Logger client dynamic.Interface + cachedClient discovery.CachedDiscoveryInterface + logger *log.Logger clientConfig *rest.Config + kclient *kubernetes.Clientset } func NewClient(config *rest.Config, logger *log.Logger) (*Client, error) { @@ -39,10 +43,17 @@ func NewClient(config *rest.Config, logger *log.Logger) (*Client, error) { logger = log.New(os.Stdout, "Client : ", log.LstdFlags) } + kclient, err := kubernetes.NewForConfig(config) + if err != nil { + return nil, err + } + return &Client{ logger: logger, client: client, clientConfig: config, + kclient: kclient, + cachedClient: memory.NewMemCacheClient(kclient.Discovery()), }, nil } @@ -62,29 +73,20 @@ func (c *Client) GetKubePolicyDeployment() (*apps.Deployment, error) { // or generate a kube client value to access the interface //GetEventsInterface provides typed interface for events func (c *Client) GetEventsInterface() (event.EventInterface, error) { - kubeClient, err := newKubeClient(c.clientConfig) - if err != nil { - return nil, err - } - return kubeClient.CoreV1().Events(""), nil + return c.kclient.CoreV1().Events(""), nil } func (c *Client) GetCSRInterface() (csrtype.CertificateSigningRequestInterface, error) { - kubeClient, err := newKubeClient(c.clientConfig) - if err != nil { - return nil, err - } - - return kubeClient.CertificatesV1beta1().CertificateSigningRequests(), nil + return c.kclient.CertificatesV1beta1().CertificateSigningRequests(), nil } -func (c *Client) getInterface(kind string) dynamic.NamespaceableResourceInterface { - return c.client.Resource(c.getGroupVersionMapper(kind)) +func (c *Client) getInterface(resource string) dynamic.NamespaceableResourceInterface { + return c.client.Resource(c.getGroupVersionMapper(resource)) } -func (c *Client) getResourceInterface(kind string, namespace string) dynamic.ResourceInterface { +func (c *Client) getResourceInterface(resource string, namespace string) dynamic.ResourceInterface { // Get the resource interface - namespaceableInterface := c.getInterface(kind) + namespaceableInterface := c.getInterface(resource) // Get the namespacable interface var resourceInteface dynamic.ResourceInterface if namespace != "" { @@ -96,52 +98,52 @@ func (c *Client) getResourceInterface(kind string, namespace string) dynamic.Res } // Keep this a stateful as the resource list will be based on the kubernetes version we connect to -func (c *Client) getGroupVersionMapper(kind string) schema.GroupVersionResource { - //TODO: add checks to see if the kind is supported - //TODO: build the resource list dynamically( by querying the registered resource kinds) +func (c *Client) getGroupVersionMapper(resource string) schema.GroupVersionResource { + //TODO: add checks to see if the resource is supported + //TODO: build the resource list dynamically( by querying the registered resources) //TODO: the error scenarios - return getGrpVersionMapper(kind, c.clientConfig, false) + return c.getGVR(resource) } // GetResource returns the resource in unstructured/json format -func (c *Client) GetResource(kind string, namespace string, name string) (*unstructured.Unstructured, error) { - return c.getResourceInterface(kind, namespace).Get(name, meta.GetOptions{}) +func (c *Client) GetResource(resource string, namespace string, name string) (*unstructured.Unstructured, error) { + return c.getResourceInterface(resource, namespace).Get(name, meta.GetOptions{}) } // ListResource returns the list of resources in unstructured/json format // Access items using []Items -func (c *Client) ListResource(kind string, namespace string) (*unstructured.UnstructuredList, error) { - return c.getResourceInterface(kind, namespace).List(meta.ListOptions{}) +func (c *Client) ListResource(resource string, namespace string) (*unstructured.UnstructuredList, error) { + return c.getResourceInterface(resource, namespace).List(meta.ListOptions{}) } -func (c *Client) DeleteResouce(kind string, namespace string, name string) error { - return c.getResourceInterface(kind, namespace).Delete(name, &meta.DeleteOptions{}) +func (c *Client) DeleteResouce(resource string, namespace string, name string) error { + return c.getResourceInterface(resource, namespace).Delete(name, &meta.DeleteOptions{}) } -// CreateResource creates object for the specified kind/namespace -func (c *Client) CreateResource(kind string, namespace string, obj interface{}) (*unstructured.Unstructured, error) { +// CreateResource creates object for the specified resource/namespace +func (c *Client) CreateResource(resource string, namespace string, obj interface{}) (*unstructured.Unstructured, error) { // convert typed to unstructured obj if unstructuredObj := convertToUnstructured(obj); unstructuredObj != nil { - return c.getResourceInterface(kind, namespace).Create(unstructuredObj, meta.CreateOptions{}) + return c.getResourceInterface(resource, namespace).Create(unstructuredObj, meta.CreateOptions{}) } return nil, fmt.Errorf("Unable to create resource ") } -// UpdateResource updates object for the specified kind/namespace -func (c *Client) UpdateResource(kind string, namespace string, obj interface{}) (*unstructured.Unstructured, error) { +// UpdateResource updates object for the specified resource/namespace +func (c *Client) UpdateResource(resource string, namespace string, obj interface{}) (*unstructured.Unstructured, error) { // convert typed to unstructured obj if unstructuredObj := convertToUnstructured(obj); unstructuredObj != nil { - return c.getResourceInterface(kind, namespace).Update(unstructuredObj, meta.UpdateOptions{}) + return c.getResourceInterface(resource, namespace).Update(unstructuredObj, meta.UpdateOptions{}) } return nil, fmt.Errorf("Unable to update resource ") } // UpdateStatusResource updates the resource "status" subresource -func (c *Client) UpdateStatusResource(kind string, namespace string, obj interface{}) (*unstructured.Unstructured, error) { +func (c *Client) UpdateStatusResource(resource string, namespace string, obj interface{}) (*unstructured.Unstructured, error) { // convert typed to unstructured obj if unstructuredObj := convertToUnstructured(obj); unstructuredObj != nil { - return c.getResourceInterface(kind, namespace).UpdateStatus(unstructuredObj, meta.UpdateOptions{}) + return c.getResourceInterface(resource, namespace).UpdateStatus(unstructuredObj, meta.UpdateOptions{}) } return nil, fmt.Errorf("Unable to update resource ") } @@ -179,7 +181,7 @@ func (c *Client) GenerateSecret(generator types.Generation, namespace string) er // if generator.CopyFrom != nil { c.logger.Printf("Copying data from secret %s/%s", generator.CopyFrom.Namespace, generator.CopyFrom.Name) // Get configMap resource - unstrSecret, err := c.GetResource(Secret, generator.CopyFrom.Namespace, generator.CopyFrom.Name) + unstrSecret, err := c.GetResource(Secrets, generator.CopyFrom.Namespace, generator.CopyFrom.Name) if err != nil { return err } @@ -219,7 +221,7 @@ func (c *Client) GenerateConfigMap(generator types.Generation, namespace string) // if generator.CopyFrom != nil { c.logger.Printf("Copying data from configmap %s/%s", generator.CopyFrom.Namespace, generator.CopyFrom.Name) // Get configMap resource - unstrConfigMap, err := c.GetResource("configmaps", generator.CopyFrom.Namespace, generator.CopyFrom.Name) + unstrConfigMap, err := c.GetResource(ConfigMaps, generator.CopyFrom.Namespace, generator.CopyFrom.Name) if err != nil { return err } @@ -276,7 +278,7 @@ func convertToCSR(obj *unstructured.Unstructured) (*certificates.CertificateSign func (c *Client) createConfigMapAfterNamespaceIsCreated(configMap v1.ConfigMap, namespace string) { err := c.waitUntilNamespaceIsCreated(namespace) if err == nil { - _, err = c.CreateResource("configmaps", namespace, configMap) + _, err = c.CreateResource(ConfigMaps, namespace, configMap) } if err != nil { c.logger.Printf("Can't create a configmap: %s", err) @@ -286,7 +288,7 @@ func (c *Client) createConfigMapAfterNamespaceIsCreated(configMap v1.ConfigMap, func (c *Client) createSecretAfterNamespaceIsCreated(secret v1.Secret, namespace string) { err := c.waitUntilNamespaceIsCreated(namespace) if err == nil { - _, err = c.CreateResource(Secret, namespace, secret) + _, err = c.CreateResource(Secrets, namespace, secret) } if err != nil { c.logger.Printf("Can't create a secret: %s", err) @@ -299,7 +301,7 @@ func (c *Client) waitUntilNamespaceIsCreated(name string) error { var lastError error = nil for time.Now().Sub(timeStart) < namespaceCreationMaxWaitTime { - _, lastError = c.GetResource("namespaces", "", name) + _, lastError = c.GetResource(Namespaces, "", name) if lastError == nil { break } @@ -308,10 +310,24 @@ func (c *Client) waitUntilNamespaceIsCreated(name string) error { return lastError } -// KindIsSupported checks if the kind is a registerd GVK -func (c *Client) KindIsSupported(kind string) bool { - kind = strings.ToLower(kind) + "s" - buildGVKMapper(c.clientConfig, false) - _, ok := getValue(kind) - return ok +func (c *Client) getGVR(resource string) schema.GroupVersionResource { + emptyGVR := schema.GroupVersionResource{} + serverresources, err := c.cachedClient.ServerPreferredResources() + if err != nil { + utilruntime.HandleError(err) + return emptyGVR + } + resources, err := discovery.GroupVersionResources(serverresources) + if err != nil { + utilruntime.HandleError(err) + return emptyGVR + } + //TODO using cached client to support cache validation and invalidation + // iterate over the key to compare the resource + for gvr, _ := range resources { + if gvr.Resource == resource { + return gvr + } + } + return emptyGVR } diff --git a/client/utils.go b/client/utils.go index d768ddda78..d787cdf8e6 100644 --- a/client/utils.go +++ b/client/utils.go @@ -1,99 +1,14 @@ package client import ( - "fmt" - "strings" "time" - - "k8s.io/apimachinery/pkg/runtime/schema" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" ) const ( - CSR string = "certificatesigningrequests" - Secret string = "secrets" + CSRs string = "certificatesigningrequests" + Secrets string = "secrets" + ConfigMaps string = "configmaps" + Namespaces string = "namespaces" ) const namespaceCreationMaxWaitTime time.Duration = 30 * time.Second const namespaceCreationWaitInterval time.Duration = 100 * time.Millisecond - -var groupVersionMapper map[string]schema.GroupVersionResource -var kubeClient *kubernetes.Clientset - -func getGrpVersionMapper(kind string, clientConfig *rest.Config, refresh bool) schema.GroupVersionResource { - // build the GVK mapper - buildGVKMapper(clientConfig, refresh) - // Query mapper - if val, ok := getValue(kind); ok { - return *val - } - utilruntime.HandleError(fmt.Errorf("Resouce '%s' not registered", kind)) - return schema.GroupVersionResource{} -} - -func buildGVKMapper(clientConfig *rest.Config, refresh bool) { - if groupVersionMapper == nil || refresh { - groupVersionMapper = make(map[string]schema.GroupVersionResource) - // refresh the mapper - if err := refreshRegisteredResources(groupVersionMapper, clientConfig); err != nil { - utilruntime.HandleError(err) - return - } - } -} - -func getValue(kind string) (*schema.GroupVersionResource, bool) { - if groupVersionMapper == nil { - utilruntime.HandleError(fmt.Errorf("GroupVersionKind mapper is not loaded")) - return nil, false - } - if val, ok := groupVersionMapper[kind]; ok { - return &val, true - } - return nil, false -} - -func refreshRegisteredResources(mapper map[string]schema.GroupVersionResource, clientConfig *rest.Config) error { - // build kubernetes client - client, err := newKubeClient(clientConfig) - if err != nil { - return err - } - - // get registered server groups and resources - _, resourceList, err := client.Discovery().ServerGroupsAndResources() - if err != nil { - return err - } - for _, apiResource := range resourceList { - for _, resource := range apiResource.APIResources { - grpVersion := strings.Split(apiResource.GroupVersion, "/") - if len(grpVersion) == 2 { - mapper[resource.Name] = schema.GroupVersionResource{ - Group: grpVersion[0], - Version: grpVersion[1], - Resource: resource.Name, - } - } else { - // resources with only versions - mapper[resource.Name] = schema.GroupVersionResource{ - Version: apiResource.GroupVersion, - Resource: resource.Name, - } - } - } - } - return nil -} - -func newKubeClient(clientConfig *rest.Config) (*kubernetes.Clientset, error) { - var err error - if kubeClient == nil { - kubeClient, err = kubernetes.NewForConfig(clientConfig) - if err != nil { - return nil, err - } - } - return kubeClient, nil -} diff --git a/pkg/violation/builder.go b/pkg/violation/builder.go index 3579037e47..8e76660be8 100644 --- a/pkg/violation/builder.go +++ b/pkg/violation/builder.go @@ -90,7 +90,7 @@ func (b *builder) processViolation(info Info) error { modifiedPolicy.Status.Violations = modifiedViolations // Violations are part of the status sub resource, so we can use the Update Status api instead of updating the policy object - _, err = b.client.UpdateStatusResource("policies", namespace, modifiedPolicy) + _, err = b.client.UpdateStatusResource("policies/status", namespace, modifiedPolicy) if err != nil { return err } diff --git a/pkg/webhooks/server.go b/pkg/webhooks/server.go index c588216ddf..fc21a0b9aa 100644 --- a/pkg/webhooks/server.go +++ b/pkg/webhooks/server.go @@ -87,13 +87,11 @@ func (ws *WebhookServer) serve(w http.ResponseWriter, r *http.Request) { admissionReview.Response = &v1beta1.AdmissionResponse{ Allowed: true, } - if ws.client.KindIsSupported(admissionReview.Request.Kind.Kind) { - switch r.URL.Path { - case config.MutatingWebhookServicePath: - admissionReview.Response = ws.HandleMutation(admissionReview.Request) - case config.ValidatingWebhookServicePath: - admissionReview.Response = ws.HandleValidation(admissionReview.Request) - } + switch r.URL.Path { + case config.MutatingWebhookServicePath: + admissionReview.Response = ws.HandleMutation(admissionReview.Request) + case config.ValidatingWebhookServicePath: + admissionReview.Response = ws.HandleValidation(admissionReview.Request) } admissionReview.Response.UID = admissionReview.Request.UID From ab31d980b68cc430ecc8f1654178a5d606c8f584 Mon Sep 17 00:00:00 2001 From: kacejot Date: Wed, 22 May 2019 18:28:38 +0100 Subject: [PATCH 09/19] Updated mutation base due to spec --- pkg/engine/mutation.go | 2 +- pkg/engine/overlay.go | 33 ++++++++++++++------------------- pkg/engine/overlay_test.go | 16 +++++++++++++++- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/pkg/engine/mutation.go b/pkg/engine/mutation.go index 02bdfdeb9a..276f4bcd36 100644 --- a/pkg/engine/mutation.go +++ b/pkg/engine/mutation.go @@ -3,7 +3,7 @@ package engine import ( "log" - kubepolicy "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1" + kubepolicy "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) diff --git a/pkg/engine/overlay.go b/pkg/engine/overlay.go index 4bac976dc3..8c2ef40ac6 100644 --- a/pkg/engine/overlay.go +++ b/pkg/engine/overlay.go @@ -2,11 +2,11 @@ package engine import ( "encoding/json" - "fmt" "log" + "reflect" "strconv" - kubepolicy "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1" + kubepolicy "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -37,6 +37,12 @@ func ProcessOverlay(policy kubepolicy.Policy, rawResource []byte, gvk metav1.Gro } func applyOverlay(resource, overlay interface{}, path string) ([]PatchBytes, error) { + // resource item exists but has different type - replace + // all subtree within this path by overlay + if reflect.TypeOf(resource) != reflect.TypeOf(overlay) { + replaceResource(resource, overlay, path) + } + switch typedOverlay := overlay.(type) { case map[string]interface{}: typedResource := resource.(map[string]interface{}) @@ -55,23 +61,11 @@ func applyOverlay(resource, overlay interface{}, path string) ([]PatchBytes, err typedResource := resource.([]interface{}) applyOverlayToArray(typedResource, typedOverlay, path) case string: - typedResource, ok := resource.(string) - if !ok { - return nil, fmt.Errorf("Expected string, found %T", resource) - } - replaceResource(typedResource, typedOverlay, path) + replaceResource(resource, overlay, path) case float64: - typedResource, ok := resource.(float64) - if !ok { - return nil, fmt.Errorf("Expected string, found %T", resource) - } - replaceResource(typedResource, typedOverlay, path) + replaceResource(resource, overlay, path) case int64: - typedResource, ok := resource.(int64) - if !ok { - return nil, fmt.Errorf("Expected string, found %T", resource) - } - replaceResource(typedResource, typedOverlay, path) + replaceResource(resource, overlay, path) } return nil, nil @@ -82,7 +76,6 @@ func applyOverlayToArray(resource, overlay []interface{}, path string) { case map[string]interface{}: for _, overlayElement := range overlay { typedOverlay := overlayElement.(map[string]interface{}) - anchors := GetAnchorsFromMap(typedOverlay) if len(anchors) > 0 { @@ -117,7 +110,9 @@ func skipArrayObject(object, anchors map[string]interface{}) bool { return true } - return value != pattern + if value != pattern { + return true + } } return false diff --git a/pkg/engine/overlay_test.go b/pkg/engine/overlay_test.go index a35f183ae6..ab508039b6 100644 --- a/pkg/engine/overlay_test.go +++ b/pkg/engine/overlay_test.go @@ -1,11 +1,25 @@ package engine import ( + "encoding/json" + "fmt" + "reflect" "testing" "gotest.tools/assert" ) func TestApplyOverlay_BaseCase(t *testing.T) { - assert.Assert(t, true) + resource1Raw := []byte(`{ "dictionary": { "key1": "val1", "key2": "val2", "array": [ 1, 2 ] } }`) + resource2Raw := []byte(`{ "dictionary": "somestring" }`) + + var resource1, resource2 interface{} + + json.Unmarshal(resource1Raw, &resource1) + json.Unmarshal(resource2Raw, &resource2) + + fmt.Printf("First resource type: %v", reflect.TypeOf(resource1)) + fmt.Printf("Second resource type: %v", reflect.TypeOf(resource2)) + + assert.Assert(t, reflect.TypeOf(resource1) == reflect.TypeOf(resource2)) } From f776e26dccb01a4d37a10cbbc396ee21ff938ecc Mon Sep 17 00:00:00 2001 From: kacejot Date: Wed, 22 May 2019 18:29:10 +0100 Subject: [PATCH 10/19] Updated code due to changes in structure --- pkg/webhooks/server.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pkg/webhooks/server.go b/pkg/webhooks/server.go index f611050762..0c5156ed38 100644 --- a/pkg/webhooks/server.go +++ b/pkg/webhooks/server.go @@ -12,11 +12,12 @@ import ( "os" "time" - kubeClient "github.com/nirmata/kube-policy/kubeclient" - policylister "github.com/nirmata/kube-policy/pkg/client/listers/policy/v1alpha1" - "github.com/nirmata/kube-policy/pkg/config" - engine "github.com/nirmata/kube-policy/pkg/engine" - tlsutils "github.com/nirmata/kube-policy/pkg/tls" + "github.com/nirmata/kyverno/client" + "github.com/nirmata/kyverno/pkg/client/listers/policy/v1alpha1" + "github.com/nirmata/kyverno/pkg/config" + engine "github.com/nirmata/kyverno/pkg/engine" + "github.com/nirmata/kyverno/pkg/sharedinformer" + tlsutils "github.com/nirmata/kyverno/pkg/tls" v1beta1 "k8s.io/api/admission/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" From afb6b068e4751ed48a9f871b6875317dd9cd39bd Mon Sep 17 00:00:00 2001 From: kacejot Date: Wed, 22 May 2019 18:29:57 +0100 Subject: [PATCH 11/19] Updated .gitignore to ingore kyverno binary --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6068efc5ee..b838b00397 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ vendor pkg/client pkg/apis/policy/v1alpha1/zz_generated.deepcopy.go certs -kube-policy +kyverno Gopkg.lock Dockerfile .vscode From 857aa81f3e6f743c3cfff6c3a17bbd2bb98d8e25 Mon Sep 17 00:00:00 2001 From: shivdudhani Date: Wed, 22 May 2019 10:53:01 -0700 Subject: [PATCH 12/19] update the project name in api version and test --- examples/Validate/check_cpu_memory.yaml | 2 +- examples/Validate/check_hostpath.yaml | 2 +- examples/Validate/check_image_version.yaml | 2 +- examples/Validate/check_nodeport.yaml | 2 +- examples/Validate/check_probe_exists.yaml | 2 +- examples/Validate/check_probe_intervals.yaml | 2 +- examples/Validate/check_whitelist_registries.yaml | 2 +- pkg/engine/validation_test.go | 4 ++-- test/Ingress/policy-ingress.yaml | 2 +- test/Job/policy-job.yaml | 2 +- test/LimitRange/policy-limitrange.yaml | 2 +- test/Namespace/policy-namespace.yaml | 2 +- test/NetworkPolicy/policy-network-policy.yaml | 2 +- test/PersistentVolumeClaim/policy-PVC.yaml | 2 +- test/PodDisruptionBudget/policy-pdb.yaml | 2 +- test/PodTemplate/policy-PodTemplate.yaml | 2 +- test/ResourceQuota/policy-quota-validation.yaml | 2 +- test/ResourceQuota/policy-quota.yaml | 2 +- test/Secret/policy-secret.yaml | 2 +- test/Service/policy-service.yaml | 2 +- test/StatefulSet/policy-StatefulSet.yaml | 2 +- 21 files changed, 22 insertions(+), 22 deletions(-) diff --git a/examples/Validate/check_cpu_memory.yaml b/examples/Validate/check_cpu_memory.yaml index 88b800d27d..f4a418296a 100644 --- a/examples/Validate/check_cpu_memory.yaml +++ b/examples/Validate/check_cpu_memory.yaml @@ -1,4 +1,4 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.nirmata.io/v1alpha1 kind: Policy metadata: name: check-cpu-memory diff --git a/examples/Validate/check_hostpath.yaml b/examples/Validate/check_hostpath.yaml index db91e4c35a..35dd08225b 100644 --- a/examples/Validate/check_hostpath.yaml +++ b/examples/Validate/check_hostpath.yaml @@ -1,4 +1,4 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.nirmata.io/v1alpha1 kind: Policy metadata: name: check-host-path diff --git a/examples/Validate/check_image_version.yaml b/examples/Validate/check_image_version.yaml index 3529c1cd26..15c8cb2d9a 100644 --- a/examples/Validate/check_image_version.yaml +++ b/examples/Validate/check_image_version.yaml @@ -1,4 +1,4 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.nirmata.io/v1alpha1 kind: Policy metadata: name: image-pull-policy diff --git a/examples/Validate/check_nodeport.yaml b/examples/Validate/check_nodeport.yaml index 0277405364..c2456f00e3 100644 --- a/examples/Validate/check_nodeport.yaml +++ b/examples/Validate/check_nodeport.yaml @@ -1,4 +1,4 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.nirmata.io/v1alpha1 kind: Policy metadata: name: check-host-path diff --git a/examples/Validate/check_probe_exists.yaml b/examples/Validate/check_probe_exists.yaml index 7a1e30edcc..442525a423 100644 --- a/examples/Validate/check_probe_exists.yaml +++ b/examples/Validate/check_probe_exists.yaml @@ -1,4 +1,4 @@ -apiVersion: kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.nirmata.io/v1alpha1 kind: Policy metadata: name: check-probe-exists diff --git a/examples/Validate/check_probe_intervals.yaml b/examples/Validate/check_probe_intervals.yaml index c2e25aa78e..15f93e4a88 100644 --- a/examples/Validate/check_probe_intervals.yaml +++ b/examples/Validate/check_probe_intervals.yaml @@ -1,4 +1,4 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.nirmata.io/v1alpha1 kind: Policy metadata: name: check-probe-intervals diff --git a/examples/Validate/check_whitelist_registries.yaml b/examples/Validate/check_whitelist_registries.yaml index 6875dd3ea2..386fe92cda 100644 --- a/examples/Validate/check_whitelist_registries.yaml +++ b/examples/Validate/check_whitelist_registries.yaml @@ -1,4 +1,4 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.nirmata.io/v1alpha1 kind: Policy metadata: name: check-whitelist-registries diff --git a/pkg/engine/validation_test.go b/pkg/engine/validation_test.go index e0b031d216..84d94632f0 100644 --- a/pkg/engine/validation_test.go +++ b/pkg/engine/validation_test.go @@ -358,7 +358,7 @@ func TestValidateMapElement_OneElementInArrayNotPass(t *testing.T) { } func TestValidate_ServiceTest(t *testing.T) { - rawPolicy := []byte(`{ "apiVersion": "kubepolicy.nirmata.io/v1alpha1", "kind": "Policy", "metadata": { "name": "policy-service" }, "spec": { "rules": [ { "name": "ps1", "resource": { "kind": "Service", "name": "game-service*" }, "mutate": { "patches": [ { "path": "/metadata/labels/isMutated", "op": "add", "value": "true" }, { "path": "/metadata/labels/secretLabel", "op": "replace", "value": "weKnow" }, { "path": "/metadata/labels/originalLabel", "op": "remove" }, { "path": "/spec/selector/app", "op": "replace", "value": "mutedApp" } ] }, "validate": { "message": "This resource is broken", "pattern": { "spec": { "ports": [ { "name": "hs", "protocol": 32 } ] } } } } ] } }`) + rawPolicy := []byte(`{ "apiVersion": "kyverno.nirmata.io/v1alpha1", "kind": "Policy", "metadata": { "name": "policy-service" }, "spec": { "rules": [ { "name": "ps1", "resource": { "kind": "Service", "name": "game-service*" }, "mutate": { "patches": [ { "path": "/metadata/labels/isMutated", "op": "add", "value": "true" }, { "path": "/metadata/labels/secretLabel", "op": "replace", "value": "weKnow" }, { "path": "/metadata/labels/originalLabel", "op": "remove" }, { "path": "/spec/selector/app", "op": "replace", "value": "mutedApp" } ] }, "validate": { "message": "This resource is broken", "pattern": { "spec": { "ports": [ { "name": "hs", "protocol": 32 } ] } } } } ] } }`) rawResource := []byte(`{ "kind": "Service", "apiVersion": "v1", "metadata": { "name": "game-service", "labels": { "originalLabel": "isHere", "secretLabel": "thisIsMySecret" } }, "spec": { "selector": { "app": "MyApp" }, "ports": [ { "name": "http", "protocol": "TCP", "port": 80, "targetPort": 9376 } ] } }`) var policy kubepolicy.Policy @@ -372,7 +372,7 @@ func TestValidate_ServiceTest(t *testing.T) { } func TestValidate_MapHasFloats(t *testing.T) { - rawPolicy := []byte(`{ "apiVersion": "kubepolicy.nirmata.io/v1alpha1", "kind": "Policy", "metadata": { "name": "policy-deployment-changed" }, "spec": { "rules": [ { "name": "First policy v2", "resource": { "kind": "Deployment", "name": "nginx-*" }, "mutate": { "patches": [ { "path": "/metadata/labels/isMutated", "op": "add", "value": "true" }, { "path": "/metadata/labels/app", "op": "replace", "value": "nginx_is_mutated" } ] }, "validate": { "message": "replicas number is wrong", "pattern": { "metadata": { "labels": { "app": "*" } }, "spec": { "replicas": 3 } } } } ] } }`) + rawPolicy := []byte(`{ "apiVersion": "kyverno.nirmata.io/v1alpha1", "kind": "Policy", "metadata": { "name": "policy-deployment-changed" }, "spec": { "rules": [ { "name": "First policy v2", "resource": { "kind": "Deployment", "name": "nginx-*" }, "mutate": { "patches": [ { "path": "/metadata/labels/isMutated", "op": "add", "value": "true" }, { "path": "/metadata/labels/app", "op": "replace", "value": "nginx_is_mutated" } ] }, "validate": { "message": "replicas number is wrong", "pattern": { "metadata": { "labels": { "app": "*" } }, "spec": { "replicas": 3 } } } } ] } }`) rawResource := []byte(`{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { "name": "nginx-deployment", "labels": { "app": "nginx" } }, "spec": { "replicas": 3, "selector": { "matchLabels": { "app": "nginx" } }, "template": { "metadata": { "labels": { "app": "nginx" } }, "spec": { "containers": [ { "name": "nginx", "image": "nginx:1.7.9", "ports": [ { "containerPort": 80 } ] } ] } } } }`) var policy kubepolicy.Policy diff --git a/test/Ingress/policy-ingress.yaml b/test/Ingress/policy-ingress.yaml index e8eb03b690..220f741df6 100644 --- a/test/Ingress/policy-ingress.yaml +++ b/test/Ingress/policy-ingress.yaml @@ -1,4 +1,4 @@ -apiVersion: kubepolicy.nirmata.io/v1alpha1 +apiVersion: kyverno.nirmata.io/v1alpha1 kind: Policy metadata : name : policy-ingress diff --git a/test/Job/policy-job.yaml b/test/Job/policy-job.yaml index 58660646fd..a9ef3e035d 100644 --- a/test/Job/policy-job.yaml +++ b/test/Job/policy-job.yaml @@ -1,4 +1,4 @@ -apiVersion: kubepolicy.nirmata.io/v1alpha1 +apiVersion: kyverno.nirmata.io/v1alpha1 kind: Policy metadata: name: policy-job-perl-bigint diff --git a/test/LimitRange/policy-limitrange.yaml b/test/LimitRange/policy-limitrange.yaml index c7bc58eac5..ccc8fee490 100644 --- a/test/LimitRange/policy-limitrange.yaml +++ b/test/LimitRange/policy-limitrange.yaml @@ -1,4 +1,4 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.nirmata.io/v1alpha1 kind : Policy metadata : name : policy-limitrange diff --git a/test/Namespace/policy-namespace.yaml b/test/Namespace/policy-namespace.yaml index 5697b22a43..1f8657f579 100644 --- a/test/Namespace/policy-namespace.yaml +++ b/test/Namespace/policy-namespace.yaml @@ -1,4 +1,4 @@ -apiVersion: kubepolicy.nirmata.io/v1alpha1 +apiVersion: kyverno.nirmata.io/v1alpha1 kind: Policy metadata : name : policy-namespace diff --git a/test/NetworkPolicy/policy-network-policy.yaml b/test/NetworkPolicy/policy-network-policy.yaml index 084bda2762..2c7d415ddc 100644 --- a/test/NetworkPolicy/policy-network-policy.yaml +++ b/test/NetworkPolicy/policy-network-policy.yaml @@ -1,4 +1,4 @@ -apiVersion: kubepolicy.nirmata.io/v1alpha1 +apiVersion: kyverno.nirmata.io/v1alpha1 kind: Policy metadata: name: policy-network-policy diff --git a/test/PersistentVolumeClaim/policy-PVC.yaml b/test/PersistentVolumeClaim/policy-PVC.yaml index 47e3c9ace6..7d45d2ae50 100644 --- a/test/PersistentVolumeClaim/policy-PVC.yaml +++ b/test/PersistentVolumeClaim/policy-PVC.yaml @@ -1,4 +1,4 @@ -apiVersion: kubepolicy.nirmata.io/v1alpha1 +apiVersion: kyverno.nirmata.io/v1alpha1 kind: Policy metadata: name: policy-pvc diff --git a/test/PodDisruptionBudget/policy-pdb.yaml b/test/PodDisruptionBudget/policy-pdb.yaml index 9af46f5fd0..dce6c993e0 100644 --- a/test/PodDisruptionBudget/policy-pdb.yaml +++ b/test/PodDisruptionBudget/policy-pdb.yaml @@ -1,4 +1,4 @@ -apiVersion: kubepolicy.nirmata.io/v1alpha1 +apiVersion: kyverno.nirmata.io/v1alpha1 kind: Policy metadata: name: policy-pdb diff --git a/test/PodTemplate/policy-PodTemplate.yaml b/test/PodTemplate/policy-PodTemplate.yaml index c3c789e082..bd19ba6d0f 100644 --- a/test/PodTemplate/policy-PodTemplate.yaml +++ b/test/PodTemplate/policy-PodTemplate.yaml @@ -1,4 +1,4 @@ -apiVersion: kubepolicy.nirmata.io/v1alpha1 +apiVersion: kyverno.nirmata.io/v1alpha1 kind: Policy metadata: name: test-podtemplate diff --git a/test/ResourceQuota/policy-quota-validation.yaml b/test/ResourceQuota/policy-quota-validation.yaml index e813d7fb07..5fe16379b2 100644 --- a/test/ResourceQuota/policy-quota-validation.yaml +++ b/test/ResourceQuota/policy-quota-validation.yaml @@ -1,4 +1,4 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.nirmata.io/v1alpha1 kind : Policy metadata : name : policy-quota-low-test-validation diff --git a/test/ResourceQuota/policy-quota.yaml b/test/ResourceQuota/policy-quota.yaml index e845eb56fb..fe131c5a74 100644 --- a/test/ResourceQuota/policy-quota.yaml +++ b/test/ResourceQuota/policy-quota.yaml @@ -1,4 +1,4 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.nirmata.io/v1alpha1 kind : Policy metadata : name : policy-quota-low-test diff --git a/test/Secret/policy-secret.yaml b/test/Secret/policy-secret.yaml index 315c374754..8e008d040c 100644 --- a/test/Secret/policy-secret.yaml +++ b/test/Secret/policy-secret.yaml @@ -1,4 +1,4 @@ -apiVersion: kubepolicy.nirmata.io/v1alpha1 +apiVersion: kyverno.nirmata.io/v1alpha1 kind: Policy metadata: name: policy-secrets diff --git a/test/Service/policy-service.yaml b/test/Service/policy-service.yaml index 8d2feb2200..c3ba48b24b 100644 --- a/test/Service/policy-service.yaml +++ b/test/Service/policy-service.yaml @@ -1,4 +1,4 @@ -apiVersion : kubepolicy.nirmata.io/v1alpha1 +apiVersion : kyverno.nirmata.io/v1alpha1 kind : Policy metadata : name : policy-service diff --git a/test/StatefulSet/policy-StatefulSet.yaml b/test/StatefulSet/policy-StatefulSet.yaml index 71ab13295b..9da7967d7a 100644 --- a/test/StatefulSet/policy-StatefulSet.yaml +++ b/test/StatefulSet/policy-StatefulSet.yaml @@ -1,4 +1,4 @@ -apiVersion: kubepolicy.nirmata.io/v1alpha1 +apiVersion: kyverno.nirmata.io/v1alpha1 kind: Policy metadata: name: policy-statefulset From 3857c6b9a593d778d068d62f7a24124f9072ad42 Mon Sep 17 00:00:00 2001 From: shivdudhani Date: Wed, 22 May 2019 12:01:33 -0700 Subject: [PATCH 13/19] remove enum conditions in crd for kinds --- definitions/install.yaml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/definitions/install.yaml b/definitions/install.yaml index f7ca441a23..a598c8f110 100644 --- a/definitions/install.yaml +++ b/definitions/install.yaml @@ -41,25 +41,6 @@ spec: type: array items: type: string - enum: - - ConfigMap - - CronJob - - DaemonSet - - Deployment - - Endpoints - - HorizontalPodAutoscaler - - Ingress - - Job - - LimitRange - - Namespace - - NetworkPolicy - - PersistentVolumeClaim - - PodDisruptionBudget - - PodTemplate - - ResourceQuota - - Secret - - Service - - StatefulSet name: type: string selector: From 09e0065d4cdd0000d204cd620f0f98958f6e4d68 Mon Sep 17 00:00:00 2001 From: kacejot Date: Wed, 22 May 2019 22:34:25 +0100 Subject: [PATCH 14/19] Finished mutating overlay. Added several tests --- pkg/engine/overlay.go | 309 +++++++++++++++++++++++++++++++++---- pkg/engine/overlay_test.go | 60 +++++-- 2 files changed, 329 insertions(+), 40 deletions(-) diff --git a/pkg/engine/overlay.go b/pkg/engine/overlay.go index 8c2ef40ac6..1fe49b5141 100644 --- a/pkg/engine/overlay.go +++ b/pkg/engine/overlay.go @@ -2,9 +2,11 @@ package engine import ( "encoding/json" + "fmt" "log" "reflect" - "strconv" + + jsonpatch "github.com/evanphx/json-patch" kubepolicy "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -37,10 +39,18 @@ func ProcessOverlay(policy kubepolicy.Policy, rawResource []byte, gvk metav1.Gro } func applyOverlay(resource, overlay interface{}, path string) ([]PatchBytes, error) { + var appliedPatches []PatchBytes + // resource item exists but has different type - replace // all subtree within this path by overlay if reflect.TypeOf(resource) != reflect.TypeOf(overlay) { - replaceResource(resource, overlay, path) + patch, err := replaceSubtree(overlay, path) + if err != nil { + return nil, err + } + + appliedPatches = append(appliedPatches, patch) + return appliedPatches, nil } switch typedOverlay := overlay.(type) { @@ -48,57 +58,169 @@ func applyOverlay(resource, overlay interface{}, path string) ([]PatchBytes, err typedResource := resource.(map[string]interface{}) for key, value := range typedOverlay { - path += "/" + key + if wrappedWithParentheses(key) { + key = key[1 : len(key)-1] + } + currentPath := path + key + "/" resourcePart, ok := typedResource[key] if ok { - applyOverlay(resourcePart, value, path) + patches, err := applyOverlay(resourcePart, value, currentPath) + if err != nil { + return nil, err + } + + appliedPatches = append(appliedPatches, patches...) + } else { - createSubtree(value, path) + patch, err := insertSubtree(value, currentPath) + if err != nil { + return nil, err + } + + appliedPatches = append(appliedPatches, patch) } } case []interface{}: typedResource := resource.([]interface{}) - applyOverlayToArray(typedResource, typedOverlay, path) + patches, err := applyOverlayToArray(typedResource, typedOverlay, path) + if err != nil { + return nil, err + } + + appliedPatches = append(appliedPatches, patches...) case string: - replaceResource(resource, overlay, path) + patch, err := replaceSubtree(overlay, path) + if err != nil { + return nil, err + } + + appliedPatches = append(appliedPatches, patch) case float64: - replaceResource(resource, overlay, path) + patch, err := replaceSubtree(overlay, path) + if err != nil { + return nil, err + } + + appliedPatches = append(appliedPatches, patch) case int64: - replaceResource(resource, overlay, path) + patch, err := replaceSubtree(overlay, path) + if err != nil { + return nil, err + } + + appliedPatches = append(appliedPatches, patch) } - return nil, nil + return appliedPatches, nil } -func applyOverlayToArray(resource, overlay []interface{}, path string) { +func applyOverlayToArray(resource, overlay []interface{}, path string) ([]PatchBytes, error) { + var appliedPatches []PatchBytes + if len(overlay) == 0 { + return nil, fmt.Errorf("overlay does not support empty arrays") + } + + if len(resource) == 0 { + patches, err := fillEmptyArray(overlay, path) + if err != nil { + return nil, err + } + + return patches, nil + } + + if reflect.TypeOf(resource[0]) != reflect.TypeOf(overlay[0]) { + return nil, fmt.Errorf("overlay array and resource array have elements of different types: %T and %T", overlay[0], resource[0]) + } + switch overlay[0].(type) { case map[string]interface{}: for _, overlayElement := range overlay { typedOverlay := overlayElement.(map[string]interface{}) anchors := GetAnchorsFromMap(typedOverlay) - if len(anchors) > 0 { - // Try to replace - for i, resourceElement := range resource { - path += "/" + strconv.Itoa(i) - typedResource := resourceElement.(map[string]interface{}) + currentPath := path + "0/" + for _, resourceElement := range resource { + typedResource := resourceElement.(map[string]interface{}) + if len(anchors) > 0 { if !skipArrayObject(typedResource, anchors) { - replaceResource(typedResource, typedOverlay, path) + patches, err := applyOverlay(resourceElement, overlayElement, currentPath) + if err != nil { + return nil, err + } + + appliedPatches = append(appliedPatches, patches...) + } + } else { + if hasNestedAnchors(overlayElement) { + patches, err := applyOverlay(resourceElement, overlayElement, currentPath) + if err != nil { + return nil, err + } + appliedPatches = append(appliedPatches, patches...) + } else { + patch, err := insertSubtree(overlayElement, currentPath) + if err != nil { + return nil, err + } + appliedPatches = append(appliedPatches, patch) } } - } else { - // Add new item to the front - path += "/0" - createSubtree(typedOverlay, path) + } + + } + default: + path += "0/" + for _, value := range overlay { + patch, err := insertSubtree(value, path) + if err != nil { + return nil, err + } + appliedPatches = append(appliedPatches, patch) + } + } + + return appliedPatches, nil +} + +// In case of empty resource array +// append all non-anchor items to front +func fillEmptyArray(overlay []interface{}, path string) ([]PatchBytes, error) { + var appliedPatches []PatchBytes + if len(overlay) == 0 { + return nil, fmt.Errorf("overlay does not support empty arrays") + } + + path += "0/" + + switch overlay[0].(type) { + case map[string]interface{}: + for _, overlayElement := range overlay { + typedOverlay := overlayElement.(map[string]interface{}) + anchors := GetAnchorsFromMap(typedOverlay) + + if len(anchors) == 0 { + patch, err := insertSubtree(overlayElement, path) + if err != nil { + return nil, err + } + + appliedPatches = append(appliedPatches, patch) } } default: - path += "/0" - for _, value := range overlay { - createSubtree(value, path) + for _, overlayElement := range overlay { + patch, err := insertSubtree(overlayElement, path) + if err != nil { + return nil, err + } + + appliedPatches = append(appliedPatches, patch) } } + + return appliedPatches, nil } func skipArrayObject(object, anchors map[string]interface{}) bool { @@ -118,11 +240,140 @@ func skipArrayObject(object, anchors map[string]interface{}) bool { return false } -func replaceResource(resource, overlay interface{}, path string) { - +func insertSubtree(overlay interface{}, path string) ([]byte, error) { + return processSubtree(overlay, path, "add") } -func createSubtree(overlayPart interface{}, path string) []PatchBytes { - - return nil +func replaceSubtree(overlay interface{}, path string) ([]byte, error) { + return processSubtree(overlay, path, "replace") +} + +func processSubtree(overlay interface{}, path string, op string) ([]byte, error) { + if len(path) > 1 && path[len(path)-1] == '/' { + path = path[:len(path)-1] + } + + if path == "" { + path = "/" + } + + value := prepareJSONValue(overlay) + patchStr := fmt.Sprintf(`{ "op": "%s", "path": "%s", "value": %s }`, op, path, value) + + // check the patch + _, err := jsonpatch.DecodePatch([]byte("[" + patchStr + "]")) + if err != nil { + return nil, err + } + + return []byte(patchStr), nil +} + +func prepareJSONValue(overlay interface{}) string { + switch typed := overlay.(type) { + case map[string]interface{}: + if len(typed) == 0 { + return "" + } + + if hasOnlyAnchors(overlay) { + return "" + } + + result := "" + for key, value := range typed { + jsonValue := prepareJSONValue(value) + + pair := fmt.Sprintf(`"%s":%s`, key, jsonValue) + + if result != "" { + result += ", " + } + + result += pair + } + + result = fmt.Sprintf(`{ %s }`, result) + return result + case []interface{}: + if len(typed) == 0 { + return "" + } + + if hasOnlyAnchors(overlay) { + return "" + } + + result := "" + for _, value := range typed { + jsonValue := prepareJSONValue(value) + + if result != "" { + result += ", " + } + + result += jsonValue + } + + result = fmt.Sprintf(`[ %s ]`, result) + return result + case string: + return fmt.Sprintf(`"%s"`, typed) + case float64: + return fmt.Sprintf("%f", typed) + case int64: + return fmt.Sprintf("%d", typed) + default: + return "" + } +} + +func hasOnlyAnchors(overlay interface{}) bool { + switch typed := overlay.(type) { + case map[string]interface{}: + if anchors := GetAnchorsFromMap(typed); len(anchors) == len(typed) { + return true + } + + for _, value := range typed { + if !hasOnlyAnchors(value) { + return false + } + } + + return true + case string: + return false + case float64: + return false + case int64: + return false + default: + return false + } +} + +func hasNestedAnchors(overlay interface{}) bool { + switch typed := overlay.(type) { + case map[string]interface{}: + if anchors := GetAnchorsFromMap(typed); len(anchors) > 0 { + return true + } + + for _, value := range typed { + if hasNestedAnchors(value) { + return true + } + } + + return false + case string: + return false + case float64: + return false + case int64: + return false + default: + return false + } } diff --git a/pkg/engine/overlay_test.go b/pkg/engine/overlay_test.go index ab508039b6..086fbe7511 100644 --- a/pkg/engine/overlay_test.go +++ b/pkg/engine/overlay_test.go @@ -2,24 +2,62 @@ package engine import ( "encoding/json" - "fmt" - "reflect" + "log" "testing" + jsonpatch "github.com/evanphx/json-patch" "gotest.tools/assert" ) -func TestApplyOverlay_BaseCase(t *testing.T) { - resource1Raw := []byte(`{ "dictionary": { "key1": "val1", "key2": "val2", "array": [ 1, 2 ] } }`) - resource2Raw := []byte(`{ "dictionary": "somestring" }`) +func TestApplyOverlay_NestedListWithAnchor(t *testing.T) { + resourceRaw := []byte(`{ "apiVersion": "v1", "kind": "Endpoints", "metadata": { "name": "test-endpoint", "labels": { "label": "test" } }, "subsets": [ { "addresses": [ { "ip": "192.168.10.171" } ], "ports": [ { "name": "secure-connection", "port": 443, "protocol": "TCP" } ] } ] }`) + overlayRaw := []byte(`{ "subsets": [ { "ports": [ { "(name)": "secure-connection", "port": 444, "protocol": "UDP" } ] } ] }`) - var resource1, resource2 interface{} + var resource, overlay interface{} - json.Unmarshal(resource1Raw, &resource1) - json.Unmarshal(resource2Raw, &resource2) + json.Unmarshal(resourceRaw, &resource) + json.Unmarshal(overlayRaw, &overlay) - fmt.Printf("First resource type: %v", reflect.TypeOf(resource1)) - fmt.Printf("Second resource type: %v", reflect.TypeOf(resource2)) + patches, err := applyOverlay(resource, overlay, "/") + assert.NilError(t, err) + assert.Assert(t, patches != nil) - assert.Assert(t, reflect.TypeOf(resource1) == reflect.TypeOf(resource2)) + patch := JoinPatches(patches) + decoded, err := jsonpatch.DecodePatch(patch) + assert.NilError(t, err) + assert.Assert(t, decoded != nil) + + patched, err := decoded.Apply(resourceRaw) + assert.NilError(t, err) + assert.Assert(t, patched != nil) + + expectedResult := []byte(`{"apiVersion":"v1","kind":"Endpoints","metadata":{"name":"test-endpoint","labels":{"label":"test"}},"subsets":[{"addresses":[{"ip":"192.168.10.171"}],"ports":[{"name":"secure-connection","port":444.000000,"protocol":"UDP"}]}]}`) + assert.Equal(t, string(expectedResult), string(patched)) +} + +func TestApplyOverlay_InsertIntoArray(t *testing.T) { + resourceRaw := []byte(`{ "apiVersion": "v1", "kind": "Endpoints", "metadata": { "name": "test-endpoint", "labels": { "label": "test" } }, "subsets": [ { "addresses": [ { "ip": "192.168.10.171" } ], "ports": [ { "name": "secure-connection", "port": 443, "protocol": "TCP" } ] } ] }`) + overlayRaw := []byte(`{ "subsets": [ { "addresses": [ { "ip": "192.168.10.172" }, { "ip": "192.168.10.173" } ], "ports": [ { "name": "insecure-connection", "port": 80, "protocol": "UDP" } ] } ] }`) + + var resource, overlay interface{} + + json.Unmarshal(resourceRaw, &resource) + json.Unmarshal(overlayRaw, &overlay) + + patches, err := applyOverlay(resource, overlay, "/") + assert.NilError(t, err) + assert.Assert(t, patches != nil) + + patch := JoinPatches(patches) + + decoded, err := jsonpatch.DecodePatch(patch) + assert.NilError(t, err) + assert.Assert(t, decoded != nil) + + patched, err := decoded.Apply(resourceRaw) + assert.NilError(t, err) + assert.Assert(t, patched != nil) + + log.Fatalf("%s", patched) + //assert.Equal(t, string(expectedResult), string(patched)) } From 1219063ff87559c3041a652e86ce42e6e491cb5b Mon Sep 17 00:00:00 2001 From: kacejot Date: Wed, 22 May 2019 22:43:19 +0100 Subject: [PATCH 15/19] Updated unit tests --- pkg/engine/overlay_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/engine/overlay_test.go b/pkg/engine/overlay_test.go index 086fbe7511..f3dcebd4fc 100644 --- a/pkg/engine/overlay_test.go +++ b/pkg/engine/overlay_test.go @@ -2,7 +2,6 @@ package engine import ( "encoding/json" - "log" "testing" jsonpatch "github.com/evanphx/json-patch" @@ -58,6 +57,6 @@ func TestApplyOverlay_InsertIntoArray(t *testing.T) { assert.NilError(t, err) assert.Assert(t, patched != nil) - log.Fatalf("%s", patched) - //assert.Equal(t, string(expectedResult), string(patched)) + expectedResult := []byte(`{"apiVersion":"v1","kind":"Endpoints","metadata":{"name":"test-endpoint","labels":{"label":"test"}},"subsets":[{"addresses":[{"ip":"192.168.10.172"},{"ip":"192.168.10.173"}],"ports":[{"name":"insecure-connection","port":80.000000,"protocol":"UDP"}]},{"addresses":[{"ip":"192.168.10.171"}],"ports":[{"name":"secure-connection","port":443,"protocol":"TCP"}]}]}`) + assert.Equal(t, string(expectedResult), string(patched)) } From 101870fb5e79c4050596b9ca524d20df5a700dec Mon Sep 17 00:00:00 2001 From: kacejot Date: Wed, 22 May 2019 22:54:38 +0100 Subject: [PATCH 16/19] Added Overlay logic to mutation handling --- pkg/engine/mutation.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/engine/mutation.go b/pkg/engine/mutation.go index 276f4bcd36..3d387d6f55 100644 --- a/pkg/engine/mutation.go +++ b/pkg/engine/mutation.go @@ -29,11 +29,11 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio // Process Overlay if rule.Mutation.Overlay != nil { - //overlayPatches, err := ProcessOverlay(rule.Mutation.Overlay, rawResource) + overlayPatches, err := ProcessOverlay(policy, rawResource, gvk) if err != nil { log.Printf("Overlay application has failed for rule %s in policy %s, err: %v\n", rule.Name, policy.ObjectMeta.Name, err) } else { - //policyPatches = append(policyPatches, overlayPatches...) + policyPatches = append(policyPatches, overlayPatches...) } } From 6825979238bdd827cc624bd60ffe52d3621b2d0f Mon Sep 17 00:00:00 2001 From: shivdudhani Date: Wed, 22 May 2019 17:29:26 -0700 Subject: [PATCH 17/19] update apiVersion in policy for examples --- examples/Validate/check_cpu_memory.yaml | 2 +- examples/Validate/check_hostpath.yaml | 2 +- examples/Validate/check_image_version.yaml | 2 +- examples/Validate/check_nodeport.yaml | 2 +- examples/Validate/check_probe_exists.yaml | 2 +- examples/Validate/check_probe_intervals.yaml | 2 +- examples/Validate/check_whitelist_registries.yaml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/Validate/check_cpu_memory.yaml b/examples/Validate/check_cpu_memory.yaml index f4a418296a..00bac02e72 100644 --- a/examples/Validate/check_cpu_memory.yaml +++ b/examples/Validate/check_cpu_memory.yaml @@ -1,4 +1,4 @@ -apiVersion : kyverno.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind: Policy metadata: name: check-cpu-memory diff --git a/examples/Validate/check_hostpath.yaml b/examples/Validate/check_hostpath.yaml index 35dd08225b..0ee2baf7b5 100644 --- a/examples/Validate/check_hostpath.yaml +++ b/examples/Validate/check_hostpath.yaml @@ -1,4 +1,4 @@ -apiVersion : kyverno.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind: Policy metadata: name: check-host-path diff --git a/examples/Validate/check_image_version.yaml b/examples/Validate/check_image_version.yaml index 15c8cb2d9a..8d41e4eb92 100644 --- a/examples/Validate/check_image_version.yaml +++ b/examples/Validate/check_image_version.yaml @@ -1,4 +1,4 @@ -apiVersion : kyverno.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind: Policy metadata: name: image-pull-policy diff --git a/examples/Validate/check_nodeport.yaml b/examples/Validate/check_nodeport.yaml index c2456f00e3..a8126e29b9 100644 --- a/examples/Validate/check_nodeport.yaml +++ b/examples/Validate/check_nodeport.yaml @@ -1,4 +1,4 @@ -apiVersion : kyverno.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind: Policy metadata: name: check-host-path diff --git a/examples/Validate/check_probe_exists.yaml b/examples/Validate/check_probe_exists.yaml index 442525a423..b109baddef 100644 --- a/examples/Validate/check_probe_exists.yaml +++ b/examples/Validate/check_probe_exists.yaml @@ -1,4 +1,4 @@ -apiVersion : kyverno.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind: Policy metadata: name: check-probe-exists diff --git a/examples/Validate/check_probe_intervals.yaml b/examples/Validate/check_probe_intervals.yaml index 15f93e4a88..3e866ecebd 100644 --- a/examples/Validate/check_probe_intervals.yaml +++ b/examples/Validate/check_probe_intervals.yaml @@ -1,4 +1,4 @@ -apiVersion : kyverno.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind: Policy metadata: name: check-probe-intervals diff --git a/examples/Validate/check_whitelist_registries.yaml b/examples/Validate/check_whitelist_registries.yaml index 386fe92cda..40b6beb7eb 100644 --- a/examples/Validate/check_whitelist_registries.yaml +++ b/examples/Validate/check_whitelist_registries.yaml @@ -1,4 +1,4 @@ -apiVersion : kyverno.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind: Policy metadata: name: check-whitelist-registries From ad835cf484efe61b39f3ab3a7fc42048b14f1dd5 Mon Sep 17 00:00:00 2001 From: shivdudhani Date: Wed, 22 May 2019 17:57:40 -0700 Subject: [PATCH 18/19] update apiVersion for test YAMLs and update spec.rules.generate type to object --- .../policy-cm-test.yaml | 2 +- .../policy-namespace-patch-cmgCG-sgCG.yaml | 8 ++++---- test/Ingress/policy-ingress.yaml | 2 +- test/Job/policy-job.yaml | 2 +- test/LimitRange/policy-limitrange.yaml | 2 +- test/Namespace/policy-namespace.yaml | 2 +- test/NetworkPolicy/policy-network-policy.yaml | 2 +- test/PersistentVolumeClaim/policy-PVC.yaml | 2 +- test/PodDisruptionBudget/policy-pdb.yaml | 2 +- test/PodTemplate/policy-PodTemplate.yaml | 2 +- test/ResourceQuota/policy-quota-validation.yaml | 2 +- test/ResourceQuota/policy-quota.yaml | 2 +- test/Secret/policy-secret.yaml | 2 +- test/Service/policy-service.yaml | 2 +- test/StatefulSet/policy-StatefulSet.yaml | 2 +- 15 files changed, 18 insertions(+), 18 deletions(-) diff --git a/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml b/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml index 9ae1f69d10..3c33a44a25 100644 --- a/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml +++ b/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml @@ -12,7 +12,7 @@ spec: matchLabels: LabelForSelector : "namespace2" generate : - - kind: ConfigMap + kind: ConfigMap name : copied-cm copyFrom : namespace : default diff --git a/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml b/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml index 522e3829c9..7272a9e56e 100644 --- a/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml +++ b/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml @@ -30,7 +30,7 @@ spec : matchLabels: LabelForSelector : "namespace2" generate : - - kind: ConfigMap + kind: ConfigMap name : copied-cm copyFrom : namespace : default @@ -46,7 +46,7 @@ spec : matchLabels: LabelForSelector : "namespace2" generate : - - kind: ConfigMap + kind: ConfigMap name : generated-cm data : secretData: "very sensitive data from cmg" @@ -63,7 +63,7 @@ spec : - Namespace name: ns2 generate : - - kind: Secret + kind: Secret name : generated-secrets data : foo : bar @@ -80,7 +80,7 @@ spec : - Namespace name: ns2 generate : - - kind: Secret + kind: Secret name : copied-secrets copyFrom : namespace : default diff --git a/test/Ingress/policy-ingress.yaml b/test/Ingress/policy-ingress.yaml index 220f741df6..99d757f82b 100644 --- a/test/Ingress/policy-ingress.yaml +++ b/test/Ingress/policy-ingress.yaml @@ -1,4 +1,4 @@ -apiVersion: kyverno.nirmata.io/v1alpha1 +apiVersion: kyverno.io/v1alpha1 kind: Policy metadata : name : policy-ingress diff --git a/test/Job/policy-job.yaml b/test/Job/policy-job.yaml index a9ef3e035d..8cc7dc84ff 100644 --- a/test/Job/policy-job.yaml +++ b/test/Job/policy-job.yaml @@ -1,4 +1,4 @@ -apiVersion: kyverno.nirmata.io/v1alpha1 +apiVersion: kyverno.io/v1alpha1 kind: Policy metadata: name: policy-job-perl-bigint diff --git a/test/LimitRange/policy-limitrange.yaml b/test/LimitRange/policy-limitrange.yaml index ccc8fee490..0bc2447bb4 100644 --- a/test/LimitRange/policy-limitrange.yaml +++ b/test/LimitRange/policy-limitrange.yaml @@ -1,4 +1,4 @@ -apiVersion : kyverno.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind : Policy metadata : name : policy-limitrange diff --git a/test/Namespace/policy-namespace.yaml b/test/Namespace/policy-namespace.yaml index 1f8657f579..72e27c0e80 100644 --- a/test/Namespace/policy-namespace.yaml +++ b/test/Namespace/policy-namespace.yaml @@ -1,4 +1,4 @@ -apiVersion: kyverno.nirmata.io/v1alpha1 +apiVersion: kyverno.io/v1alpha1 kind: Policy metadata : name : policy-namespace diff --git a/test/NetworkPolicy/policy-network-policy.yaml b/test/NetworkPolicy/policy-network-policy.yaml index 2c7d415ddc..d2989cf978 100644 --- a/test/NetworkPolicy/policy-network-policy.yaml +++ b/test/NetworkPolicy/policy-network-policy.yaml @@ -1,4 +1,4 @@ -apiVersion: kyverno.nirmata.io/v1alpha1 +apiVersion: kyverno.io/v1alpha1 kind: Policy metadata: name: policy-network-policy diff --git a/test/PersistentVolumeClaim/policy-PVC.yaml b/test/PersistentVolumeClaim/policy-PVC.yaml index 7d45d2ae50..f827bf77c3 100644 --- a/test/PersistentVolumeClaim/policy-PVC.yaml +++ b/test/PersistentVolumeClaim/policy-PVC.yaml @@ -1,4 +1,4 @@ -apiVersion: kyverno.nirmata.io/v1alpha1 +apiVersion: kyverno.io/v1alpha1 kind: Policy metadata: name: policy-pvc diff --git a/test/PodDisruptionBudget/policy-pdb.yaml b/test/PodDisruptionBudget/policy-pdb.yaml index dce6c993e0..74c48fcfe3 100644 --- a/test/PodDisruptionBudget/policy-pdb.yaml +++ b/test/PodDisruptionBudget/policy-pdb.yaml @@ -1,4 +1,4 @@ -apiVersion: kyverno.nirmata.io/v1alpha1 +apiVersion: kyverno.io/v1alpha1 kind: Policy metadata: name: policy-pdb diff --git a/test/PodTemplate/policy-PodTemplate.yaml b/test/PodTemplate/policy-PodTemplate.yaml index bd19ba6d0f..e2732b8fab 100644 --- a/test/PodTemplate/policy-PodTemplate.yaml +++ b/test/PodTemplate/policy-PodTemplate.yaml @@ -1,4 +1,4 @@ -apiVersion: kyverno.nirmata.io/v1alpha1 +apiVersion: kyverno.io/v1alpha1 kind: Policy metadata: name: test-podtemplate diff --git a/test/ResourceQuota/policy-quota-validation.yaml b/test/ResourceQuota/policy-quota-validation.yaml index 5fe16379b2..2431f31a50 100644 --- a/test/ResourceQuota/policy-quota-validation.yaml +++ b/test/ResourceQuota/policy-quota-validation.yaml @@ -1,4 +1,4 @@ -apiVersion : kyverno.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind : Policy metadata : name : policy-quota-low-test-validation diff --git a/test/ResourceQuota/policy-quota.yaml b/test/ResourceQuota/policy-quota.yaml index fe131c5a74..19f9730811 100644 --- a/test/ResourceQuota/policy-quota.yaml +++ b/test/ResourceQuota/policy-quota.yaml @@ -1,4 +1,4 @@ -apiVersion : kyverno.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind : Policy metadata : name : policy-quota-low-test diff --git a/test/Secret/policy-secret.yaml b/test/Secret/policy-secret.yaml index 8e008d040c..f09b152e64 100644 --- a/test/Secret/policy-secret.yaml +++ b/test/Secret/policy-secret.yaml @@ -1,4 +1,4 @@ -apiVersion: kyverno.nirmata.io/v1alpha1 +apiVersion: kyverno.io/v1alpha1 kind: Policy metadata: name: policy-secrets diff --git a/test/Service/policy-service.yaml b/test/Service/policy-service.yaml index c3ba48b24b..4cb99a1509 100644 --- a/test/Service/policy-service.yaml +++ b/test/Service/policy-service.yaml @@ -1,4 +1,4 @@ -apiVersion : kyverno.nirmata.io/v1alpha1 +apiVersion : kyverno.io/v1alpha1 kind : Policy metadata : name : policy-service diff --git a/test/StatefulSet/policy-StatefulSet.yaml b/test/StatefulSet/policy-StatefulSet.yaml index 9da7967d7a..b1f0e5b041 100644 --- a/test/StatefulSet/policy-StatefulSet.yaml +++ b/test/StatefulSet/policy-StatefulSet.yaml @@ -1,4 +1,4 @@ -apiVersion: kyverno.nirmata.io/v1alpha1 +apiVersion: kyverno.io/v1alpha1 kind: Policy metadata: name: policy-statefulset From 6a94179b616aad20ba15e3550b36a93d11f75daa Mon Sep 17 00:00:00 2001 From: shuting Date: Wed, 22 May 2019 20:07:41 -0700 Subject: [PATCH 19/19] update examples --- examples/generate/configMap.yaml | 20 +++++++++++ examples/generate/namespace.yaml | 7 ++++ examples/generate/policy_generate.yaml | 34 +++++++++++++++++++ .../overlay/policy_set_imagePullPolicy.yaml | 20 +++++++++++ .../overlay/set_imagePullPolicy_nginx.yaml | 23 +++++++++++++ examples/mutate/patches/endpoints.yaml | 13 +++++++ examples/mutate/patches/policy_endpoints.yaml | 27 +++++++++++++++ 7 files changed, 144 insertions(+) create mode 100644 examples/generate/configMap.yaml create mode 100644 examples/generate/namespace.yaml create mode 100644 examples/generate/policy_generate.yaml create mode 100644 examples/mutate/overlay/policy_set_imagePullPolicy.yaml create mode 100644 examples/mutate/overlay/set_imagePullPolicy_nginx.yaml create mode 100644 examples/mutate/patches/endpoints.yaml create mode 100644 examples/mutate/patches/policy_endpoints.yaml diff --git a/examples/generate/configMap.yaml b/examples/generate/configMap.yaml new file mode 100644 index 0000000000..8524e95d4a --- /dev/null +++ b/examples/generate/configMap.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: game-config + namespace: default + labels: + originalLabel : isHere +data: + ui.properties : | + color.good=green + color.bad=red + + game.properties : | + enemies=predators + lives=3 + + configmap.data: | + ns=default + labels=originalLabel + labelscount=1 diff --git a/examples/generate/namespace.yaml b/examples/generate/namespace.yaml new file mode 100644 index 0000000000..566684da82 --- /dev/null +++ b/examples/generate/namespace.yaml @@ -0,0 +1,7 @@ +kind: Namespace +apiVersion: v1 +metadata: + name: "ns2" + labels: + LabelForSelector : "namespace2" + \ No newline at end of file diff --git a/examples/generate/policy_generate.yaml b/examples/generate/policy_generate.yaml new file mode 100644 index 0000000000..8645a9736f --- /dev/null +++ b/examples/generate/policy_generate.yaml @@ -0,0 +1,34 @@ +apiVersion: kyverno.io/v1alpha1 +kind: Policy +metadata: + name: "zk-kafka-address" +spec: + rules: + - name: "copy-comfigmap" + resource : + kinds : + - Namespace + selector: + matchLabels: + LabelForSelector : "namespace2" + generate : + kind: ConfigMap + name : copied-cm + copyFrom : + namespace : default + name : game-config + data : + secretData: "data from cmg" + - name: "zk-kafka-address" + resource: + kinds: + - Namespace + selector: + matchExpressions: + - {key: LabelForSelector, operator: In, values: [namespace2]} + generate: + kind: ConfigMap + name: zk-kafka-address + data: + ZK_ADDRESS: "192.168.10.10:2181,192.168.10.11:2181,192.168.10.12:2181" + KAFKA_ADDRESS: "192.168.10.13:9092,192.168.10.14:9092,192.168.10.15:9092" diff --git a/examples/mutate/overlay/policy_set_imagePullPolicy.yaml b/examples/mutate/overlay/policy_set_imagePullPolicy.yaml new file mode 100644 index 0000000000..0bf8a3331c --- /dev/null +++ b/examples/mutate/overlay/policy_set_imagePullPolicy.yaml @@ -0,0 +1,20 @@ +apiVersion: kyverno.io/v1alpha1 +kind: Policy +metadata: + name: set-image-pull-policy +spec: + rules: + - name: set-image-pull-policy + resource: + kinds: + - Deployment + mutate: + overlay: + spec: + template: + spec: + containers: + # match images which end with :latest + - (image): "*:latest" + # set the imagePullPolicy to "Always" + imagePullPolicy: "Always" \ No newline at end of file diff --git a/examples/mutate/overlay/set_imagePullPolicy_nginx.yaml b/examples/mutate/overlay/set_imagePullPolicy_nginx.yaml new file mode 100644 index 0000000000..20d0713896 --- /dev/null +++ b/examples/mutate/overlay/set_imagePullPolicy_nginx.yaml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 1 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:latest + ports: + - containerPort: 80 + - name: ghost + image: ghost:latest diff --git a/examples/mutate/patches/endpoints.yaml b/examples/mutate/patches/endpoints.yaml new file mode 100644 index 0000000000..958d931482 --- /dev/null +++ b/examples/mutate/patches/endpoints.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Endpoints +metadata: + name: test-endpoint + labels: + label : test +subsets: +- addresses: + - ip: 192.168.10.171 + ports: + - name: secure-connection + port: 443 + protocol: TCP diff --git a/examples/mutate/patches/policy_endpoints.yaml b/examples/mutate/patches/policy_endpoints.yaml new file mode 100644 index 0000000000..4e36eda51d --- /dev/null +++ b/examples/mutate/patches/policy_endpoints.yaml @@ -0,0 +1,27 @@ +apiVersion : kyverno.io/v1alpha1 +kind : Policy +metadata : + name : policy-endpoints +spec : + rules: + - name: pEP + resource: + kinds : + - Endpoints + selector: + matchLabels: + label : test + mutate: + patches: + - path : "/subsets/0/ports/0/port" + op : replace + value: 9663 + - path : "/subsets/0" + op: add + value: + addresses: + - ip: "192.168.10.172" + ports: + - name: load-balancer-connection + port: 80 + protocol: UDP \ No newline at end of file