1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00

Merge pull request #238 from nirmata/221_resources_provide_exception

221 resources provide exception
This commit is contained in:
Shivkumar Dudhani 2019-07-26 07:35:31 -04:00 committed by GitHub
commit 96393ed6e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
72 changed files with 981 additions and 605 deletions

View file

@ -34,45 +34,88 @@ spec:
type: object type: object
required: required:
- name - name
- resource - match
properties: properties:
name: name:
type: string type: string
resource: match:
type: object type: object
required: required:
- kinds - resources
properties: properties:
kinds: resources:
type: array type: object
items: required:
type: string - kinds
name:
type: string
namespace:
type: string
selector:
properties: properties:
matchLabels: kinds:
type: object
additionalProperties:
type: string
matchExpressions:
type: array type: array
items: items:
type: object type: string
required: name:
- key type: string
- operator namespace:
properties: type: string
key: selector:
properties:
matchLabels:
type: object
additionalProperties:
type: string type: string
operator: matchExpressions:
type: array
items:
type: object
required:
- key
- operator
properties:
key:
type: string
operator:
type: string
values:
type: array
items:
type: string
exclude:
type: object
required:
- resources
properties:
resources:
type: object
properties:
kinds:
type: array
items:
type: string
name:
type: string
namespace:
type: string
selector:
properties:
matchLabels:
type: object
additionalProperties:
type: string type: string
values: matchExpressions:
type: array type: array
items: items:
type: string type: object
required:
- key
- operator
properties:
key:
type: string
operator:
type: string
values:
type: array
items:
type: string
mutate: mutate:
type: object type: object
properties: properties:

View file

@ -26,51 +26,96 @@ spec:
validationFailureAction: validationFailureAction:
type: string type: string
enum: enum:
- block - enforce # blocks the resorce api-reques if a rule fails. Default behavior
- report - audit # allows resource creationg and reports the failed validation rules as violations
rules: rules:
type: array type: array
items: items:
type: object type: object
required: required:
- name - name
- resource - match
properties: properties:
name: name:
type: string type: string
resource: match:
type: object type: object
required: required:
- kinds - resources
properties: properties:
kinds: resources:
type: array type: object
items: required:
type: string - kinds
name:
type: string
selector:
properties: properties:
matchLabels: kinds:
type: object
additionalProperties:
type: string
matchExpressions:
type: array type: array
items: items:
type: object type: string
required: name:
- key type: string
- operator namespace:
properties: type: string
key: selector:
properties:
matchLabels:
type: object
additionalProperties:
type: string type: string
operator: matchExpressions:
type: array
items:
type: object
required:
- key
- operator
properties:
key:
type: string
operator:
type: string
values:
type: array
items:
type: string
exclude:
type: object
required:
- resources
properties:
resources:
type: object
properties:
kinds:
type: array
items:
type: string
name:
type: string
namespace:
type: string
selector:
properties:
matchLabels:
type: object
additionalProperties:
type: string type: string
values: matchExpressions:
type: array type: array
items: items:
type: string type: object
required:
- key
- operator
properties:
key:
type: string
operator:
type: string
values:
type: array
items:
type: string
mutate: mutate:
type: object type: object
properties: properties:

View file

@ -5,12 +5,13 @@ metadata :
spec : spec :
rules: rules:
- name: add-label - name: add-label
resource: match:
kinds : resources:
- Deployment kinds :
selector : - Deployment
matchLabels : selector :
cli: test matchLabels :
cli: test
mutate: mutate:
patches: patches:
- path: /metadata/labels/isMutated - path: /metadata/labels/isMutated
@ -20,12 +21,13 @@ spec :
op: replace op: replace
value: "nginx_is_mutated" value: "nginx_is_mutated"
- name: check-image - name: check-image
resource: match:
kinds : resources:
- Deployment kinds :
selector : - Deployment
matchLabels : selector :
cli: test matchLabels :
cli: test
validate: validate:
message: "The imagePullPolicy must be Always when using image nginx" message: "The imagePullPolicy must be Always when using image nginx"
pattern: pattern:

View file

@ -5,15 +5,17 @@ metadata:
spec: spec:
rules: rules:
- name: image-pull-policy - name: image-pull-policy
resource: match:
kinds: resources:
- Deployment kinds:
# - StatefulSet - Deployment
# name: "my-deployment" exclude:
# selector : resources:
# matchLabels: name: nginx-deployment1
# app.type: prod selector :
# namespace: "my-namespace" matchLabels:
app: nginx1
namespace: "default"
mutate: mutate:
overlay: overlay:
spec: spec:

View file

@ -5,11 +5,12 @@ metadata:
spec: spec:
rules: rules:
- name: check-registries - name: check-registries
resource: match:
kinds: resources:
- Deployment kinds:
- StatefulSet - Deployment
namespace: default - StatefulSet
namespace: default
validate: validate:
message: "Registry is not allowed" message: "Registry is not allowed"
pattern: pattern:

View file

@ -5,22 +5,19 @@ metadata:
spec: spec:
rules: rules:
- name: "deny-ingress-traffic" - name: "deny-ingress-traffic"
resource: match:
kinds: resources:
- Namespace kinds:
name: "devtest" - Namespace
name: "devtest"
generate: generate:
kind: NetworkPolicy kind: NetworkPolicy
name: deny-ingress-traffic name: deny-ingress-traffic
data: data:
spec: spec:
podSelector: policyTypes:
matchLabels: {} - Ingress
matchExpressions: []
policyTypes:
- Ingress
metadata: metadata:
annotations: {}
labels: labels:
policyname: "default" policyname: "default"
# kind: ConfigMap # kind: ConfigMap

View file

@ -5,12 +5,13 @@ metadata:
spec: spec:
rules: rules:
- name: validate-runAsNonRoot - name: validate-runAsNonRoot
resource: match:
kinds: resources:
- Deployment kinds:
selector : - Deployment
matchLabels: selector :
app.type: prod matchLabels:
app.type: prod
validate: validate:
message: "security context 'runAsNonRoot' shoud be set to true" message: "security context 'runAsNonRoot' shoud be set to true"
pattern: pattern:

View file

@ -5,9 +5,10 @@ metadata :
spec: spec:
rules: rules:
- name: check-readinessProbe-exists - name: check-readinessProbe-exists
resource: match:
kinds : resources:
- Pod kinds :
- Pod
validate: validate:
message: "readinessProbe is required" message: "readinessProbe is required"
pattern: pattern:
@ -17,9 +18,10 @@ spec:
readinessProbe: readinessProbe:
successThreshold: ">1" successThreshold: ">1"
- name: check-livenessProbe-exists - name: check-livenessProbe-exists
resource: match:
kinds : resources:
- Pod kinds :
- Pod
validate: validate:
message: "livenessProbe is required" message: "livenessProbe is required"
pattern: pattern:

View file

@ -3,12 +3,13 @@ kind: Policy
metadata: metadata:
name: policy-qos name: policy-qos
spec: spec:
validationFailureAction: "audit" # validationFailureAction: "audit"
rules: rules:
- name: add-memory-limit - name: add-memory-limit
resource: match:
kinds: resources:
- Deployment kinds:
- Deployment
mutate: mutate:
overlay: overlay:
spec: spec:
@ -21,10 +22,12 @@ spec:
limits: limits:
# add memory limit if it is not exist # add memory limit if it is not exist
"+(memory)": "300Mi" "+(memory)": "300Mi"
"+(cpu)": "100"
- name: check-cpu-memory-limits - name: check-cpu-memory-limits
resource: match:
kinds: resources:
- Deployment kinds:
- Deployment
validate: validate:
message: "Resource limits are required for CPU and memory" message: "Resource limits are required for CPU and memory"
pattern: pattern:

View file

@ -5,12 +5,13 @@ metadata:
spec: spec:
rules: rules:
- name: validate-user-privilege - name: validate-user-privilege
resource: match:
kinds: resources:
- Deployment kinds:
selector : - Deployment
matchLabels: selector :
app.type: prod matchLabels:
app.type: prod
validate: validate:
message: "validate container security contexts" message: "validate container security contexts"
pattern: pattern:

View file

@ -5,12 +5,13 @@ metadata :
spec : spec :
rules: rules:
- name: "Basic clone config generator for all namespaces" - name: "Basic clone config generator for all namespaces"
resource: match:
kinds: resources:
- Namespace kinds:
selector: - Namespace
matchLabels: selector:
LabelForSelector : "namespace2" matchLabels:
LabelForSelector : "namespace2"
generate: generate:
kind: ConfigMap kind: ConfigMap
name: default-config name: default-config
@ -18,12 +19,13 @@ spec :
namespace: default namespace: default
name: config-template name: config-template
- name: "Basic config generator for all namespaces" - name: "Basic config generator for all namespaces"
resource: match:
kinds: resources:
- Namespace kinds:
selector: - Namespace
matchLabels: selector:
LabelForSelector : "namespace2" matchLabels:
LabelForSelector : "namespace2"
generate: generate:
kind: Secret kind: Secret
name: mongo-creds name: mongo-creds

View file

@ -5,12 +5,13 @@ metadata:
spec: spec:
rules: rules:
- name: "copy-comfigmap" - name: "copy-comfigmap"
resource : match:
kinds : resources:
- Namespace kinds :
selector: - Namespace
matchLabels: selector:
LabelForSelector : "namespace2" matchLabels:
LabelForSelector : "namespace2"
generate : generate :
kind: ConfigMap kind: ConfigMap
name : copied-cm name : copied-cm
@ -18,12 +19,13 @@ spec:
namespace : default namespace : default
name : game-config name : game-config
- name: "zk-kafka-address" - name: "zk-kafka-address"
resource: match:
kinds: resources:
- Namespace kinds:
selector: - Namespace
matchExpressions: selector:
- {key: LabelForSelector, operator: In, values: [namespace2]} matchExpressions:
- {key: LabelForSelector, operator: In, values: [namespace2]}
generate: generate:
kind: ConfigMap kind: ConfigMap
name: zk-kafka-address name: zk-kafka-address

View file

@ -5,10 +5,11 @@ metadata:
spec: spec:
rules: rules:
- name: "deny-all-traffic" - name: "deny-all-traffic"
resource: match:
kinds: resources:
- Namespace kinds:
name: "*" - Namespace
name: "*"
generate: generate:
kind: NetworkPolicy kind: NetworkPolicy
name: deny-all-traffic name: deny-all-traffic

