1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-28 10:28:36 +00:00

add anyPattern in validate rule

This commit is contained in:
Shuting Zhao 2019-08-21 12:38:15 -07:00
parent 124b105736
commit 97335270cd
4 changed files with 81 additions and 63 deletions

View file

@ -1,22 +1,27 @@
apiVersion : kyverno.io/v1alpha1
apiVersion: kyverno.io/v1alpha1
kind: Policy
metadata:
name: policy-security-context
name: check-container-security-context
spec:
# validationFailureAction: "audit"
rules:
- name: validate-runAsNonRoot
- name: check-root-user
exclude:
resources:
namespaces:
- kube-system
match:
resources:
kinds:
- Deployment
selector :
matchLabels:
test: psp
- Pod
validate:
message: "security context 'runAsNonRoot' shoud be set to true"
pattern:
spec:
template:
spec:
message: "Root user is not allowed. Set runAsNonRoot to true."
anyPattern:
- spec:
securityContext:
runAsNonRoot: true
- spec:
containers:
- name: "*"
securityContext:
runAsNonRoot: true

View file

@ -1,21 +1,10 @@
apiVersion: apps/v1
kind: Deployment
apiVersion: v1
kind: Pod
metadata:
name: psp-demo-unprivileged
labels:
test: psp
name: sec-ctx-unprivileged
spec:
replicas: 1
selector:
matchLabels:
test: psp
template:
metadata:
labels:
test: psp
spec:
securityContext:
runAsNonRoot: true
containers:
- name: sec-ctx-unprivileged
image: nginxinc/nginx-unprivileged
# securityContext:
# runAsNonRoot: true
containers:
- name: imagen-with-hostpath
image: nginxinc/nginx-unprivileged

View file

@ -1,7 +1,6 @@
package engine
import (
"encoding/json"
"errors"
"fmt"
"path/filepath"
@ -18,18 +17,6 @@ import (
// Validate handles validating admission request
// Checks the target resources for rules defined in the policy
func Validate(policy kyverno.Policy, resource unstructured.Unstructured) EngineResponse {
resourceRaw, err := resource.MarshalJSON()
if err != nil {
glog.V(4).Infof("Skip processing validating rule, unable to marshal resource : %v\n", err)
return EngineResponse{PatchedResource: resource}
}
var resourceInt interface{}
if err := json.Unmarshal(resourceRaw, &resourceInt); err != nil {
glog.V(4).Infof("unable to unmarshal resource : %v\n", err)
return EngineResponse{PatchedResource: resource}
}
var ruleInfos []info.RuleInfo
for _, rule := range policy.Spec.Rules {
@ -46,22 +33,54 @@ func Validate(policy kyverno.Policy, resource unstructured.Unstructured) EngineR
continue
}
ruleInfo := info.NewRuleInfo(rule.Name, info.Validation)
err := validateResourceWithPattern(resourceInt, rule.Validation.Pattern)
if err != nil {
ruleInfo.Fail()
ruleInfo.Addf("Failed to apply pattern: %v.", err)
} else {
ruleInfo.Add("Pattern succesfully validated")
glog.V(4).Infof("pattern validated succesfully on resource %s/%s", resource.GetNamespace(), resource.GetName())
}
ruleInfo := validatePatterns(resource, rule.Validation, rule.Name)
ruleInfos = append(ruleInfos, ruleInfo)
}
return EngineResponse{RuleInfos: ruleInfos}
}
// validatePatterns validate pattern and anyPattern
func validatePatterns(resource unstructured.Unstructured, validation kyverno.Validation, ruleName string) info.RuleInfo {
var errs []error
ruleInfo := info.NewRuleInfo(ruleName, info.Validation)
if validation.Pattern != nil {
err := validateResourceWithPattern(resource.Object, validation.Pattern)
if err != nil {
ruleInfo.Fail()
ruleInfo.Addf("Failed to apply pattern: %v", err)
} else {
ruleInfo.Add("Pattern succesfully validated")
glog.V(4).Infof("pattern validated succesfully on resource %s/%s", resource.GetNamespace(), resource.GetName())
}
return ruleInfo
}
if validation.AnyPattern != nil {
for _, pattern := range validation.AnyPattern {
if err := validateResourceWithPattern(resource.Object, pattern); err != nil {
errs = append(errs, err)
}
}
failedPattern := len(errs)
patterns := len(validation.AnyPattern)
// all pattern fail
if failedPattern == patterns {
ruleInfo.Fail()
ruleInfo.Addf("None of anyPattern succeed: %v", errs)
} else {
ruleInfo.Addf("%d/%d patterns succesfully validated", patterns-failedPattern, patterns)
glog.V(4).Infof("%d/%d patterns validated succesfully on resource %s/%s", patterns-failedPattern, patterns, resource.GetNamespace(), resource.GetName())
}
return ruleInfo
}
return info.RuleInfo{}
}
// validateResourceWithPattern is a start of element-by-element validation process
// It assumes that validation is started from root, so "/" is passed
func validateResourceWithPattern(resource, pattern interface{}) error {

View file

@ -25,7 +25,10 @@ func (ws *WebhookServer) HandlePolicyValidation(request *v1beta1.AdmissionReques
}
if err := json.Unmarshal(raw, &policy); err != nil {
glog.Errorf("Failed to unmarshal policy admission request, err %v\n", err)
return &v1beta1.AdmissionResponse{Allowed: false}
return &v1beta1.AdmissionResponse{Allowed: false,
Result: &metav1.Status{
Message: fmt.Sprintf("Failed to unmarshal policy admission request err %v", err),
}}
}
if request.Operation != v1beta1.Delete {
@ -50,14 +53,16 @@ func (ws *WebhookServer) validatePolicy(policy *kyverno.Policy) *v1beta1.Admissi
func (ws *WebhookServer) validateOverlayPattern(policy *kyverno.Policy) *v1beta1.AdmissionResponse {
for _, rule := range policy.Spec.Rules {
if !reflect.DeepEqual(rule.Validation, kyverno.Validation{}) {
if rule.Validation.Pattern == nil && rule.Validation.AnyPattern == nil {
return &v1beta1.AdmissionResponse{
Allowed: false,
Result: &metav1.Status{
Message: "Invalid policy, either pattern or anyPattern found in policy spec",
},
}
if reflect.DeepEqual(rule.Validation, kyverno.Validation{}) {
continue
}
if rule.Validation.Pattern == nil && len(rule.Validation.AnyPattern) == 0 {
return &v1beta1.AdmissionResponse{
Allowed: false,
Result: &metav1.Status{
Message: fmt.Sprintf("Invalid policy, neither pattern nor anyPattern found in validate rule %s", rule.Name),
},
}
}
}