mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
Merge pull request #135 from nirmata/21_enhancement
update namespace trigger + update documentation
This commit is contained in:
commit
1dcdb0033c
10 changed files with 118 additions and 104 deletions
|
@ -98,12 +98,14 @@ spec:
|
||||||
selector:
|
selector:
|
||||||
matchExpressions:
|
matchExpressions:
|
||||||
- {key: kafka, operator: Exists}
|
- {key: kafka, operator: Exists}
|
||||||
generate:
|
generate:
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
name: zk-kafka-address
|
name: zk-kafka-address
|
||||||
data:
|
data:
|
||||||
ZK_ADDRESS: "192.168.10.10:2181,192.168.10.11:2181,192.168.10.12:2181"
|
kind: ConfigMap
|
||||||
KAFKA_ADDRESS: "192.168.10.13:9092,192.168.10.14:9092,192.168.10.15:9092"
|
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
|
### 4. More examples
|
||||||
|
|
|
@ -102,14 +102,11 @@ spec:
|
||||||
required:
|
required:
|
||||||
- kind
|
- kind
|
||||||
- name
|
- name
|
||||||
- namespace
|
|
||||||
properties:
|
properties:
|
||||||
kind:
|
kind:
|
||||||
type: string
|
type: string
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
namespace:
|
|
||||||
type: string
|
|
||||||
clone:
|
clone:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
|
|
|
@ -2,47 +2,82 @@
|
||||||
|
|
||||||
# Generate Configurations
|
# 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
|
````yaml
|
||||||
apiVersion : kyverno.io/v1alpha1
|
apiVersion: kyverno.io/v1alpha1
|
||||||
kind : Policy
|
kind: Policy
|
||||||
metadata :
|
metadata:
|
||||||
name : basic-policy
|
name: basic-policy
|
||||||
spec :
|
spec:
|
||||||
rules:
|
rules:
|
||||||
- name: "Basic confog generator for all namespaces"
|
- name: "Basic config generator for all namespaces"
|
||||||
resource:
|
resource:
|
||||||
kind: Namespace
|
kinds:
|
||||||
|
- Namespace
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
LabelForSelector : "namespace2"
|
||||||
generate:
|
generate:
|
||||||
# For now the next kinds are supported:
|
kind: ConfigMap
|
||||||
# ConfigMap
|
|
||||||
# Secret
|
|
||||||
- kind: ConfigMap
|
|
||||||
name: default-config
|
name: default-config
|
||||||
copyFrom:
|
clone:
|
||||||
namespace: default
|
namespace: default
|
||||||
name: config-template
|
name: config-template
|
||||||
data:
|
- name: "Basic config generator for all namespaces"
|
||||||
DB_ENDPOINT: mongodb://mydomain.ua/db_stage:27017
|
resource:
|
||||||
labels:
|
kinds:
|
||||||
purpose: mongo
|
- Namespace
|
||||||
- kind: Secret
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
LabelForSelector : "namespace2"
|
||||||
|
generate:
|
||||||
|
kind: Secret
|
||||||
name: mongo-creds
|
name: mongo-creds
|
||||||
data:
|
data:
|
||||||
DB_USER: YWJyYWthZGFicmE=
|
data:
|
||||||
DB_PASSWORD: YXBwc3dvcmQ=
|
DB_USER: YWJyYWthZGFicmE=
|
||||||
labels:
|
DB_PASSWORD: YXBwc3dvcmQ=
|
||||||
purpose: mongo
|
metadata:
|
||||||
|
labels:
|
||||||
|
purpose: mongo
|
||||||
````
|
````
|
||||||
|
|
||||||
In this example, when this policy is applied, any new namespace will receive 2 new resources after its creation:
|
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 with added value DB_ENDPOINT.
|
* ConfigMap copied from default/config-template.
|
||||||
* Secret with values DB_USER and DB_PASSWORD.
|
* 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.
|
||||||
|
|
||||||
---
|
---
|
||||||
<small>*Read Next >> [Testing Policies](/documentation/testing-policies.md)*</small>
|
<small>*Read Next >> [Testing Policies](/documentation/testing-policies.md)*</small>
|
||||||
|
|
|
@ -14,21 +14,21 @@ spec:
|
||||||
generate :
|
generate :
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
name : copied-cm
|
name : copied-cm
|
||||||
copyFrom :
|
clone:
|
||||||
namespace : default
|
namespace : default
|
||||||
name : game-config
|
name : game-config
|
||||||
data :
|
|
||||||
secretData: "data from cmg"
|
|
||||||
- name: "zk-kafka-address"
|
- name: "zk-kafka-address"
|
||||||
resource:
|
resource:
|
||||||
kinds:
|
kinds:
|
||||||
- Namespace
|
- Namespace
|
||||||
selector:
|
selector:
|
||||||
matchExpressions:
|
matchExpressions:
|
||||||
- {key: LabelForSelector, operator: In, values: [namespace2]}
|
- {key: LabelForSelector, operator: In, values: [namespace2]}
|
||||||
generate:
|
generate:
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
name: zk-kafka-address
|
name: zk-kafka-address
|
||||||
data:
|
data:
|
||||||
ZK_ADDRESS: "192.168.10.10:2181,192.168.10.11:2181,192.168.10.12:2181"
|
kind: ConfigMap
|
||||||
KAFKA_ADDRESS: "192.168.10.13:9092,192.168.10.14:9092,192.168.10.15:9092"
|
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"
|
24
examples/generate/policy_networkPolicy.yaml
Normal file
24
examples/generate/policy_networkPolicy.yaml
Normal file
|
@ -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"
|
|
@ -61,11 +61,10 @@ type Validation struct {
|
||||||
|
|
||||||
// Generation describes which resources will be created when other resource is created
|
// Generation describes which resources will be created when other resource is created
|
||||||
type Generation struct {
|
type Generation struct {
|
||||||
Kind string `json:"kind"`
|
Kind string `json:"kind"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Namespace string `json:"namespace"`
|
Data interface{} `json:"data"`
|
||||||
Data interface{} `json:"data"`
|
Clone *CloneFrom `json:"clone"`
|
||||||
Clone *CloneFrom `json:"clone"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloneFrom - location of a Secret or a ConfigMap
|
// CloneFrom - location of a Secret or a ConfigMap
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -166,41 +165,7 @@ func ConvertToRuntimeObject(obj *unstructured.Unstructured) (*runtime.Object, er
|
||||||
return &runtimeObj, nil
|
return &runtimeObj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// only support 2 levels of keys
|
// GenerateResource creates resource of the specified kind(supports 'clone' & 'data')
|
||||||
// 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
|
|
||||||
func (c *Client) GenerateResource(generator types.Generation, namespace string) error {
|
func (c *Client) GenerateResource(generator types.Generation, namespace string) error {
|
||||||
var err error
|
var err error
|
||||||
rGVR := c.getGVRFromKind(generator.Kind)
|
rGVR := c.getGVRFromKind(generator.Kind)
|
||||||
|
@ -214,10 +179,6 @@ func (c *Client) GenerateResource(generator types.Generation, namespace string)
|
||||||
utilruntime.HandleError(err)
|
utilruntime.HandleError(err)
|
||||||
return 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
|
// clone -> copy from existing resource
|
||||||
if generator.Clone != nil {
|
if generator.Clone != nil {
|
||||||
|
@ -230,7 +191,7 @@ func (c *Client) GenerateResource(generator types.Generation, namespace string)
|
||||||
|
|
||||||
resource.SetUnstructuredContent(rdata)
|
resource.SetUnstructuredContent(rdata)
|
||||||
resource.SetName(generator.Name)
|
resource.SetName(generator.Name)
|
||||||
resource.SetNamespace(generator.Namespace)
|
resource.SetNamespace(namespace)
|
||||||
resource.SetResourceVersion("")
|
resource.SetResourceVersion("")
|
||||||
|
|
||||||
err = c.waitUntilNamespaceIsCreated(namespace)
|
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)
|
glog.Errorf("Can't create a resource %s: %v", generator.Name, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_, err = c.CreateResource(rGVR.Resource, generator.Namespace, resource)
|
_, err = c.CreateResource(rGVR.Resource, namespace, resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,6 @@ func applyRuleGenerator(client *client.Client, rawResource []byte, generator *ku
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Unable to apply generator for %s '%s/%s' : %v", generator.Kind, namespace, generator.Name, err)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,6 @@ spec:
|
||||||
generate :
|
generate :
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
name : copied-cm
|
name : copied-cm
|
||||||
copyFrom :
|
clone:
|
||||||
namespace : default
|
namespace : default
|
||||||
name : game-config
|
name : game-config
|
||||||
data :
|
|
||||||
secretData: "data from cmg"
|
|
|
@ -32,11 +32,9 @@ spec :
|
||||||
generate :
|
generate :
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
name : copied-cm
|
name : copied-cm
|
||||||
copyFrom :
|
clone:
|
||||||
namespace : default
|
namespace : default
|
||||||
name : game-config
|
name : game-config
|
||||||
data :
|
|
||||||
secretData: "data from cmg"
|
|
||||||
|
|
||||||
- name: "generateCM"
|
- name: "generateCM"
|
||||||
resource :
|
resource :
|
||||||
|
@ -49,13 +47,13 @@ spec :
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
name : generated-cm
|
name : generated-cm
|
||||||
data :
|
data :
|
||||||
secretData: "very sensitive data from cmg"
|
data:
|
||||||
database: mongodb
|
secretData: "very sensitive data from cmg"
|
||||||
database_uri: mongodb://localhost:27017
|
database: mongodb
|
||||||
|
database_uri: mongodb://localhost:27017
|
||||||
keys: |
|
keys: |
|
||||||
image.public.key=771
|
image.public.key=771
|
||||||
rsa.public.key=42
|
rsa.public.key=42
|
||||||
|
|
||||||
- name: "generateSecret"
|
- name: "generateSecret"
|
||||||
resource :
|
resource :
|
||||||
|
|
Loading…
Add table
Reference in a new issue