View file

@ -5,9 +5,10 @@ metadata:
spec: spec:
rules: rules:
- name: set-image-pull-policy - name: set-image-pull-policy
resource: match:
kinds: resources:
- Deployment kinds:
- Deployment
mutate: mutate:
overlay: overlay:
spec: spec:

View file

@ -5,12 +5,13 @@ metadata :
spec : spec :
rules: rules:
- name: pEP - name: pEP
resource: match:
kinds : resources:
- Endpoints kinds :
selector: - Endpoints
matchLabels: selector:
label : test matchLabels:
label : test
mutate: mutate:
patches: patches:
- path : "/subsets/0/ports/0/port" - path : "/subsets/0/ports/0/port"

View file

@ -5,9 +5,10 @@ metadata:
spec: spec:
rules: rules:
- name: check-defined - name: check-defined
resource: match:
kinds: resources:
- Deployment kinds:
- Deployment
validate: validate:
message: "Resource limits are required for CPU and memory" message: "Resource limits are required for CPU and memory"
pattern: pattern:
@ -22,9 +23,10 @@ spec:
cpu: "?*" cpu: "?*"
- name: check-cpu - name: check-cpu
resource: match:
kinds: resources:
- Deployment kinds:
- Deployment
validate: validate:
message: "CPU request should be less than 4" message: "CPU request should be less than 4"
pattern: pattern:

View file

@ -5,9 +5,10 @@ metadata:
spec: spec:
rules: rules:
- name: check-host-path - name: check-host-path
resource: match:
kinds: resources:
- Pod kinds:
- Pod
validate: validate:
message: "Host path is not allowed" message: "Host path is not allowed"
pattern: pattern:

View file

@ -5,9 +5,10 @@ metadata:
spec: spec:
rules: rules:
- name: image-pull-policy - name: image-pull-policy
resource: match:
kinds: resources:
- Deployment kinds:
- Deployment
validate: validate:
message: "Image tag ':latest' requires imagePullPolicy 'Always'" message: "Image tag ':latest' requires imagePullPolicy 'Always'"
pattern: pattern:

View file

@ -5,14 +5,15 @@ metadata :
spec : spec :
rules: rules:
- name: check-memory_requests_link_in_yaml - name: check-memory_requests_link_in_yaml
resource: match:
# Kind specifies one or more resource types to match resources:
kinds: # Kind specifies one or more resource types to match
- Deployment kinds:
# Name is optional and can use wildcards - Deployment
name: "*" # Name is optional and can use wildcards
# Selector is optional name: "*"
selector: # Selector is optional
selector:
validate: validate:
pattern: pattern:
spec: spec:

View file

@ -5,14 +5,15 @@ metadata :
spec : spec :
rules: rules:
- name: check-memory_requests_link_in_yaml_relative - name: check-memory_requests_link_in_yaml_relative
resource: match:
# Kind specifies one or more resource types to match resources:
kinds: # Kind specifies one or more resource types to match
- Deployment kinds:
# Name is optional and can use wildcards - Deployment
name: "*" # Name is optional and can use wildcards
# Selector is optional name: "*"
selector: # Selector is optional
selector:
validate: validate:
pattern: pattern:
spec: spec:

View file

@ -5,9 +5,10 @@ metadata:
spec: spec:
rules: rules:
- name: check-node-port - name: check-node-port
resource: match:
kinds: resources:
- Service kinds:
- Service
validate: validate:
message: "NodePort type is not allowed" message: "NodePort type is not allowed"
pattern: pattern:

View file

@ -5,11 +5,12 @@ metadata :
spec : spec :
rules: rules:
- name: check-non-root - name: check-non-root
resource: match:
kinds: resources:
- Deployment kinds:
- StatefuleSet - Deployment
- DaemonSet - StatefuleSet
- DaemonSet
validate: validate:
message: "Root user is not allowed" message: "Root user is not allowed"
pattern: pattern:

View file

@ -5,9 +5,10 @@ metadata :
spec: spec:
rules: rules:
- name: check-liveness-probe-exists - name: check-liveness-probe-exists
resource: match:
kinds : resources:
- StatefulSet kinds :
- StatefulSet
validate: validate:
message: "a livenessProbe is required" message: "a livenessProbe is required"
pattern: pattern:
@ -19,9 +20,10 @@ spec:
livenessProbe: livenessProbe:
periodSeconds: ">0" periodSeconds: ">0"
- name: check-readiness-probe-exists - name: check-readiness-probe-exists
resource: match:
kinds : resources:
- StatefulSet kinds :
- StatefulSet
validate: validate:
message: "a readinessProbe is required" message: "a readinessProbe is required"
pattern: pattern:

View file

@ -5,9 +5,10 @@ metadata :
spec: spec:
rules: rules:
- name: check-probe-intervals - name: check-probe-intervals
resource: match:
kinds : resources:
- Deployment kinds :
- Deployment
validate: validate:
message: "livenessProbe must be > 10s" message: "livenessProbe must be > 10s"
pattern: pattern:
@ -19,9 +20,10 @@ spec:
livenessProbe: livenessProbe:
periodSeconds: ">10" periodSeconds: ">10"
- name: check-probe-intervals - name: check-probe-intervals
resource: match:
kinds : resources:
- Deployment kinds :
- Deployment
validate: validate:
message: "readinessProbe must be > 10s" message: "readinessProbe must be > 10s"
pattern: pattern:

View file

@ -5,10 +5,11 @@ metadata:
spec: spec:
rules: rules:
- name: check-registries - name: check-registries
resource: match:
kinds: resources:
- Deployment kinds:
- StatefulSet - Deployment
- StatefulSet
validate: validate:
message: "Registry is not allowed" message: "Registry is not allowed"
pattern: pattern:

View file

