From ecca97b2a063cf029d961f9a289364c8335287af Mon Sep 17 00:00:00 2001 From: shivdudhani Date: Mon, 3 Jun 2019 16:02:34 -0700 Subject: [PATCH 1/2] update namespace trigger + update documentation --- README.md | 8 +- definitions/install.yaml | 3 - documentation/writing-policies-generate.md | 89 ++++++++++++++------- examples/generate/policy_generate.yaml | 18 ++--- examples/generate/policy_networkPolicy.yaml | 24 ++++++ pkg/apis/policy/v1alpha1/types.go | 9 +-- pkg/dclient/client.go | 45 +---------- pkg/engine/generation.go | 2 +- 8 files changed, 108 insertions(+), 90 deletions(-) create mode 100644 examples/generate/policy_networkPolicy.yaml diff --git a/README.md b/README.md index 90b7aeaefe..cb5dade870 100644 --- a/README.md +++ b/README.md @@ -98,12 +98,14 @@ spec: selector: matchExpressions: - {key: kafka, operator: Exists} - generate: + 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" + kind: ConfigMap + 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" ```` ### 4. More examples diff --git a/definitions/install.yaml b/definitions/install.yaml index a60b528bd1..743a16f1eb 100644 --- a/definitions/install.yaml +++ b/definitions/install.yaml @@ -102,14 +102,11 @@ spec: required: - kind - name - - namespace properties: kind: type: string name: type: string - namespace: - type: string clone: type: object required: diff --git a/documentation/writing-policies-generate.md b/documentation/writing-policies-generate.md index 77cc451841..6fcabefd4d 100644 --- a/documentation/writing-policies-generate.md +++ b/documentation/writing-policies-generate.md @@ -2,47 +2,82 @@ # Generate Configurations -```generatate``` feature can be applied to created namespaces to create new resources in them. This feature is useful when every namespace in a cluster must contain some basic required resources. The feature is available for policy rules in which the resource kind is Namespace. +```generate``` feature can be applied to created namespaces to create new resources in them. This feature is useful when every namespace in a cluster must contain some basic required resources. The feature is available for policy rules in which the resource kind is Namespace. -## Example +## Example 1 ````yaml -apiVersion : kyverno.io/v1alpha1 -kind : Policy -metadata : - name : basic-policy -spec : +apiVersion: kyverno.io/v1alpha1 +kind: Policy +metadata: + name: basic-policy +spec: rules: - - name: "Basic confog generator for all namespaces" + - name: "Basic config generator for all namespaces" resource: - kind: Namespace + kinds: + - Namespace + selector: + matchLabels: + LabelForSelector : "namespace2" generate: - # For now the next kinds are supported: - # ConfigMap - # Secret - - kind: ConfigMap + kind: ConfigMap name: default-config - copyFrom: + clone: namespace: default name: config-template - data: - DB_ENDPOINT: mongodb://mydomain.ua/db_stage:27017 - labels: - purpose: mongo - - kind: Secret + - name: "Basic config generator for all namespaces" + resource: + kinds: + - Namespace + selector: + matchLabels: + LabelForSelector : "namespace2" + generate: + kind: Secret name: mongo-creds data: - DB_USER: YWJyYWthZGFicmE= - DB_PASSWORD: YXBwc3dvcmQ= - labels: - purpose: mongo + data: + DB_USER: YWJyYWthZGFicmE= + DB_PASSWORD: YXBwc3dvcmQ= + metadata: + labels: + purpose: mongo ```` -In this example, when this policy is applied, any new namespace will receive 2 new resources after its creation: -* ConfigMap copied from default/config-template with added value DB_ENDPOINT. -* Secret with values DB_USER and DB_PASSWORD. +In this example, when this policy is applied, any new namespace that satisfies the label selector will receive 2 new resources after its creation: +* ConfigMap copied from default/config-template. +* Secret with values DB_USER and DB_PASSWORD, and label ```purpose: mongo```. -Both resources will contain a label ```purpose: mongo``` + +## Example 2 +````yaml +apiVersion: kyverno.io/v1alpha1 +kind: Policy +metadata: + name: "default" +spec: + rules: + - name: "deny-all-traffic" + resource: + kinds: + - Namespace + name: "*" + generate: + kind: NetworkPolicy + name: deny-all-traffic + data: + spec: + podSelector: + matchLabels: {} + matchExpressions: [] + policyTypes: [] + metadata: + annotations: {} + labels: + policyname: "default" +```` +In this example, when this policy is applied, any new namespace will receive a new NetworkPolicy resource based on the specified template that by default denies all inbound and outbound traffic. --- *Read Next >> [Testing Policies](/documentation/testing-policies.md)* diff --git a/examples/generate/policy_generate.yaml b/examples/generate/policy_generate.yaml index 8645a9736f..964d79eee7 100644 --- a/examples/generate/policy_generate.yaml +++ b/examples/generate/policy_generate.yaml @@ -14,21 +14,21 @@ spec: generate : kind: ConfigMap name : copied-cm - copyFrom : + clone: namespace : default name : game-config - data : - secretData: "data from cmg" - name: "zk-kafka-address" - resource: + resource: kinds: - - Namespace + - Namespace selector: - matchExpressions: + matchExpressions: - {key: LabelForSelector, operator: In, values: [namespace2]} - generate: + 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" + kind: ConfigMap + 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" \ No newline at end of file diff --git a/examples/generate/policy_networkPolicy.yaml b/examples/generate/policy_networkPolicy.yaml new file mode 100644 index 0000000000..b62d0273f3 --- /dev/null +++ b/examples/generate/policy_networkPolicy.yaml @@ -0,0 +1,24 @@ +apiVersion: kyverno.io/v1alpha1 +kind: Policy +metadata: + name: "default" +spec: + rules: + - name: "deny-all-traffic" + resource: + kinds: + - Namespace + name: "*" + generate: + kind: NetworkPolicy + name: deny-all-traffic + data: + spec: + podSelector: + matchLabels: {} + matchExpressions: [] + policyTypes: [] + metadata: + annotations: {} + labels: + policyname: "default" \ No newline at end of file diff --git a/pkg/apis/policy/v1alpha1/types.go b/pkg/apis/policy/v1alpha1/types.go index d489e967d7..95a18b850c 100644 --- a/pkg/apis/policy/v1alpha1/types.go +++ b/pkg/apis/policy/v1alpha1/types.go @@ -61,11 +61,10 @@ type Validation struct { // Generation describes which resources will be created when other resource is created type Generation struct { - Kind string `json:"kind"` - Name string `json:"name"` - Namespace string `json:"namespace"` - Data interface{} `json:"data"` - Clone *CloneFrom `json:"clone"` + Kind string `json:"kind"` + Name string `json:"name"` + Data interface{} `json:"data"` + Clone *CloneFrom `json:"clone"` } // CloneFrom - location of a Secret or a ConfigMap diff --git a/pkg/dclient/client.go b/pkg/dclient/client.go index a2ddd2d008..66428ef08c 100644 --- a/pkg/dclient/client.go +++ b/pkg/dclient/client.go @@ -1,7 +1,6 @@ package client import ( - "errors" "fmt" "strings" "time" @@ -166,41 +165,7 @@ func ConvertToRuntimeObject(obj *unstructured.Unstructured) (*runtime.Object, er return &runtimeObj, nil } -// only support 2 levels of keys -// To-Do support multiple levels of key -func keysExist(data map[string]interface{}, keys ...string) bool { - var v interface{} - var t map[string]interface{} - var ok bool - for _, key := range keys { - ks := strings.Split(key, ".") - if len(ks) > 2 { - glog.Error("Only support 2 levels of keys from root. Support to be extendend in future") - return false - } - if v, ok = data[ks[0]]; !ok { - glog.Infof("key %s does not exist", key) - return false - } - if len(ks) == 2 { - if t, ok = v.(map[string]interface{}); !ok { - glog.Error("expecting type map[string]interface{}") - } - return keyExist(t, ks[1]) - } - } - return true -} - -func keyExist(data map[string]interface{}, key string) (ok bool) { - if _, ok = data[key]; !ok { - glog.Infof("key %s does not exist", key) - } - return ok -} - -// support mode 'data' -> create resource -// To-Do: support 'from' -> copy/clone the resource +// GenerateResource creates resource of the specified kind(supports 'clone' & 'data') func (c *Client) GenerateResource(generator types.Generation, namespace string) error { var err error rGVR := c.getGVRFromKind(generator.Kind) @@ -214,10 +179,6 @@ func (c *Client) GenerateResource(generator types.Generation, namespace string) utilruntime.HandleError(err) return err } - // verify if mandatory attributes have been defined - if !keysExist(rdata, "kind", "apiVersion", "metadata.name", "metadata.namespace") { - return errors.New("mandatory keys not defined") - } } // clone -> copy from existing resource if generator.Clone != nil { @@ -230,7 +191,7 @@ func (c *Client) GenerateResource(generator types.Generation, namespace string) resource.SetUnstructuredContent(rdata) resource.SetName(generator.Name) - resource.SetNamespace(generator.Namespace) + resource.SetNamespace(namespace) resource.SetResourceVersion("") err = c.waitUntilNamespaceIsCreated(namespace) @@ -238,7 +199,7 @@ func (c *Client) GenerateResource(generator types.Generation, namespace string) glog.Errorf("Can't create a resource %s: %v", generator.Name, err) return nil } - _, err = c.CreateResource(rGVR.Resource, generator.Namespace, resource) + _, err = c.CreateResource(rGVR.Resource, namespace, resource) if err != nil { return err } diff --git a/pkg/engine/generation.go b/pkg/engine/generation.go index eb91ad3944..b4e45a672e 100644 --- a/pkg/engine/generation.go +++ b/pkg/engine/generation.go @@ -46,6 +46,6 @@ func applyRuleGenerator(client *client.Client, rawResource []byte, generator *ku if err != nil { return fmt.Errorf("Unable to apply generator for %s '%s/%s' : %v", generator.Kind, namespace, generator.Name, err) } - glog.Infof("Successfully applied generator %s/%s", generator.Kind, generator.Name) + glog.Infof("Successfully applied generator %s '%s/%s'", generator.Kind, namespace, generator.Name) return nil } From 5c71cc9d5834777653db2026ea0972acaadbbf89 Mon Sep 17 00:00:00 2001 From: shivdudhani Date: Mon, 3 Jun 2019 16:09:14 -0700 Subject: [PATCH 2/2] update test examples --- .../policy-cm-test.yaml | 6 ++---- .../policy-namespace-patch-cmgCG-sgCG.yaml | 18 ++++++++---------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml b/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml index 3c33a44a25..fa4f831fff 100644 --- a/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml +++ b/test/ConfigMapGenerator-SecretGenerator/policy-cm-test.yaml @@ -14,8 +14,6 @@ spec: generate : kind: ConfigMap name : copied-cm - copyFrom : + clone: namespace : default - name : game-config - data : - secretData: "data from cmg" \ No newline at end of file + name : game-config \ No newline at end of file diff --git a/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml b/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml index 7272a9e56e..dd19f398af 100644 --- a/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml +++ b/test/ConfigMapGenerator-SecretGenerator/policy-namespace-patch-cmgCG-sgCG.yaml @@ -32,11 +32,9 @@ spec : generate : kind: ConfigMap name : copied-cm - copyFrom : + clone: namespace : default name : game-config - data : - secretData: "data from cmg" - name: "generateCM" resource : @@ -49,13 +47,13 @@ spec : kind: ConfigMap name : generated-cm data : - secretData: "very sensitive data from cmg" - database: mongodb - database_uri: mongodb://localhost:27017 - - keys: | - image.public.key=771 - rsa.public.key=42 + data: + secretData: "very sensitive data from cmg" + database: mongodb + database_uri: mongodb://localhost:27017 + keys: | + image.public.key=771 + rsa.public.key=42 - name: "generateSecret" resource :