1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +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 kind: Policy
metadata: metadata:
name: policy-security-context name: check-container-security-context
spec: spec:
# validationFailureAction: "audit"
rules: rules:
- name: validate-runAsNonRoot - name: check-root-user
exclude:
resources:
namespaces:
- kube-system
match: match:
resources: resources:
kinds: kinds:
- Deployment - Pod
selector :
matchLabels:
test: psp
validate: validate:
message: "security context 'runAsNonRoot' shoud be set to true" message: "Root user is not allowed. Set runAsNonRoot to true."
pattern: anyPattern:
spec: - spec:
template: securityContext:
spec: runAsNonRoot: true
- spec:
containers:
- name: "*"
securityContext: securityContext:
runAsNonRoot: true runAsNonRoot: true

View file

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

View file

@ -1,7 +1,6 @@
package engine package engine
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"path/filepath" "path/filepath"
@ -18,18 +17,6 @@ import (
// Validate handles validating admission request // Validate handles validating admission request
// Checks the target resources for rules defined in the policy // Checks the target resources for rules defined in the policy
func Validate(policy kyverno.Policy, resource unstructured.Unstructured) EngineResponse { 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 var ruleInfos []info.RuleInfo
for _, rule := range policy.Spec.Rules { for _, rule := range policy.Spec.Rules {
@ -46,22 +33,54 @@ func Validate(policy kyverno.Policy, resource unstructured.Unstructured) EngineR
continue continue
} }
ruleInfo := info.NewRuleInfo(rule.Name, info.Validation) ruleInfo := validatePatterns(resource, rule.Validation, rule.Name)
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())
}
ruleInfos = append(ruleInfos, ruleInfo) ruleInfos = append(ruleInfos, ruleInfo)
} }
return EngineResponse{RuleInfos: ruleInfos} 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 // validateResourceWithPattern is a start of element-by-element validation process
// It assumes that validation is started from root, so "/" is passed // It assumes that validation is started from root, so "/" is passed
func validateResourceWithPattern(resource, pattern interface{}) error { 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 { if err := json.Unmarshal(raw, &policy); err != nil {
glog.Errorf("Failed to unmarshal policy admission request, err %v\n", err) 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 { 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 { func (ws *WebhookServer) validateOverlayPattern(policy *kyverno.Policy) *v1beta1.AdmissionResponse {
for _, rule := range policy.Spec.Rules { for _, rule := range policy.Spec.Rules {
if !reflect.DeepEqual(rule.Validation, kyverno.Validation{}) { if reflect.DeepEqual(rule.Validation, kyverno.Validation{}) {
if rule.Validation.Pattern == nil && rule.Validation.AnyPattern == nil { continue
return &v1beta1.AdmissionResponse{ }
Allowed: false,
Result: &metav1.Status{ if rule.Validation.Pattern == nil && len(rule.Validation.AnyPattern) == 0 {
Message: "Invalid policy, either pattern or anyPattern found in policy spec", return &v1beta1.AdmissionResponse{
}, Allowed: false,
} Result: &metav1.Status{
Message: fmt.Sprintf("Invalid policy, neither pattern nor anyPattern found in validate rule %s", rule.Name),
},
} }
} }
} }