diff --git a/README.md b/README.md index 2335a3b78f..12506896d1 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ See [Milestones](https://github.com/nirmata/kyverno/milestones) and [Issues](htt ## Getting help * For feature requests and bugs, file an [issue](https://github.com/nirmata/kyverno/issues). - * For discussions or questions, join our [Kubernetes Slack channel #kyverno](https://app.slack.com/client/T09NY5SBT/CLGR9BJU9) or the [mailing list](https://groups.google.com/forum/#!forum/kyverno) + * For discussions or questions, join the **#kyverno** channel on the [Kubernetes Slack](https://kubernetes.slack.com/) or the [mailing list](https://groups.google.com/forum/#!forum/kyverno) ## Contributing diff --git a/definitions/install.yaml b/definitions/install.yaml index f7ebfb5590..d5c433bb77 100644 --- a/definitions/install.yaml +++ b/definitions/install.yaml @@ -20,6 +20,7 @@ spec: validation: openAPIV3Schema: properties: + status: {} spec: required: - rules diff --git a/definitions/install_debug.yaml b/definitions/install_debug.yaml index 3598dbca1d..d0193eb91e 100644 --- a/definitions/install_debug.yaml +++ b/definitions/install_debug.yaml @@ -20,6 +20,7 @@ spec: validation: openAPIV3Schema: properties: + status: {} spec: required: - rules diff --git a/documentation/writing-policies-mutate.md b/documentation/writing-policies-mutate.md index 9486d33598..68b6aaa45e 100644 --- a/documentation/writing-policies-mutate.md +++ b/documentation/writing-policies-mutate.md @@ -20,28 +20,31 @@ A JSON Patch rule provides an alternate way to mutate resources. With Kyverno, the add and replace have the same behavior i.e. both operations will add or replace the target element. -This patch adds an init container to all deployments. +This patch policy adds, or replaces, entries in a `ConfigMap` with the name `config-game` in any namespace. ````yaml -apiVersion: kyverno.io/v1 -kind: ClusterPolicy -metadata: - name: policy-v1 -spec: +apiVersion : kyverno.io/v1 +kind : ClusterPolicy +metadata : + name : policy-generate-cm +spec : rules: - - name: "add-init-secrets" + - name: pCM1 match: resources: - kinds: - - Deployment + name: "config-game" + kinds : + - ConfigMap mutate: - overlay: - spec: - template: - spec: - initContainers: - - name: init-secrets - image: nirmata.io/kube-vault-client:v2 + patches: + - path: "/data/ship.properties" + op: add + value: | + type=starship + owner=utany.corp + - path : "/data/newKey1" + op : add + value : newValue1 ```` Here is the example of a patch that removes a label from the secret: diff --git a/pkg/api/kyverno/v1/types.go b/pkg/api/kyverno/v1/types.go index a05adb96e4..4c7bc74c59 100644 --- a/pkg/api/kyverno/v1/types.go +++ b/pkg/api/kyverno/v1/types.go @@ -121,7 +121,7 @@ type Policy struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` Spec Spec `json:"spec"` - Status PolicyStatus `json:"status"` + Status PolicyStatus `json:"status,omitempty"` } // Spec describes policy behavior by its rules @@ -236,7 +236,7 @@ type CloneFrom struct { // PolicyStatus mostly contains statistics related to policy type PolicyStatus struct { // average time required to process the policy rules on a resource - AvgExecutionTime string `json:"averageExecutionTime"` + AvgExecutionTime string `json:"averageExecutionTime,omitempty"` // number of violations created by this policy ViolationCount int `json:"violationCount,omitempty"` // Count of rules that failed diff --git a/pkg/generate/policyStatus_test.go b/pkg/generate/policyStatus_test.go index b0fa04b591..b465a8547b 100644 --- a/pkg/generate/policyStatus_test.go +++ b/pkg/generate/policyStatus_test.go @@ -15,7 +15,7 @@ func Test_Stats(t *testing.T) { expectedOutput []byte existingStatus map[string]v1.PolicyStatus }{ - expectedOutput: []byte(`{"policy1":{"averageExecutionTime":"","resourcesGeneratedCount":2,"ruleStatus":[{"ruleName":"rule1","averageExecutionTime":"23ns","resourcesGeneratedCount":1},{"ruleName":"rule2","averageExecutionTime":"44ns","resourcesGeneratedCount":1},{"ruleName":"rule3"}]}}`), + expectedOutput: []byte(`{"policy1":{"resourcesGeneratedCount":2,"ruleStatus":[{"ruleName":"rule1","averageExecutionTime":"23ns","resourcesGeneratedCount":1},{"ruleName":"rule2","averageExecutionTime":"44ns","resourcesGeneratedCount":1},{"ruleName":"rule3"}]}}`), generatedSyncStats: []generateSyncStats{ { policyName: "policy1", diff --git a/pkg/policy/validate.go b/pkg/policy/validate.go index dd8f336406..a6693e4373 100644 --- a/pkg/policy/validate.go +++ b/pkg/policy/validate.go @@ -94,10 +94,6 @@ func Validate(policyRaw []byte, client *dclient.Client, mock bool, openAPIContro // of match and exclude block is not an empty set func doesMatchAndExcludeConflict(rule kyverno.Rule) bool { - if reflect.DeepEqual(rule.MatchResources, kyverno.MatchResources{}) { - return true - } - if reflect.DeepEqual(rule.ExcludeResources, kyverno.ExcludeResources{}) { return false } @@ -137,6 +133,10 @@ func doesMatchAndExcludeConflict(rule kyverno.Rule) bool { } if len(excludeRoles) > 0 { + if len(rule.MatchResources.UserInfo.Roles) == 0 { + return false + } + for _, role := range rule.MatchResources.UserInfo.Roles { if !excludeRoles[role] { return false @@ -145,6 +145,10 @@ func doesMatchAndExcludeConflict(rule kyverno.Rule) bool { } if len(excludeClusterRoles) > 0 { + if len(rule.MatchResources.UserInfo.ClusterRoles) == 0 { + return false + } + for _, clusterRole := range rule.MatchResources.UserInfo.ClusterRoles { if !excludeClusterRoles[clusterRole] { return false @@ -153,6 +157,10 @@ func doesMatchAndExcludeConflict(rule kyverno.Rule) bool { } if len(excludeSubjects) > 0 { + if len(rule.MatchResources.UserInfo.Subjects) == 0 { + return false + } + for _, subject := range rule.MatchResources.UserInfo.Subjects { subjectRaw, _ := json.Marshal(subject) if !excludeSubjects[string(subjectRaw)] { @@ -168,6 +176,10 @@ func doesMatchAndExcludeConflict(rule kyverno.Rule) bool { } if len(excludeNamespaces) > 0 { + if len(rule.MatchResources.ResourceDescription.Namespaces) == 0 { + return false + } + for _, namespace := range rule.MatchResources.ResourceDescription.Namespaces { if !excludeNamespaces[namespace] { return false @@ -176,6 +188,10 @@ func doesMatchAndExcludeConflict(rule kyverno.Rule) bool { } if len(excludeKinds) > 0 { + if len(rule.MatchResources.ResourceDescription.Kinds) == 0 { + return false + } + for _, kind := range rule.MatchResources.ResourceDescription.Kinds { if !excludeKinds[kind] { return false @@ -185,6 +201,10 @@ func doesMatchAndExcludeConflict(rule kyverno.Rule) bool { if rule.MatchResources.ResourceDescription.Selector != nil && rule.ExcludeResources.ResourceDescription.Selector != nil { if len(excludeMatchExpressions) > 0 { + if len(rule.MatchResources.ResourceDescription.Selector.MatchExpressions) == 0 { + return false + } + for _, matchExpression := range rule.MatchResources.ResourceDescription.Selector.MatchExpressions { matchExpressionRaw, _ := json.Marshal(matchExpression) if !excludeMatchExpressions[string(matchExpressionRaw)] { @@ -194,6 +214,10 @@ func doesMatchAndExcludeConflict(rule kyverno.Rule) bool { } if len(rule.ExcludeResources.ResourceDescription.Selector.MatchLabels) > 0 { + if len(rule.MatchResources.ResourceDescription.Selector.MatchLabels) == 0 { + return false + } + for label, value := range rule.MatchResources.ResourceDescription.Selector.MatchLabels { if rule.ExcludeResources.ResourceDescription.Selector.MatchLabels[label] != value { return false diff --git a/pkg/policy/validate_test.go b/pkg/policy/validate_test.go index 0ca0778dd6..6b5717ea7f 100644 --- a/pkg/policy/validate_test.go +++ b/pkg/policy/validate_test.go @@ -1022,6 +1022,11 @@ func Test_doesMatchExcludeConflict(t *testing.T) { rule: []byte(`{"name":"set-image-pull-policy-2","match":{"resources":{"kinds":["Pod","Namespace"],"name":"somxething","namespaces":["something","something1"]}},"exclude":{"resources":{"kinds":["Pod","Namespace","Job"],"name":"some*","namespaces":["something","something1","something2"]}}}`), expectedOutput: false, }, + { + description: "empty case", + rule: []byte(`{"name":"check-allow-deletes","match":{"resources":{"selector":{"matchLabels":{"allow-deletes":"false"}}}},"exclude":{"clusterRoles":["random"]},"validate":{"message":"Deleting {{request.object.kind}}/{{request.object.metadata.name}} is not allowed","deny":{"conditions":[{"key":"{{request.operation}}","operator":"Equal","value":"DELETE"}]}}}`), + expectedOutput: false, + }, } for i, testcase := range testcases { diff --git a/pkg/policystatus/main.go b/pkg/policystatus/main.go index b21ff2e505..6e89d41b9b 100644 --- a/pkg/policystatus/main.go +++ b/pkg/policystatus/main.go @@ -80,7 +80,7 @@ func (s *Sync) Run(workers int, stopCh <-chan struct{}) { go s.updateStatusCache(stopCh) } - wait.Until(s.updatePolicyStatus, 2*time.Second, stopCh) + wait.Until(s.updatePolicyStatus, 10*time.Second, stopCh) <-stopCh } diff --git a/pkg/policystatus/status_test.go b/pkg/policystatus/status_test.go index 310852cf2f..c36f1a5c0f 100644 --- a/pkg/policystatus/status_test.go +++ b/pkg/policystatus/status_test.go @@ -28,7 +28,7 @@ func (d dummyStatusUpdater) PolicyName() string { } func TestKeyToMutex(t *testing.T) { - expectedCache := `{"policy1":{"averageExecutionTime":"","rulesAppliedCount":100}}` + expectedCache := `{"policy1":{"rulesAppliedCount":100}}` stopCh := make(chan struct{}) s := NewSync(nil, dummyStore{}) diff --git a/pkg/policyviolation/policyStatus_test.go b/pkg/policyviolation/policyStatus_test.go index 8db26ae4a6..39f718ba13 100644 --- a/pkg/policyviolation/policyStatus_test.go +++ b/pkg/policyviolation/policyStatus_test.go @@ -33,7 +33,7 @@ func Test_Stats(t *testing.T) { }, }, }, - expectedOutput: []byte(`{"policy1":{"averageExecutionTime":"","violationCount":1,"ruleStatus":[{"ruleName":"rule4","violationCount":1}]},"policy2":{"averageExecutionTime":"","violationCount":1,"ruleStatus":[{"ruleName":"rule4","violationCount":1}]}}`), + expectedOutput: []byte(`{"policy1":{"violationCount":1,"ruleStatus":[{"ruleName":"rule4","violationCount":1}]},"policy2":{"violationCount":1,"ruleStatus":[{"ruleName":"rule4","violationCount":1}]}}`), violationCountStats: []struct { policyName string violatedRules []v1.ViolatedRule diff --git a/samples/RequirePodRequestsLimits.md b/samples/RequirePodRequestsLimits.md index 173492b408..d49220391b 100644 --- a/samples/RequirePodRequestsLimits.md +++ b/samples/RequirePodRequestsLimits.md @@ -31,5 +31,4 @@ spec: cpu: "?*" limits: memory: "?*" - cpu: "?*" ```` diff --git a/samples/best_practices/require_pod_requests_limits.yaml b/samples/best_practices/require_pod_requests_limits.yaml index 3902b97c6b..175f5c01c7 100644 --- a/samples/best_practices/require_pod_requests_limits.yaml +++ b/samples/best_practices/require_pod_requests_limits.yaml @@ -26,5 +26,4 @@ spec: memory: "?*" cpu: "?*" limits: - memory: "?*" - cpu: "?*" \ No newline at end of file + memory: "?*" \ No newline at end of file diff --git a/test/scenarios/samples/best_practices/require_pod_requests_limits.yaml b/test/scenarios/samples/best_practices/require_pod_requests_limits.yaml index 31fa5d4df0..ee05cc8f5a 100644 --- a/test/scenarios/samples/best_practices/require_pod_requests_limits.yaml +++ b/test/scenarios/samples/best_practices/require_pod_requests_limits.yaml @@ -14,4 +14,4 @@ expected: rules: - name: validate-resources type: Validation - success: false + success: true