@ -210,10 +210,23 @@ func ParseAnnotationsFromObject(bytes []byte) map[string]string {
//AddPolicyJSONPatch generate JSON Patch to add policy informatino JSON patch //AddPolicyJSONPatch generate JSON Patch to add policy informatino JSON patch
func AddPolicyJSONPatch(ann map[string]string, pi *pinfo.PolicyInfo, ruleType pinfo.RuleType) (map[string]string, []byte, error) { func AddPolicyJSONPatch(ann map[string]string, pi *pinfo.PolicyInfo, ruleType pinfo.RuleType) (map[string]string, []byte, error) {
if ann == nil { if !pi.ContainsRuleType(ruleType) {
ann = make(map[string]string, 0) return nil, nil, nil
} }
PolicyObj := newAnnotationForPolicy(pi) PolicyObj := newAnnotationForPolicy(pi)
if ann == nil {
ann = make(map[string]string, 0)
PolicyByte, err := json.Marshal(PolicyObj)
if err != nil {
return nil, nil, err
}
// create a json patch to add annotation object
ann[BuildKey(pi.Name)] = string(PolicyByte)
// create add JSON patch
jsonPatch, err := createAddJSONPatch(BuildKey(pi.Name), string(PolicyByte))
return ann, jsonPatch, err
}
// if the annotations map is present then we
cPolicy, ok := ann[BuildKey(pi.Name)] cPolicy, ok := ann[BuildKey(pi.Name)]
if !ok { if !ok {
PolicyByte, err := json.Marshal(PolicyObj) PolicyByte, err := json.Marshal(PolicyObj)
@ -223,7 +236,7 @@ func AddPolicyJSONPatch(ann map[string]string, pi *pinfo.PolicyInfo, ruleType pi
// insert policy information // insert policy information
ann[BuildKey(pi.Name)] = string(PolicyByte) ann[BuildKey(pi.Name)] = string(PolicyByte)
// create add JSON patch // create add JSON patch
jsonPatch, err := createAddJSONPatch(ann) jsonPatch, err := createAddJSONPatch(BuildKey(pi.Name), string(PolicyByte))
return ann, jsonPatch, err return ann, jsonPatch, err
} }
@ -244,7 +257,7 @@ func AddPolicyJSONPatch(ann map[string]string, pi *pinfo.PolicyInfo, ruleType pi
// update policy information // update policy information
ann[BuildKey(pi.Name)] = string(cPolicyByte) ann[BuildKey(pi.Name)] = string(cPolicyByte)
// create update JSON patch // create update JSON patch
jsonPatch, err := createReplaceJSONPatch(ann) jsonPatch, err := createReplaceJSONPatch(BuildKey(pi.Name), string(cPolicyByte))
return ann, jsonPatch, err return ann, jsonPatch, err
} }
@ -253,12 +266,7 @@ func RemovePolicyJSONPatch(ann map[string]string, policy string) (map[string]str
if ann == nil { if ann == nil {
return nil, nil, nil return nil, nil, nil
} }
delete(ann, policy) jsonPatch, err := createRemoveJSONPatchKey(policy)
if len(ann) == 0 {
jsonPatch, err := createRemoveJSONPatch(ann)
return nil, jsonPatch, err
}
jsonPatch, err := createReplaceJSONPatch(ann)
return ann, jsonPatch, err return ann, jsonPatch, err
} }
@ -268,7 +276,13 @@ type patchMapValue struct {
Value map[string]string `json:"value"` Value map[string]string `json:"value"`
} }
func createRemoveJSONPatch(ann map[string]string) ([]byte, error) { type patchStringValue struct {
Op string `json:"op"`
Path string `json:"path"`
Value string `json:"value"`
}
func createRemoveJSONPatchMap() ([]byte, error) {
payload := []patchMapValue{{ payload := []patchMapValue{{
Op: "remove", Op: "remove",
Path: "/metadata/annotations", Path: "/metadata/annotations",
@ -276,11 +290,8 @@ func createRemoveJSONPatch(ann map[string]string) ([]byte, error) {
return json.Marshal(payload) return json.Marshal(payload)
} }
func createAddJSONPatchMap(ann map[string]string) ([]byte, error) {
func createAddJSONPatch(ann map[string]string) ([]byte, error) {
if ann == nil {
ann = make(map[string]string, 0)
}
payload := []patchMapValue{{ payload := []patchMapValue{{
Op: "add", Op: "add",
Path: "/metadata/annotations", Path: "/metadata/annotations",
@ -289,14 +300,33 @@ func createAddJSONPatch(ann map[string]string) ([]byte, error) {
return json.Marshal(payload) return json.Marshal(payload)
} }
func createReplaceJSONPatch(ann map[string]string) ([]byte, error) { func createAddJSONPatch(key, value string) ([]byte, error) {
if ann == nil {
ann = make(map[string]string, 0) payload := []patchStringValue{{
} Op: "add",
payload := []patchMapValue{{ Path: "/metadata/annotations/" + key,
Op: "replace", Value: value,
Path: "/metadata/annotations",
Value: ann,
}} }}
return json.Marshal(payload) return json.Marshal(payload)
} }
func createReplaceJSONPatch(key, value string) ([]byte, error) {
// if ann == nil {
// ann = make(map[string]string, 0)
// }
payload := []patchStringValue{{
Op: "replace",
Path: "/metadata/annotations/" + key,
Value: value,
}}
return json.Marshal(payload)
}
func createRemoveJSONPatchKey(key string) ([]byte, error) {
payload := []patchStringValue{{
Op: "remove",
Path: "/metadata/annotations/" + key,
}}
return json.Marshal(payload)
}

View file

@ -34,7 +34,7 @@ func NewAnnotationControler(client *client.Client) Controller {
} }
func (c *controller) Add(rkind, rns, rname string, patch []byte) { func (c *controller) Add(rkind, rns, rname string, patch []byte) {
c.queue.Add(newInfo(rkind, rns, rname, patch)) c.queue.Add(newInfo(rkind, rns, rname, &patch))
} }
func (c *controller) Run(stopCh <-chan struct{}) { func (c *controller) Run(stopCh <-chan struct{}) {
@ -99,14 +99,7 @@ func (c *controller) syncHandler(obj interface{}) error {
} }
var err error var err error
// check if the resource is created _, err = c.client.PatchResource(key.RKind, key.RNs, key.RName, *key.patch)
_, err = c.client.GetResource(key.RKind, key.RNs, key.RName)
if err != nil {
glog.Errorf("Error creating annotation: unable to get resource %s/%s/%s, will retry: %s ", key.RKind, key.RNs, key.RName, err)
return err
}
// if it is patch the resource
_, err = c.client.PatchResource(key.RKind, key.RNs, key.RName, *key.Patch)
if err != nil { if err != nil {
glog.Errorf("Error creating annotation: unable to get resource %s/%s/%s, will retry: %s", key.RKind, key.RNs, key.RName, err) glog.Errorf("Error creating annotation: unable to get resource %s/%s/%s, will retry: %s", key.RKind, key.RNs, key.RName, err)
return err return err

View file

@ -5,14 +5,14 @@ type info struct {
RNs string RNs string
RName string RName string
//TODO:Hack as slice makes the struct unhasable //TODO:Hack as slice makes the struct unhasable
Patch *[]byte patch *[]byte
} }
func newInfo(rkind, rns, rname string, patch []byte) info { func newInfo(rkind, rns, rname string, patch *[]byte) info {
return info{ return info{
RKind: rkind, RKind: rkind,
RNs: rns, RNs: rns,
RName: rname, RName: rname,
Patch: &patch, patch: patch,
} }
} }

View file

@ -2,7 +2,7 @@ package annotations
const annotationQueueName = "annotation-queue" const annotationQueueName = "annotation-queue"
const workerThreadCount = 1 const workerThreadCount = 1
const workQueueRetryLimit = 3 const workQueueRetryLimit = 5
func getStatus(status bool) string { func getStatus(status bool) string {
if status { if status {
@ -12,5 +12,10 @@ func getStatus(status bool) string {
} }
func BuildKey(policyName string) string { func BuildKey(policyName string) string {
//JSON Pointers
return "policies.kyverno.io~1" + policyName
}
func BuildKeyString(policyName string) string {
return "policies.kyverno.io/" + policyName return "policies.kyverno.io/" + policyName
} }

View file

@ -25,11 +25,22 @@ type Spec struct {
// Rule is set of mutation, validation and generation actions // Rule is set of mutation, validation and generation actions
// for the single resource description // for the single resource description
type Rule struct { type Rule struct {
Name string `json:"name"` Name string `json:"name"`
ResourceDescription `json:"resource"` MatchResources MatchResources `json:"match"`
Mutation *Mutation `json:"mutate"` ExcludeResources ExcludeResources `json:"exclude,omitempty"`
Validation *Validation `json:"validate"` Mutation *Mutation `json:"mutate"`
Generation *Generation `json:"generate"` Validation *Validation `json:"validate"`
Generation *Generation `json:"generate"`
}
//MatchResources contains resource description of the resources that the rule is to apply on
type MatchResources struct {
ResourceDescription `json:"resources"`
}
//ExcludeResources container resource description of the resources that are to be excluded from the applying the policy rule
type ExcludeResources struct {
ResourceDescription `json:"resources"`
} }
// ResourceDescription describes the resource to which the PolicyRule will be applied. // ResourceDescription describes the resource to which the PolicyRule will be applied.

View file

@ -9,7 +9,8 @@ import (
// Validate checks if rule is not empty and all substructures are valid // Validate checks if rule is not empty and all substructures are valid
func (r *Rule) Validate() error { func (r *Rule) Validate() error {
err := r.ResourceDescription.Validate() // check matches Resoource Description of match resource
err := r.MatchResources.ResourceDescription.Validate()
if err != nil { if err != nil {
return err return err
} }

View file

@ -8,6 +8,7 @@ import (
) )
var defaultResourceDescriptionName = "defaultResourceDescription" var defaultResourceDescriptionName = "defaultResourceDescription"
var defaultResourceDescription = ResourceDescription{ var defaultResourceDescription = ResourceDescription{
Kinds: []string{"Deployment"}, Kinds: []string{"Deployment"},
Name: &defaultResourceDescriptionName, Name: &defaultResourceDescriptionName,
@ -18,8 +19,8 @@ var defaultResourceDescription = ResourceDescription{
func Test_EmptyRule(t *testing.T) { func Test_EmptyRule(t *testing.T) {
emptyRule := Rule{ emptyRule := Rule{
Name: "defaultRule", Name: "defaultRule",
ResourceDescription: defaultResourceDescription, MatchResources: MatchResources{ResourceDescription: defaultResourceDescription},
} }
err := emptyRule.Validate() err := emptyRule.Validate()
assert.Assert(t, err != nil) assert.Assert(t, err != nil)

View file

@ -41,6 +41,23 @@ func (in *CloneFrom) DeepCopy() *CloneFrom {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExcludeResources) DeepCopyInto(out *ExcludeResources) {
*out = *in
in.ResourceDescription.DeepCopyInto(&out.ResourceDescription)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExcludeResources.
func (in *ExcludeResources) DeepCopy() *ExcludeResources {
if in == nil {
return nil
}
out := new(ExcludeResources)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FailedRule) DeepCopyInto(out *FailedRule) { func (in *FailedRule) DeepCopyInto(out *FailedRule) {
*out = *in *out = *in
@ -67,6 +84,23 @@ func (in *Generation) DeepCopy() *Generation {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MatchResources) DeepCopyInto(out *MatchResources) {
*out = *in
in.ResourceDescription.DeepCopyInto(&out.ResourceDescription)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MatchResources.
func (in *MatchResources) DeepCopy() *MatchResources {
if in == nil {
return nil
}
out := new(MatchResources)
in.DeepCopyInto(out)
return out
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Mutation. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Mutation.
func (in *Mutation) DeepCopy() *Mutation { func (in *Mutation) DeepCopy() *Mutation {
if in == nil { if in == nil {
@ -177,7 +211,8 @@ func (in *ResourceDescription) DeepCopy() *ResourceDescription {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Rule) DeepCopyInto(out *Rule) { func (in *Rule) DeepCopyInto(out *Rule) {
*out = *in *out = *in
in.ResourceDescription.DeepCopyInto(&out.ResourceDescription) in.MatchResources.DeepCopyInto(&out.MatchResources)
in.ExcludeResources.DeepCopyInto(&out.ExcludeResources)
if in.Mutation != nil { if in.Mutation != nil {
in, out := &in.Mutation, &out.Mutation in, out := &in.Mutation, &out.Mutation
*out = (*in).DeepCopy() *out = (*in).DeepCopy()

View file

@ -2,11 +2,10 @@ package controller
import ( import (
"github.com/golang/glog" "github.com/golang/glog"
"github.com/minio/minio/pkg/wildcard"
"github.com/nirmata/kyverno/pkg/annotations" "github.com/nirmata/kyverno/pkg/annotations"
v1alpha1 "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" v1alpha1 "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
client "github.com/nirmata/kyverno/pkg/dclient" client "github.com/nirmata/kyverno/pkg/dclient"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "github.com/nirmata/kyverno/pkg/engine"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@ -23,44 +22,12 @@ func cleanAnnotations(client *client.Client, obj interface{}) {
return return
} }
// Get the resources that apply to the policy // Get the resources that apply to the policy
// key uid resourceMap := engine.ListResourcesThatApplyToPolicy(client, &policy)
resourceMap := map[string]unstructured.Unstructured{}
for _, rule := range policy.Spec.Rules {
for _, k := range rule.Kinds {
if k == "Namespace" {
continue
}
// kind -> resource
gvr := client.DiscoveryClient.GetGVRFromKind(k)
// label selectors
// namespace ? should it be default or allow policy to specify it
namespace := "default"
if rule.ResourceDescription.Namespace != nil {
namespace = *rule.ResourceDescription.Namespace
}
list, err := client.ListResource(k, namespace, rule.ResourceDescription.Selector)
if err != nil {
glog.Errorf("unable to list resource for %s with label selector %s", gvr.Resource, rule.Selector.String())
glog.Errorf("unable to apply policy %s rule %s. err: %s", policy.Name, rule.Name, err)
continue
}
for _, res := range list.Items {
name := rule.ResourceDescription.Name
if name != nil {
// wild card matching
if !wildcard.Match(*name, res.GetName()) {
continue
}
}
resourceMap[string(res.GetUID())] = res
}
}
}
// remove annotations for the resources // remove annotations for the resources
for _, obj := range resourceMap { for _, obj := range resourceMap {
// get annotations // get annotations
ann := obj.GetAnnotations()
ann := obj.Resource.GetAnnotations()
_, patch, err := annotations.RemovePolicyJSONPatch(ann, annotations.BuildKey(policy.Name)) _, patch, err := annotations.RemovePolicyJSONPatch(ann, annotations.BuildKey(policy.Name))
if err != nil { if err != nil {
@ -68,7 +35,7 @@ func cleanAnnotations(client *client.Client, obj interface{}) {
continue continue
} }
// patch the resource // patch the resource
_, err = client.PatchResource(obj.GetKind(), obj.GetNamespace(), obj.GetName(), patch) _, err = client.PatchResource(obj.Resource.GetKind(), obj.Resource.GetNamespace(), obj.Resource.GetName(), patch)
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
continue continue

View file

@ -227,7 +227,7 @@ func (pc *PolicyController) createAnnotations(policyInfos []*info.PolicyInfo) {
} }
// Generation rules // Generation rules
ann, gpatch, err := annotations.AddPolicyJSONPatch(ann, pi, info.Validation) ann, gpatch, err := annotations.AddPolicyJSONPatch(ann, pi, info.Generation)
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
} }
@ -251,14 +251,23 @@ func (pc *PolicyController) createAnnotations(policyInfos []*info.PolicyInfo) {
patch = mpatch patch = mpatch
} }
// generation
if gpatch != nil { if gpatch != nil {
patch, err = jsonpatch.MergePatch(patch, gpatch) // generation
if err != nil { if patch != nil {
glog.Error(err) patch, err = jsonpatch.MergePatch(patch, gpatch)
continue if err != nil {
glog.Error(err)
continue
}
} else {
patch = gpatch
} }
} }
if patch == nil {
return
}
// add the anotation to the resource // add the anotation to the resource
_, err = pc.client.PatchResource(pi.RKind, pi.RNamespace, pi.RName, patch) _, err = pc.client.PatchResource(pi.RKind, pi.RNamespace, pi.RName, patch)
if err != nil { if err != nil {

View file

@ -8,44 +8,80 @@ import (
client "github.com/nirmata/kyverno/pkg/dclient" client "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/info" "github.com/nirmata/kyverno/pkg/info"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1helper "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
) )
// ProcessExisting checks for mutation and validation violations of existing resources func ListResourcesThatApplyToPolicy(client *client.Client, policy *types.Policy) map[string]resourceInfo {
func ProcessExisting(client *client.Client, policy *types.Policy) []*info.PolicyInfo {
glog.Infof("Applying policy %s on existing resources", policy.Name)
// key uid // key uid
resourceMap := map[string]resourceInfo{} resourceMap := map[string]resourceInfo{}
for _, rule := range policy.Spec.Rules { for _, rule := range policy.Spec.Rules {
for _, k := range rule.Kinds { // Match
for _, k := range rule.MatchResources.Kinds {
// kind -> resource // kind -> resource
gvr := client.DiscoveryClient.GetGVRFromKind(k) gvr := client.DiscoveryClient.GetGVRFromKind(k)
// label selectors // Namespace
// namespace ? should it be default or allow policy to specify it
namespace := "default" namespace := "default"
if rule.ResourceDescription.Namespace != nil { if rule.MatchResources.Namespace != nil {
namespace = *rule.ResourceDescription.Namespace namespace = *rule.MatchResources.Namespace
} }
if k == "Namespace" { if k == "Namespace" {
namespace = "" namespace = ""
} }
// Check if exclude namespace is not clashing
if rule.ExcludeResources.Namespace != nil && *rule.ExcludeResources.Namespace == namespace {
// as the namespace is excluded
continue
}
list, err := client.ListResource(k, namespace, rule.ResourceDescription.Selector) // List resources
list, err := client.ListResource(k, namespace, rule.MatchResources.Selector)
if err != nil { if err != nil {
glog.Errorf("unable to list resource for %s with label selector %s", gvr.Resource, rule.Selector.String()) glog.Errorf("unable to list resource for %s with label selector %s", gvr.Resource, rule.MatchResources.Selector.String())
glog.Errorf("unable to apply policy %s rule %s. err: %s", policy.Name, rule.Name, err) glog.Errorf("unable to apply policy %s rule %s. err: %s", policy.Name, rule.Name, err)
continue continue
} }
var selector labels.Selector
// exclude label selector
if rule.ExcludeResources.Selector != nil {
selector, err = v1helper.LabelSelectorAsSelector(rule.ExcludeResources.Selector)
if err != nil {
glog.Error(err)
}
}
for _, res := range list.Items { for _, res := range list.Items {
name := rule.ResourceDescription.Name // exclude label selectors
gvk := res.GroupVersionKind() if selector != nil {
set := labels.Set(res.GetLabels())
if selector.Matches(set) {
// if matches
continue
}
}
var name *string
// match
// name
// wild card matching
name = rule.MatchResources.Name
if name != nil { if name != nil {
// wild card matching // if does not match then we skip
if !wildcard.Match(*name, res.GetName()) { if !wildcard.Match(*name, res.GetName()) {
continue continue
} }
} }
ri := resourceInfo{resource: res, gvk: &metav1.GroupVersionKind{Group: gvk.Group, // exclude
// name
// wild card matching
name = rule.ExcludeResources.Name
if name != nil {
// if matches then we skip
if wildcard.Match(*name, res.GetName()) {
continue
}
}
gvk := res.GroupVersionKind()
ri := resourceInfo{Resource: res, Gvk: &metav1.GroupVersionKind{Group: gvk.Group,
Version: gvk.Version, Version: gvk.Version,
Kind: gvk.Kind}} Kind: gvk.Kind}}
@ -54,13 +90,60 @@ func ProcessExisting(client *client.Client, policy *types.Policy) []*info.Policy
} }
} }
} }
return resourceMap
}
// ProcessExisting checks for mutation and validation violations of existing resources
func ProcessExisting(client *client.Client, policy *types.Policy) []*info.PolicyInfo {
glog.Infof("Applying policy %s on existing resources", policy.Name)
// key uid
resourceMap := ListResourcesThatApplyToPolicy(client, policy)
// for _, rule := range policy.Spec.Rules {
// for _, k := range rule.Kinds {
// // kind -> resource
// gvr := client.DiscoveryClient.GetGVRFromKind(k)
// // label selectors
// // namespace ? should it be default or allow policy to specify it
// namespace := "default"
// if rule.ResourceDescription.Namespace != nil {
// namespace = *rule.ResourceDescription.Namespace
// }
// if k == "Namespace" {
// namespace = ""
// }
// list, err := client.ListResource(k, namespace, rule.ResourceDescription.Selector)
// if err != nil {
// glog.Errorf("unable to list resource for %s with label selector %s", gvr.Resource, rule.Selector.String())
// glog.Errorf("unable to apply policy %s rule %s. err: %s", policy.Name, rule.Name, err)
// continue
// }
// for _, res := range list.Items {
// name := rule.ResourceDescription.Name
// gvk := res.GroupVersionKind()
// if name != nil {
// // wild card matching
// if !wildcard.Match(*name, res.GetName()) {
// continue
// }
// }
// ri := resourceInfo{resource: res, gvk: &metav1.GroupVersionKind{Group: gvk.Group,
// Version: gvk.Version,
// Kind: gvk.Kind}}
// resourceMap[string(res.GetUID())] = ri
// }
// }
// }
policyInfos := []*info.PolicyInfo{} policyInfos := []*info.PolicyInfo{}
// for the filtered resource apply policy // for the filtered resource apply policy
for _, v := range resourceMap { for _, v := range resourceMap {
policyInfo, err := applyPolicy(client, policy, v) policyInfo, err := applyPolicy(client, policy, v)
if err != nil { if err != nil {
glog.Errorf("unable to apply policy %s on resource %s/%s", policy.Name, v.resource.GetName(), v.resource.GetNamespace()) glog.Errorf("unable to apply policy %s on resource %s/%s", policy.Name, v.Resource.GetName(), v.Resource.GetNamespace())
glog.Error(err) glog.Error(err)
continue continue
} }
@ -71,28 +154,28 @@ func ProcessExisting(client *client.Client, policy *types.Policy) []*info.Policy
} }
func applyPolicy(client *client.Client, policy *types.Policy, res resourceInfo) (*info.PolicyInfo, error) { func applyPolicy(client *client.Client, policy *types.Policy, res resourceInfo) (*info.PolicyInfo, error) {
policyInfo := info.NewPolicyInfo(policy.Name, res.gvk.Kind, res.resource.GetName(), res.resource.GetNamespace(), policy.Spec.ValidationFailureAction) policyInfo := info.NewPolicyInfo(policy.Name, res.Gvk.Kind, res.Resource.GetName(), res.Resource.GetNamespace(), policy.Spec.ValidationFailureAction)
glog.Infof("Applying policy %s with %d rules\n", policy.ObjectMeta.Name, len(policy.Spec.Rules)) glog.Infof("Applying policy %s with %d rules\n", policy.ObjectMeta.Name, len(policy.Spec.Rules))
rawResource, err := res.resource.MarshalJSON() rawResource, err := res.Resource.MarshalJSON()
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Mutate // Mutate
mruleInfos, err := mutation(policy, rawResource, res.gvk) mruleInfos, err := mutation(policy, rawResource, res.Gvk)
policyInfo.AddRuleInfos(mruleInfos) policyInfo.AddRuleInfos(mruleInfos)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Validation // Validation
vruleInfos, err := Validate(*policy, rawResource, *res.gvk) vruleInfos, err := Validate(*policy, rawResource, *res.Gvk)
policyInfo.AddRuleInfos(vruleInfos) policyInfo.AddRuleInfos(vruleInfos)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if res.gvk.Kind == "Namespace" { if res.Gvk.Kind == "Namespace" {
// Generation // Generation
gruleInfos := GenerateNew(client, policy, res.resource) gruleInfos := GenerateNew(client, policy, res.Resource)
policyInfo.AddRuleInfos(gruleInfos) policyInfo.AddRuleInfos(gruleInfos)
} }

View file

@ -21,7 +21,7 @@ func Generate(client *client.Client, policy kubepolicy.Policy, rawResource []byt
ri := info.NewRuleInfo(rule.Name, info.Generation) ri := info.NewRuleInfo(rule.Name, info.Generation)
ok := ResourceMeetsDescription(rawResource, rule.ResourceDescription, gvk) ok := ResourceMeetsDescription(rawResource, rule.MatchResources.ResourceDescription, rule.ExcludeResources.ResourceDescription, gvk)
if !ok { if !ok {
glog.Infof("Rule is not applicable to the request: rule name = %s in policy %s \n", rule.Name, policy.ObjectMeta.Name) glog.Infof("Rule is not applicable to the request: rule name = %s in policy %s \n", rule.Name, policy.ObjectMeta.Name)
continue continue

View file

@ -19,7 +19,7 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio
} }
ri := info.NewRuleInfo(rule.Name, info.Mutation) ri := info.NewRuleInfo(rule.Name, info.Mutation)
ok := ResourceMeetsDescription(rawResource, rule.ResourceDescription, gvk) ok := ResourceMeetsDescription(rawResource, rule.MatchResources.ResourceDescription, rule.ExcludeResources.ResourceDescription, gvk)
if !ok { if !ok {
glog.V(3).Infof("Not applicable on specified resource kind%s", gvk.Kind) glog.V(3).Infof("Not applicable on specified resource kind%s", gvk.Kind)
continue continue
@ -27,12 +27,18 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio
// Process Overlay // Process Overlay
if rule.Mutation.Overlay != nil { if rule.Mutation.Overlay != nil {
overlayPatches, err := ProcessOverlay(rule, rawResource, gvk) overlayPatches, err := ProcessOverlay(rule, rawResource, gvk)
if err != nil { if err == nil {
ri.Fail() if len(overlayPatches) == 0{
ri.Addf("overlay application has failed, err %v.", err) // if array elements dont match then we skip(nil patch, no error)
} else { // or if acnohor is defined and doenst match
// policy is not applicable
continue
}
ri.Addf("Rule %s: Overlay succesfully applied.", rule.Name) ri.Addf("Rule %s: Overlay succesfully applied.", rule.Name)
allPatches = append(allPatches, overlayPatches...) allPatches = append(allPatches, overlayPatches...)
} else {
ri.Fail()
ri.Addf("overlay application has failed, err %v.", err)
} }
} }

View file

@ -275,16 +275,43 @@ func processSubtree(overlay interface{}, path string, op string) ([]byte, error)
// converts overlay to JSON string to be inserted into the JSON Patch // converts overlay to JSON string to be inserted into the JSON Patch
func prepareJSONValue(overlay interface{}) string { func prepareJSONValue(overlay interface{}) string {
jsonOverlay, err := json.Marshal(overlay) var err error
if err != nil || hasOnlyAnchors(overlay) { if err != nil || hasOnlyAnchors(overlay) {
glog.V(3).Info(err) glog.V(3).Info(err)
return "" return ""
} }
// Need to remove anchors from the overlay struct
overlayWithoutAnchors := removeAnchorFromSubTree(overlay)
jsonOverlay, err := json.Marshal(overlayWithoutAnchors)
return string(jsonOverlay) return string(jsonOverlay)
} }
func removeAnchorFromSubTree(overlay interface{}) interface{} {
var result interface{}
switch typed := overlay.(type) {
case map[string]interface{}:
// assuming only keys have anchors
result = removeAnchroFromMap(typed)
case []interface{}:
arrayResult := make([]interface{}, 0)
for _, value := range typed {
arrayResult = append(arrayResult, removeAnchorFromSubTree(value))
}
result = arrayResult
default:
result = overlay
}
return result
}
func removeAnchroFromMap(overlay map[string]interface{}) map[string]interface{} {
result := make(map[string]interface{}, 0)
for k, v := range overlay {
result[getRawKeyIfWrappedWithAttributes(k)] = removeAnchorFromSubTree(v)
}
return result
}
// Anchor has pattern value, so resource shouldn't be mutated with it // Anchor has pattern value, so resource shouldn't be mutated with it
// If entire subtree has only anchor keys - we should skip inserting it // If entire subtree has only anchor keys - we should skip inserting it
func hasOnlyAnchors(overlay interface{}) bool { func hasOnlyAnchors(overlay interface{}) bool {

View file

@ -6,8 +6,10 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/golang/glog"
"github.com/minio/minio/pkg/wildcard" "github.com/minio/minio/pkg/wildcard"
kubepolicy "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" v1alpha1 "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -15,8 +17,8 @@ import (
) )
// ResourceMeetsDescription checks requests kind, name and labels to fit the policy rule // ResourceMeetsDescription checks requests kind, name and labels to fit the policy rule
func ResourceMeetsDescription(resourceRaw []byte, description kubepolicy.ResourceDescription, gvk metav1.GroupVersionKind) bool { func ResourceMeetsDescription(resourceRaw []byte, matches v1alpha1.ResourceDescription, exclude v1alpha1.ResourceDescription, gvk metav1.GroupVersionKind) bool {
if !findKind(description.Kinds, gvk.Kind) { if !findKind(matches.Kinds, gvk.Kind) {
return false return false
} }
@ -25,31 +27,58 @@ func ResourceMeetsDescription(resourceRaw []byte, description kubepolicy.Resourc
name := ParseNameFromObject(resourceRaw) name := ParseNameFromObject(resourceRaw)
namespace := ParseNamespaceFromObject(resourceRaw) namespace := ParseNamespaceFromObject(resourceRaw)
if description.Name != nil { if matches.Name != nil {
// Matches
if !wildcard.Match(*description.Name, name) { if !wildcard.Match(*matches.Name, name) {
return false return false
} }
} }
// Exclude
if description.Namespace != nil && *description.Namespace != namespace { // the resource name matches the exclude resource name then reject
if exclude.Name != nil {
if wildcard.Match(*exclude.Name, name) {
return false
}
}
// Matches
if matches.Namespace != nil && *matches.Namespace != namespace {
return false return false
} }
// Exclude
if description.Selector != nil { if exclude.Namespace != nil && *exclude.Namespace == namespace {
selector, err := metav1.LabelSelectorAsSelector(description.Selector) return false
if err != nil {
return false
}
labelMap := parseLabelsFromMetadata(meta)
if !selector.Matches(labelMap) {
return false
}
} }
// Matches
if matches.Selector != nil {
selector, err := metav1.LabelSelectorAsSelector(matches.Selector)
if err != nil {
glog.Error(err)
return false
}
if meta != nil {
labelMap := parseLabelsFromMetadata(meta)
if !selector.Matches(labelMap) {
return false
}
}
}
// Exclude
if exclude.Selector != nil {
selector, err := metav1.LabelSelectorAsSelector(exclude.Selector)
// if the label selector is incorrect, should be fail or
if err != nil {
glog.Error(err)
return false
}
if meta != nil {
labelMap := parseLabelsFromMetadata(meta)
if selector.Matches(labelMap) {
return false
}
}
}
} }
return true return true
} }
@ -57,8 +86,11 @@ func ResourceMeetsDescription(resourceRaw []byte, description kubepolicy.Resourc
func parseMetadataFromObject(bytes []byte) map[string]interface{} { func parseMetadataFromObject(bytes []byte) map[string]interface{} {
var objectJSON map[string]interface{} var objectJSON map[string]interface{}
json.Unmarshal(bytes, &objectJSON) json.Unmarshal(bytes, &objectJSON)
meta, ok := objectJSON["metadata"].(map[string]interface{})
return objectJSON["metadata"].(map[string]interface{}) if !ok {
return nil
}
return meta
} }
//ParseKindFromObject get kind from resource //ParseKindFromObject get kind from resource
@ -85,10 +117,16 @@ func parseLabelsFromMetadata(meta map[string]interface{}) labels.Set {
func ParseNameFromObject(bytes []byte) string { func ParseNameFromObject(bytes []byte) string {
var objectJSON map[string]interface{} var objectJSON map[string]interface{}
json.Unmarshal(bytes, &objectJSON) json.Unmarshal(bytes, &objectJSON)
meta, ok := objectJSON["metadata"]
if !ok {
return ""
}
meta := objectJSON["metadata"].(map[string]interface{}) metaMap, ok := meta.(map[string]interface{})
if !ok {
if name, ok := meta["name"].(string); ok { return ""
}
if name, ok := metaMap["name"].(string); ok {
return name return name
} }
return "" return ""
@ -98,12 +136,19 @@ func ParseNameFromObject(bytes []byte) string {
func ParseNamespaceFromObject(bytes []byte) string { func ParseNamespaceFromObject(bytes []byte) string {
var objectJSON map[string]interface{} var objectJSON map[string]interface{}
json.Unmarshal(bytes, &objectJSON) json.Unmarshal(bytes, &objectJSON)
meta, ok := objectJSON["metadata"]
meta := objectJSON["metadata"].(map[string]interface{}) if !ok {
return ""
if namespace, ok := meta["namespace"].(string); ok {
return namespace
} }
metaMap, ok := meta.(map[string]interface{})
if !ok {
return ""
}
if name, ok := metaMap["namespace"].(string); ok {
return name
}
return "" return ""
} }
@ -253,6 +298,6 @@ func convertToFloat(value interface{}) (float64, error) {
} }
type resourceInfo struct { type resourceInfo struct {
resource unstructured.Unstructured Resource unstructured.Unstructured
gvk *metav1.GroupVersionKind Gvk *metav1.GroupVersionKind
} }

View file

@ -18,6 +18,7 @@ func TestResourceMeetsDescription_Kind(t *testing.T) {
MatchExpressions: nil, MatchExpressions: nil,
}, },
} }
excludeResourcesResourceDesc := types.ResourceDescription{}
groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"}
rawResource := []byte(`{ rawResource := []byte(`{
@ -32,12 +33,12 @@ func TestResourceMeetsDescription_Kind(t *testing.T) {
} }
}`) }`)
assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
resourceDescription.Kinds[0] = "Deployment" resourceDescription.Kinds[0] = "Deployment"
assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
resourceDescription.Kinds[0] = "ConfigMap" resourceDescription.Kinds[0] = "ConfigMap"
groupVersionKind.Kind = "Deployment" groupVersionKind.Kind = "Deployment"
assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
} }
func TestResourceMeetsDescription_Name(t *testing.T) { func TestResourceMeetsDescription_Name(t *testing.T) {
@ -50,6 +51,8 @@ func TestResourceMeetsDescription_Name(t *testing.T) {
MatchExpressions: nil, MatchExpressions: nil,
}, },
} }
excludeResourcesResourceDesc := types.ResourceDescription{}
groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"}
rawResource := []byte(`{ rawResource := []byte(`{
@ -64,9 +67,9 @@ func TestResourceMeetsDescription_Name(t *testing.T) {
} }
}`) }`)
assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
resourceName = "test-config-map-new" resourceName = "test-config-map-new"
assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
rawResource = []byte(`{ rawResource = []byte(`{
"metadata":{ "metadata":{
@ -79,7 +82,7 @@ func TestResourceMeetsDescription_Name(t *testing.T) {
} }
} }
}`) }`)
assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
rawResource = []byte(`{ rawResource = []byte(`{
"metadata":{ "metadata":{
@ -92,7 +95,7 @@ func TestResourceMeetsDescription_Name(t *testing.T) {
} }
} }
}`) }`)
assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
} }
func TestResourceMeetsDescription_MatchExpressions(t *testing.T) { func TestResourceMeetsDescription_MatchExpressions(t *testing.T) {
@ -134,6 +137,8 @@ func TestResourceMeetsDescription_MatchExpressions(t *testing.T) {
}, },
}, },
} }
excludeResourcesResourceDesc := types.ResourceDescription{}
groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"}
rawResource := []byte(`{ rawResource := []byte(`{
"metadata":{ "metadata":{
@ -147,7 +152,7 @@ func TestResourceMeetsDescription_MatchExpressions(t *testing.T) {
} }
}`) }`)
assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
rawResource = []byte(`{ rawResource = []byte(`{
"metadata":{ "metadata":{
@ -161,7 +166,7 @@ func TestResourceMeetsDescription_MatchExpressions(t *testing.T) {
} }
}`) }`)
assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
} }
func TestResourceMeetsDescription_MatchLabels(t *testing.T) { func TestResourceMeetsDescription_MatchLabels(t *testing.T) {
@ -178,6 +183,7 @@ func TestResourceMeetsDescription_MatchLabels(t *testing.T) {
}, },
} }
groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"}
excludeResourcesResourceDesc := types.ResourceDescription{}
rawResource := []byte(`{ rawResource := []byte(`{
"metadata":{ "metadata":{
@ -190,7 +196,7 @@ func TestResourceMeetsDescription_MatchLabels(t *testing.T) {
} }
} }
}`) }`)
assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
rawResource = []byte(`{ rawResource = []byte(`{
"metadata":{ "metadata":{
@ -203,7 +209,7 @@ func TestResourceMeetsDescription_MatchLabels(t *testing.T) {
} }
} }
}`) }`)
assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
resourceDescription = types.ResourceDescription{ resourceDescription = types.ResourceDescription{
Kinds: []string{"ConfigMap"}, Kinds: []string{"ConfigMap"},
@ -217,7 +223,7 @@ func TestResourceMeetsDescription_MatchLabels(t *testing.T) {
}, },
} }
assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
} }
func TestResourceMeetsDescription_MatchLabelsAndMatchExpressions(t *testing.T) { func TestResourceMeetsDescription_MatchLabelsAndMatchExpressions(t *testing.T) {
@ -241,6 +247,7 @@ func TestResourceMeetsDescription_MatchLabelsAndMatchExpressions(t *testing.T) {
}, },
} }
groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"} groupVersionKind := metav1.GroupVersionKind{Kind: "ConfigMap"}
excludeResourcesResourceDesc := types.ResourceDescription{}
rawResource := []byte(`{ rawResource := []byte(`{
"metadata":{ "metadata":{
@ -254,7 +261,7 @@ func TestResourceMeetsDescription_MatchLabelsAndMatchExpressions(t *testing.T) {
} }
}`) }`)
assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
resourceDescription = types.ResourceDescription{ resourceDescription = types.ResourceDescription{
Kinds: []string{"ConfigMap"}, Kinds: []string{"ConfigMap"},
@ -286,7 +293,7 @@ func TestResourceMeetsDescription_MatchLabelsAndMatchExpressions(t *testing.T) {
} }
} }
}`) }`)
assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
resourceDescription = types.ResourceDescription{ resourceDescription = types.ResourceDescription{
Kinds: []string{"ConfigMap"}, Kinds: []string{"ConfigMap"},
@ -307,7 +314,7 @@ func TestResourceMeetsDescription_MatchLabelsAndMatchExpressions(t *testing.T) {
}, },
} }
assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
resourceDescription = types.ResourceDescription{ resourceDescription = types.ResourceDescription{
Kinds: []string{"ConfigMap"}, Kinds: []string{"ConfigMap"},
@ -329,7 +336,7 @@ func TestResourceMeetsDescription_MatchLabelsAndMatchExpressions(t *testing.T) {
}, },
} }
assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, groupVersionKind)) assert.Assert(t, false == ResourceMeetsDescription(rawResource, resourceDescription, excludeResourcesResourceDesc, groupVersionKind))
} }
func TestWrappedWithParentheses_StringIsWrappedWithParentheses(t *testing.T) { func TestWrappedWithParentheses_StringIsWrappedWithParentheses(t *testing.T) {

View file

@ -32,7 +32,7 @@ func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVers
} }
ri := info.NewRuleInfo(rule.Name, info.Validation) ri := info.NewRuleInfo(rule.Name, info.Validation)
ok := ResourceMeetsDescription(rawResource, rule.ResourceDescription, gvk) ok := ResourceMeetsDescription(rawResource, rule.MatchResources.ResourceDescription, rule.ExcludeResources.ResourceDescription, gvk)
if !ok { if !ok {
glog.V(3).Infof("Not applicable on specified resource kind%s", gvk.Kind) glog.V(3).Infof("Not applicable on specified resource kind%s", gvk.Kind)
continue continue

View file

@ -6,7 +6,7 @@ const eventWorkQueueName = "policy-controller-events"
const eventWorkerThreadCount = 1 const eventWorkerThreadCount = 1
const workQueueRetryLimit = 1 const workQueueRetryLimit = 5
//Info defines the event details //Info defines the event details
type Info struct { type Info struct {

View file

@ -1,10 +1,12 @@
package gencontroller package gencontroller
import ( import (
"encoding/json"
"fmt" "fmt"
"strings" "strings"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/annotations" "github.com/nirmata/kyverno/pkg/annotations"
@ -14,6 +16,7 @@ import (
"github.com/nirmata/kyverno/pkg/info" "github.com/nirmata/kyverno/pkg/info"
violation "github.com/nirmata/kyverno/pkg/violation" violation "github.com/nirmata/kyverno/pkg/violation"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
@ -44,7 +47,16 @@ func (c *Controller) listPolicies(ns *corev1.Namespace) ([]*v1alpha1.Policy, err
for _, r := range p.Spec.Rules { for _, r := range p.Spec.Rules {
if r.Generation != nil { if r.Generation != nil {
// Check if the resource meets the description // Check if the resource meets the description
if namespaceMeetsRuleDescription(ns, r.ResourceDescription) { data, err := json.Marshal(ns)
if err != nil {
glog.Error(err)
continue
}
// convert types of GVK
nsGvk := schema.FromAPIVersionAndKind("v1", "Namespace")
// Hardcode as we have a informer on specified gvk
gvk := metav1.GroupVersionKind{Group: nsGvk.Group, Kind: nsGvk.Kind, Version: nsGvk.Version}
if engine.ResourceMeetsDescription(data, r.MatchResources.ResourceDescription, r.ExcludeResources.ResourceDescription, gvk) {
fpolicies = append(fpolicies, p) fpolicies = append(fpolicies, p)
break break
} }
@ -76,8 +88,9 @@ func (c *Controller) processPolicy(ns *corev1.Namespace, p *v1alpha1.Policy) {
ruleInfos := engine.GenerateNew(c.client, p, unstObj) ruleInfos := engine.GenerateNew(c.client, p, unstObj)
policyInfo.AddRuleInfos(ruleInfos) policyInfo.AddRuleInfos(ruleInfos)
// generate annotations // generate annotations on namespace
c.createAnnotations(policyInfo) c.createAnnotations(policyInfo)
//TODO generate namespace on created resources
if !policyInfo.IsSuccessful() { if !policyInfo.IsSuccessful() {
glog.Infof("Failed to apply policy %s on resource %s %s", p.Name, ns.Kind, ns.Name) glog.Infof("Failed to apply policy %s on resource %s %s", p.Name, ns.Kind, ns.Name)
@ -127,7 +140,7 @@ func (c *Controller) createAnnotations(pi *info.PolicyInfo) {
// add annotation for policy application // add annotation for policy application
ann := obj.GetAnnotations() ann := obj.GetAnnotations()
// Generation rules // Generation rules
ann, gpatch, err := annotations.AddPolicyJSONPatch(ann, pi, info.Mutation) ann, gpatch, err := annotations.AddPolicyJSONPatch(ann, pi, info.Generation)
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
return return
@ -136,7 +149,6 @@ func (c *Controller) createAnnotations(pi *info.PolicyInfo) {
// nothing to patch // nothing to patch
return return
} }
// add the anotation to the resource // add the anotation to the resource
_, err = c.client.PatchResource(pi.RKind, pi.RNamespace, pi.RName, gpatch) _, err = c.client.PatchResource(pi.RKind, pi.RNamespace, pi.RName, gpatch)
if err != nil { if err != nil {

View file

@ -199,3 +199,13 @@ func (pi *PolicyInfo) GetRuleNames(onSuccess bool) string {
return strings.Join(ruleNames, ",") return strings.Join(ruleNames, ",")
} }
//ContainsRuleType checks if a policy info contains a rule type
func (pi *PolicyInfo) ContainsRuleType(ruleType RuleType) bool {
for _, r := range pi.Rules {
if r.RuleType == ruleType {
return true
}
}
return false
}

View file

@ -26,7 +26,7 @@ func (ws *WebhookServer) removePolicyViolation(request *v1beta1.AdmissionRequest
rkind := request.Kind.Kind rkind := request.Kind.Kind
// check if the resource meets the policy Resource description // check if the resource meets the policy Resource description
for _, rule := range policy.Spec.Rules { for _, rule := range policy.Spec.Rules {
ok := engine.ResourceMeetsDescription(request.Object.Raw, rule.ResourceDescription, request.Kind) ok := engine.ResourceMeetsDescription(request.Object.Raw, rule.MatchResources.ResourceDescription, rule.ExcludeResources.ResourceDescription, request.Kind)
if ok { if ok {
// Check if the policy has a violation for this resource // Check if the policy has a violation for this resource
err := ws.violationBuilder.ResourceRemoval(policy.Name, rkind, rns, rname) err := ws.violationBuilder.ResourceRemoval(policy.Name, rkind, rns, rname)

View file

@ -1,7 +1,6 @@
package webhooks package webhooks
import ( import (
jsonpatch "github.com/evanphx/json-patch"
"github.com/golang/glog" "github.com/golang/glog"
engine "github.com/nirmata/kyverno/pkg/engine" engine "github.com/nirmata/kyverno/pkg/engine"
"github.com/nirmata/kyverno/pkg/info" "github.com/nirmata/kyverno/pkg/info"
@ -33,7 +32,6 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
} }
var allPatches [][]byte var allPatches [][]byte
var annPatches []byte
policyInfos := []*info.PolicyInfo{} policyInfos := []*info.PolicyInfo{}
for _, policy := range policies { for _, policy := range policies {
// check if policy has a rule for the admission request kind // check if policy has a rule for the admission request kind
@ -79,14 +77,8 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
annPatch := addAnnotationsToResource(request.Object.Raw, policyInfo, info.Mutation) annPatch := addAnnotationsToResource(request.Object.Raw, policyInfo, info.Mutation)
if annPatch != nil { if annPatch != nil {
if annPatches == nil { // add annotations
annPatches = annPatch ws.annotationsController.Add(rkind, rns, rname, annPatch)
} else {
annPatches, err = jsonpatch.MergePatch(annPatches, annPatch)
if err != nil {
glog.Error(err)
}
}
} }
} }
@ -94,12 +86,6 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
eventsInfo, _ := newEventInfoFromPolicyInfo(policyInfos, (request.Operation == v1beta1.Update), info.Mutation) eventsInfo, _ := newEventInfoFromPolicyInfo(policyInfos, (request.Operation == v1beta1.Update), info.Mutation)
ws.eventController.Add(eventsInfo...) ws.eventController.Add(eventsInfo...)
} }
// add annotations
if annPatches != nil {
// fmt.Println(string(annPatches))
ws.annotationsController.Add(rkind, rns, rname, annPatches)
}
ok, msg := isAdmSuccesful(policyInfos) ok, msg := isAdmSuccesful(policyInfos)
if ok { if ok {
patchType := v1beta1.PatchTypeJSONPatch patchType := v1beta1.PatchTypeJSONPatch

View file

@ -77,10 +77,18 @@ func getApplicableKindsForPolicy(p *v1alpha1.Policy) []string {
kindsMap := map[string]interface{}{} kindsMap := map[string]interface{}{}
kinds := []string{} kinds := []string{}
// iterate over the rules an identify all kinds // iterate over the rules an identify all kinds
// Matching
for _, rule := range p.Spec.Rules { for _, rule := range p.Spec.Rules {
for _, k := range rule.ResourceDescription.Kinds { for _, k := range rule.MatchResources.Kinds {
kindsMap[k] = nil kindsMap[k] = nil
} }
// remove excluded ones
for _, k := range rule.ExcludeResources.Kinds {
if _, ok := kindsMap[k]; ok {
// delete kind
delete(kindsMap, k)
}
}
} }
// get the kinds // get the kinds

View file

@ -1,7 +1,6 @@
package webhooks package webhooks
import ( import (
jsonpatch "github.com/evanphx/json-patch"
"github.com/golang/glog" "github.com/golang/glog"
engine "github.com/nirmata/kyverno/pkg/engine" engine "github.com/nirmata/kyverno/pkg/engine"
"github.com/nirmata/kyverno/pkg/info" "github.com/nirmata/kyverno/pkg/info"
@ -34,7 +33,6 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1
glog.Errorf("failed to parse KIND from request: Namespace=%s Name=%s UID=%s patchOperation=%s\n", request.Namespace, request.Name, request.UID, request.Operation) glog.Errorf("failed to parse KIND from request: Namespace=%s Name=%s UID=%s patchOperation=%s\n", request.Namespace, request.Name, request.UID, request.Operation)
} }
var annPatches []byte
for _, policy := range policies { for _, policy := range policies {
if !StringInSlice(request.Kind.Kind, getApplicableKindsForPolicy(policy)) { if !StringInSlice(request.Kind.Kind, getApplicableKindsForPolicy(policy)) {
@ -88,14 +86,7 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1
// annotations // annotations
annPatch := addAnnotationsToResource(request.Object.Raw, policyInfo, info.Validation) annPatch := addAnnotationsToResource(request.Object.Raw, policyInfo, info.Validation)
if annPatch != nil { if annPatch != nil {
if annPatches == nil { ws.annotationsController.Add(rkind, rns, rname, annPatch)
annPatches = annPatch
} else {
annPatches, err = jsonpatch.MergePatch(annPatches, annPatch)
if err != nil {
glog.Error(err)
}
}
} }
} }
@ -106,10 +97,6 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1
ws.violationBuilder.Add(violations...) ws.violationBuilder.Add(violations...)
ws.eventController.Add(eventsInfo...) ws.eventController.Add(eventsInfo...)
} }
// add annotations
if annPatches != nil {
ws.annotationsController.Add(rkind, rns, rname, annPatches)
}
// If Validation fails then reject the request // If Validation fails then reject the request
ok, msg := isAdmSuccesful(policyInfos) ok, msg := isAdmSuccesful(policyInfos)
// violations are created if "audit" flag is set // violations are created if "audit" flag is set

View file

@ -5,10 +5,11 @@ metadata :
spec : spec :
rules: rules:
- name: pCM1 - name: pCM1
resource: match:
kinds : resources:
- ConfigMap kinds :
name: "game-config" - ConfigMap
name: "game-config"
mutate: mutate:
overlay: overlay:
data: data:
@ -25,10 +26,11 @@ spec :
op : add op : add
value : newValue value : newValue
- name: pCM2 - name: pCM2
resource: match:
kinds : resources:
- ConfigMap kinds :
name: "game-config" - ConfigMap
name: "game-config"
mutate: mutate:
patches: patches:
- path : "/data/secretData" - path : "/data/secretData"
@ -37,10 +39,11 @@ spec :
op : replace op : replace
value : "data is replaced" value : "data is replaced"
- name: pCM3 - name: pCM3
resource: match:
kinds : resources:
- ConfigMap kinds :
name: "game-config" - ConfigMap
name: "game-config"
mutate: mutate:
patches: patches:
- path : "/data/secretData" - path : "/data/secretData"
@ -52,10 +55,11 @@ spec :
data: data:
game.properties: "*enemies=aliens*" game.properties: "*enemies=aliens*"
- name: pCM4 - name: pCM4
resource: match:
kinds : resources:
- ConfigMap kinds :
name: "game-config" - ConfigMap
name: "game-config"
validate: validate:
message: "This CM data is broken because it does not have ui.properties" message: "This CM data is broken because it does not have ui.properties"
pattern: pattern:

View file

@ -5,12 +5,13 @@ metadata :
spec: spec:
rules: rules:
- name: "copyCM" - name: "copyCM"
resource : match:
kinds : resources:
- Namespace kinds :
selector: - Namespace
matchLabels: selector:
LabelForSelector : "namespace2" matchLabels:
LabelForSelector : "namespace2"
generate : generate :
kind: ConfigMap kind: ConfigMap
name : copied-cm name : copied-cm

View file

@ -10,12 +10,13 @@ metadata :
spec : spec :
rules: rules:
- name: "patchNamespace2" - name: "patchNamespace2"
resource : match:
kinds : resources:
- Namespace kinds :
selector: - Namespace
matchLabels: selector:
LabelForSelector : "namespace2" matchLabels:
LabelForSelector : "namespace2"
mutate: mutate:
patches: patches:
- path: "/metadata/labels/isMutatedByPolicy" - path: "/metadata/labels/isMutatedByPolicy"
@ -23,12 +24,13 @@ spec :
value: "true" value: "true"
- name: "copyCM" - name: "copyCM"
resource : match:
kinds : resources:
- Namespace kinds :
selector: - Namespace
matchLabels: selector:
LabelForSelector : "namespace2" matchLabels:
LabelForSelector : "namespace2"
generate : generate :
kind: ConfigMap kind: ConfigMap
name : copied-cm name : copied-cm
@ -37,12 +39,13 @@ spec :
name : game-config name : game-config
- name: "generateCM" - name: "generateCM"
resource : match:
kinds : resources:
- Namespace kinds :
selector: - Namespace
matchLabels: selector:
LabelForSelector : "namespace2" matchLabels:
LabelForSelector : "namespace2"
generate : generate :
kind: ConfigMap kind: ConfigMap
name : generated-cm name : generated-cm
@ -56,10 +59,11 @@ spec :
rsa.public.key=42 rsa.public.key=42
- name: "generateSecret" - name: "generateSecret"
resource : match:
kinds : resources:
- Namespace kinds :
name: ns2 - Namespace
name: ns2
generate : generate :
kind: Secret kind: Secret
name : generated-secrets name : generated-secrets
@ -73,10 +77,11 @@ spec :
foo2=bar2 foo2=bar2
- name: "copySecret" - name: "copySecret"
resource : match:
kinds : resources:
- Namespace kinds :
name: ns2 - Namespace
name: ns2
generate : generate :
kind: Secret kind: Secret
name : copied-secrets name : copied-secrets

View file

@ -5,10 +5,11 @@ metadata:
spec: spec:
rules: rules:
- name: pCJ - name: pCJ
resource: match:
kinds : resources:
- CronJob kinds :
name: "?ell*" - CronJob
name: "?ell*"
mutate: mutate:
patches: patches:
- path: "/metadata/labels/isMutated" - path: "/metadata/labels/isMutated"

View file

@ -5,10 +5,11 @@ metadata:
spec: spec:
rules: rules:
- name: "Patch and Volume validation" - name: "Patch and Volume validation"
resource: match:
kinds: resources:
- DaemonSet kinds:
name: fluentd-elasticsearch - DaemonSet
name: fluentd-elasticsearch
mutate: mutate:
patches: patches:
- path: "/metadata/labels/isMutated" - path: "/metadata/labels/isMutated"

View file

@ -5,9 +5,10 @@ metadata :
spec : spec :
rules: rules:
- name: "First policy v2" - name: "First policy v2"
resource: match:
kinds : resources:
- Deployment kinds :
- Deployment
mutate: mutate:
patches: patches:
- path: /metadata/labels/isMutated - path: /metadata/labels/isMutated
@ -16,7 +17,6 @@ spec :
- path: /metadata/labels/app - path: /metadata/labels/app
op: replace op: replace
value: "nginx_is_mutated" value: "nginx_is_mutated"
validate: validate:
message: "Because I like only mutated resources" message: "Because I like only mutated resources"
pattern: pattern:

View file

@ -5,12 +5,13 @@ metadata :
spec : spec :
rules: rules:
- name: pEP - name: pEP
resource: match:
kinds : resources:
- Endpoints kinds :
selector: - Endpoints
matchLabels: selector:
label : test matchLabels:
label : test
mutate: mutate:
patches: patches:
- path : "/subsets/0/ports/0/port" - path : "/subsets/0/ports/0/port"

View file

@ -5,12 +5,13 @@ metadata:
spec : spec :
rules: rules:
- name: hpa1 - name: hpa1
resource: match:
kinds : resources:
- HorizontalPodAutoscaler kinds :
selector: - HorizontalPodAutoscaler
matchLabels: selector:
originalLabel: isHere matchLabels:
originalLabel: isHere
mutate: mutate:
patches: patches:
- path: "/metadata/labels/isMutated" - path: "/metadata/labels/isMutated"

View file

@ -5,12 +5,13 @@ metadata :
spec : spec :
rules: rules:
- name: ingress1 - name: ingress1
resource: match:
kinds : resources:
- Ingress kinds :
selector: - Ingress
matchLabels: selector:
originalLabel: isHere matchLabels:
originalLabel: isHere
mutate: mutate:
patches: patches:
- path: "/metadata/labels/isMutated" - path: "/metadata/labels/isMutated"

View file

@ -5,10 +5,11 @@ metadata:
spec : spec :
rules: rules:
- name: job2 - name: job2
resource: match:
kinds: resources:
- Job kinds:
name: pi - Job
name: pi
mutate: mutate:
overlay: overlay:
spec: spec:
@ -20,10 +21,11 @@ spec :
- containerPort: 80 - containerPort: 80
protocol: TCP protocol: TCP
- name: job1 - name: job1
resource: match:
kinds: resources:
- Job kinds:
name: pi - Job
name: pi
mutate: mutate:
overlay: overlay:
metadata: metadata:

View file

@ -5,12 +5,13 @@ metadata :
spec : spec :
rules: rules:
- name: "rule" - name: "rule"
resource: match:
kinds : resources:
- LimitRange kinds :
selector: - LimitRange
matchLabels: selector:
containerSize: minimal matchLabels:
containerSize: minimal
mutate: mutate:
patches: patches:
- path : "/spec/limits/0/default/memory" - path : "/spec/limits/0/default/memory"

View file

@ -6,12 +6,13 @@ metadata :
spec : spec :
rules: rules:
- name: ns1 - name: ns1
resource: match:
kinds : resources:
- Namespace kinds :
selector: - Namespace
matchLabels: selector:
LabelForSelector : "namespace" matchLabels:
LabelForSelector : "namespace"
mutate: mutate:
patches: patches:
- path: "/metadata/labels/replaced" - path: "/metadata/labels/replaced"

View file

@ -5,12 +5,13 @@ metadata:
spec: spec:
rules: rules:
- name: np1 - name: np1
resource: match:
kinds : resources:
- NetworkPolicy kinds :
selector: - NetworkPolicy
matchLabels: selector:
originalLabel: isHere matchLabels:
originalLabel: isHere
mutate: mutate:
patches: patches:
- path: "/metadata/labels/isMutated" - path: "/metadata/labels/isMutated"

View file

@ -5,11 +5,12 @@ metadata:
spec: spec:
rules: rules:
- name: pvc1 - name: pvc1
resource: match:
kinds : resources:
- PersistentVolumeClaim kinds :
matchLabels: - PersistentVolumeClaim
originalLabel: isHere matchLabels:
originalLabel: isHere
mutate: mutate:
patches: patches:
- path: "/metadata/labels/originalLabel" - path: "/metadata/labels/originalLabel"

View file

@ -5,10 +5,11 @@ metadata:
spec: spec:
rules: rules:
- name: pdb1 - name: pdb1
resource: match:
kinds : resources:
- PodDisruptionBudget kinds :
name: "game-pdb" - PodDisruptionBudget
name: "game-pdb"
mutate: mutate:
patches: patches:
- path: "/metadata/labels/isMutated" - path: "/metadata/labels/isMutated"

View file

@ -5,12 +5,13 @@ metadata:
spec: spec:
rules: rules:
- name: podtemplate1 - name: podtemplate1
resource: match:
kinds : resources:
- PodTemplate kinds :
selector: - PodTemplate
matchLabels: selector:
originalLabel: isHere matchLabels:
originalLabel: isHere
mutate: mutate:
overlay: overlay:
template: template:

View file

@ -5,12 +5,13 @@ metadata :
spec : spec :
rules: rules:
- name: "rule1" - name: "rule1"
resource: match:
kinds : resources:
- ResourceQuota kinds :
selector: - ResourceQuota
matchLabels: selector:
quota: low matchLabels:
quota: low
validate: validate:
message: "This RQ requests too many RAM" message: "This RQ requests too many RAM"
pattern: pattern:
@ -18,12 +19,13 @@ spec :
hard: hard:
memory: "8Gi|12Gi" memory: "8Gi|12Gi"
- name: "rule2" - name: "rule2"
resource: match:
kinds : resources:
- ResourceQuota kinds :
selector: - ResourceQuota
matchLabels: selector:
quota: low matchLabels:
quota: low
validate: validate:
message: "This RQ requests too many CPUs" message: "This RQ requests too many CPUs"
pattern: pattern:
@ -31,12 +33,13 @@ spec :
hard: hard:
cpu: <3 cpu: <3
- name: "rule3" - name: "rule3"
resource: match:
kinds : resources:
- ResourceQuota kinds :
selector: - ResourceQuota
matchLabels: selector:
quota: low matchLabels:
quota: low
validate: validate:
message: "This RQ requests too many PODs" message: "This RQ requests too many PODs"
pattern: pattern:

View file

@ -5,12 +5,13 @@ metadata :
spec : spec :
rules: rules:
- name: "rule" - name: "rule"
resource: match:
kinds : resources:
- ResourceQuota kinds :
selector: - ResourceQuota
matchLabels: selector:
quota: low matchLabels:
quota: low
mutate: mutate:
patches: patches:
- path : "/spec/scopeSelector/matchExpressions/1" - path : "/spec/scopeSelector/matchExpressions/1"

View file

@ -5,10 +5,11 @@ metadata:
spec: spec:
rules: rules:
- name: secret1 - name: secret1
resource: match:
kinds : resources:
- Secret kinds :
name: "mysecret" - Secret
name: "mysecret"
mutate: mutate:
patches: patches:
- path: "/metadata/labels/isMutated" - path: "/metadata/labels/isMutated"

View file

@ -5,12 +5,13 @@ metadata:
spec: spec:
rules: rules:
- name: set-userID - name: set-userID
resource: match:
kinds: resources:
- Deployment kinds:
selector : - Deployment
matchLabels: selector :
app.type: prod matchLabels:
app.type: prod
mutate: mutate:
overlay: overlay:
spec: spec:

View file

@ -5,10 +5,11 @@ metadata :
spec : spec :
rules: rules:
- name: ps1 - name: ps1
resource: match:
kinds: resources:
- Service kinds:
name: "game-service*" - Service
name: "game-service*"
mutate: mutate:
patches: patches:
- path: "/metadata/labels/isMutated" - path: "/metadata/labels/isMutated"

View file

@ -5,12 +5,13 @@ metadata:
spec: spec:
rules: rules:
- name: statefulset1 - name: statefulset1
resource: match:
kinds : resources:
- StatefulSet kinds :
selector: - StatefulSet
matchLabels: selector:
originalLabel: isHere matchLabels:
originalLabel: isHere
mutate: mutate:
patches: patches:
- path: "/spec/template/metadata/labels/isMutated" - path: "/spec/template/metadata/labels/isMutated"

View file

@ -5,12 +5,13 @@ metadata :
spec : spec :
rules: rules:
- name: add-label - name: add-label
resource: match:
kinds : resources:
- Deployment kinds :
selector : - Deployment
matchLabels : selector :
cli: test matchLabels :
cli: test
mutate: mutate:
patches: patches:
- path: /metadata/labels/isMutated - path: /metadata/labels/isMutated
@ -25,36 +26,39 @@ spec :
- (image): "*nginx*" - (image): "*nginx*"
imagePullPolicy: "Always" imagePullPolicy: "Always"
- name: add-label2 - name: add-label2
resource: match:
kinds : resources:
- Deployment kinds :
selector : - Deployment
matchLabels : selector :
cli: test matchLabels :
cli: test
mutate: mutate:
patches: patches:
- path: /metadata/labels/app1 - path: /metadata/labels/app1
op: replace op: replace
value: "nginx_is_mutated" value: "nginx_is_mutated"
- name: add-label3 - name: add-label3
resource: match:
kinds : resources:
- Deployment kinds :
selector : - Deployment
matchLabels : selector :
cli: test matchLabels :
cli: test
mutate: mutate:
patches: patches:
- path: /metadata/labels/app2 - path: /metadata/labels/app2
op: add op: add
value: "nginx_is_mutated2" value: "nginx_is_mutated2"
- name: check-image - name: check-image
resource: match:
kinds : resources:
- Deployment kinds :
selector : - Deployment
matchLabels : selector :
cli: test matchLabels :
cli: test
validate: validate:
message: "The imagePullPolicy must be Always when using image nginx" message: "The imagePullPolicy must be Always when using image nginx"
pattern: pattern:
@ -65,10 +69,11 @@ spec :
- (image): "*nginx*" - (image): "*nginx*"
imagePullPolicy: "Always" imagePullPolicy: "Always"
- name: check-registries - name: check-registries
resource: match:
kinds: resources:
- Deployment kinds:
- StatefulSet - Deployment
- StatefulSet
validate: validate:
message: "Registry is not allowed" message: "Registry is not allowed"
pattern: pattern: