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:
commit
96393ed6e7
72 changed files with 981 additions and 605 deletions
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Add table
Reference in a new issue