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

feat: assert rule autogen (#10780)

* Support autogen for assert validation rules

Signed-off-by: Frank Jogeleit <frank.jogeleit@web.de>

* simplify assert autogen logic

Signed-off-by: Frank Jogeleit <frank.jogeleit@web.de>

* add chainsaw test

Signed-off-by: Frank Jogeleit <frank.jogeleit@web.de>

---------

Signed-off-by: Frank Jogeleit <frank.jogeleit@web.de>
This commit is contained in:
Frank Jogeleit 2024-08-05 12:59:55 +02:00 committed by GitHub
parent cfef8a089a
commit 91ffbb6758
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 191 additions and 0 deletions

View file

@ -160,6 +160,11 @@ func (r *Rule) HasValidateCEL() bool {
return r.Validation.CEL != nil && !datautils.DeepEqual(r.Validation.CEL, &CEL{})
}
// HasValidateAssert checks for validate.assert rule
func (r *Rule) HasValidateAssert() bool {
return !datautils.DeepEqual(r.Validation.Assert, AssertionTree{})
}
// HasValidate checks for validate rule
func (r *Rule) HasValidate() bool {
return !datautils.DeepEqual(r.Validation, Validation{})

View file

@ -19,6 +19,7 @@ const (
var (
PodControllers = sets.New("DaemonSet", "Deployment", "Job", "StatefulSet", "ReplicaSet", "ReplicationController", "CronJob")
podControllersKindsSet = PodControllers.Union(sets.New("Pod"))
assertAutogenNodes = []string{"object", "oldObject"}
)
func isKindOtherthanPod(kinds []string) bool {
@ -275,3 +276,38 @@ func computeRules(p kyvernov1.PolicyInterface, kind string) []kyvernov1.Rule {
out = append(out, genRules...)
return out
}
func copyMap(m map[string]any) map[string]any {
newMap := make(map[string]any, len(m))
for k, v := range m {
newMap[k] = v
}
return newMap
}
func createAutogenAssertion(tree kyvernov1.AssertionTree, tplKey string) kyvernov1.AssertionTree {
v, ok := tree.Value.(map[string]any)
if !ok {
return tree
}
value := copyMap(v)
for _, n := range assertAutogenNodes {
object, ok := v[n].(map[string]any)
if !ok {
continue
}
value[n] = map[string]any{
"spec": map[string]any{
tplKey: copyMap(object),
},
}
}
return kyvernov1.AssertionTree{
Value: value,
}
}

View file

@ -596,3 +596,50 @@ func Test_ValidateWithCELExpressions(t *testing.T) {
rules := computeRules(policies[0], "DaemonSet")
assert.Equal(t, 2, len(rules))
}
func Test_ValidateWithAssertion(t *testing.T) {
policy := []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "disallow-default-sa"
},
"spec": {
"validationFailureAction": "Enforce",
"background": false,
"rules": [
{
"name": "default-sa",
"match": {
"any": [
{
"resources": {
"kinds": [
"Pod"
]
}
}
]
},
"validate": {
"assert": {
"object": {
"spec": {
"(serviceAccountName == 'default')": false
}
}
}
}
}
]
}
}
`)
policies, _, _, err := yamlutils.GetPolicy([]byte(policy))
assert.NilError(t, err)
assert.Equal(t, 1, len(policies))
rules := computeRules(policies[0], "")
assert.Equal(t, 3, len(rules))
}

View file

@ -207,6 +207,11 @@ func generateRule(name string, rule *kyvernov1.Rule, tplKey, shift string, kinds
rule.Validation.CEL = cel
return rule
}
if rule.HasValidateAssert() {
rule.Validation.Assert = createAutogenAssertion(*rule.Validation.Assert.DeepCopy(), tplKey)
return rule
}
return nil
}

View file

@ -0,0 +1,8 @@
## Description
The policy should contain autogen rules for cronjobs and deployments because it has the `pod-policies.kyverno.io/autogen-controllers: Deployment,CronJob` annotation.
## Expected Behavior
The policy gets created and contains a autogen rules for cronjobs and deployments in the status.

View file

@ -0,0 +1,13 @@
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: assert-autogen
spec:
steps:
- name: step-01
try:
- apply:
file: policy.yaml
- assert:
file: policy-assert.yaml

View file

@ -0,0 +1,56 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-default-sa
spec:
validationFailureAction: Audit
rules:
- match:
any:
- resources:
kinds:
- Pod
name: disallow-default-sa
validate:
message: default ServiceAccount should not be used
assert:
object:
spec:
(serviceAccountName == 'default'): false
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready
autogen:
rules:
- match:
any:
- resources:
kinds:
- Deployment
name: autogen-disallow-default-sa
validate:
message: default ServiceAccount should not be used
assert:
object:
spec:
template:
spec:
(serviceAccountName == 'default'): false
- match:
any:
- resources:
kinds:
- CronJob
name: autogen-cronjob-disallow-default-sa
validate:
message: default ServiceAccount should not be used
assert:
object:
spec:
jobTemplate:
spec:
template:
spec:
(serviceAccountName == 'default'): false

View file

@ -0,0 +1,21 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-default-sa
annotations:
pod-policies.kyverno.io/autogen-controllers: Deployment,CronJob
spec:
validationFailureAction: Audit
rules:
- match:
any:
- resources:
kinds:
- Pod
name: disallow-default-sa
validate:
message: default ServiceAccount should not be used
assert:
object:
spec:
(serviceAccountName == 'default'): false