From 5f0d53fe34824f522d241636b44a86302ceae97b Mon Sep 17 00:00:00 2001 From: shuting Date: Fri, 2 Feb 2024 16:32:28 +0800 Subject: [PATCH] feat: apply `.matchConditions` when generating reports (#9599) * enable matchconditions for reports Signed-off-by: ShutingZhao * update Signed-off-by: ShutingZhao * add chainsaw tests Signed-off-by: ShutingZhao * fix: linter issues Signed-off-by: ShutingZhao * chore: move files Signed-off-by: ShutingZhao --------- Signed-off-by: ShutingZhao --- pkg/engine/engine.go | 10 ++-- .../handlers/validation/validate_cel.go | 3 +- pkg/engine/internal/match.go | 46 ++++++++++++++++++- pkg/utils/cel/cel.go | 5 +- pkg/validatingadmissionpolicy/utils.go | 9 ++++ .../validatingadmissionpolicy.go | 3 +- .../match-conditions-standard/README.md | 12 +++++ .../chainsaw-test.yaml | 33 +++++++++++++ .../match-conditions-standard/ns.yaml | 4 ++ .../match-conditions-standard/pod.yaml | 18 ++++++++ .../policy-assert.yaml | 9 ++++ .../match-conditions-standard/policy.yaml | 40 ++++++++++++++++ .../report-assert.yaml | 18 ++++++++ .../report-error.yaml | 18 ++++++++ .../match-conditions-userinfo/README.md | 12 +++++ .../chainsaw-test.yaml | 33 +++++++++++++ .../match-conditions-userinfo/ns.yaml | 4 ++ .../match-conditions-userinfo/pod.yaml | 18 ++++++++ .../policy-assert.yaml | 9 ++++ .../match-conditions-userinfo/policy.yaml | 42 +++++++++++++++++ .../report-error-1.yaml | 18 ++++++++ .../report-error-2.yaml | 18 ++++++++ 22 files changed, 372 insertions(+), 10 deletions(-) create mode 100644 test/conformance/chainsaw/webhook-configurations/match-conditions-standard/README.md create mode 100755 test/conformance/chainsaw/webhook-configurations/match-conditions-standard/chainsaw-test.yaml create mode 100644 test/conformance/chainsaw/webhook-configurations/match-conditions-standard/ns.yaml create mode 100644 test/conformance/chainsaw/webhook-configurations/match-conditions-standard/pod.yaml create mode 100644 test/conformance/chainsaw/webhook-configurations/match-conditions-standard/policy-assert.yaml create mode 100644 test/conformance/chainsaw/webhook-configurations/match-conditions-standard/policy.yaml create mode 100644 test/conformance/chainsaw/webhook-configurations/match-conditions-standard/report-assert.yaml create mode 100644 test/conformance/chainsaw/webhook-configurations/match-conditions-standard/report-error.yaml create mode 100644 test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/README.md create mode 100755 test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/chainsaw-test.yaml create mode 100644 test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/ns.yaml create mode 100644 test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/pod.yaml create mode 100644 test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/policy-assert.yaml create mode 100644 test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/policy.yaml create mode 100644 test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/report-error-1.yaml create mode 100644 test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/report-error-2.yaml diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 16734c653a..8b16028f14 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -91,7 +91,7 @@ func (e *engine) Validate( startTime := time.Now() response := engineapi.NewEngineResponseFromPolicyContext(policyContext) logger := internal.LoggerWithPolicyContext(logging.WithName("engine.validate"), policyContext) - if internal.MatchPolicyContext(logger, policyContext, e.configuration) { + if internal.MatchPolicyContext(logger, e.client, policyContext, e.configuration) { policyResponse := e.validate(ctx, logger, policyContext) response = response.WithPolicyResponse(policyResponse) } @@ -107,7 +107,7 @@ func (e *engine) Mutate( startTime := time.Now() response := engineapi.NewEngineResponseFromPolicyContext(policyContext) logger := internal.LoggerWithPolicyContext(logging.WithName("engine.mutate"), policyContext) - if internal.MatchPolicyContext(logger, policyContext, e.configuration) { + if internal.MatchPolicyContext(logger, e.client, policyContext, e.configuration) { policyResponse, patchedResource := e.mutate(ctx, logger, policyContext) response = response. WithPolicyResponse(policyResponse). @@ -125,7 +125,7 @@ func (e *engine) Generate( startTime := time.Now() response := engineapi.NewEngineResponseFromPolicyContext(policyContext) logger := internal.LoggerWithPolicyContext(logging.WithName("engine.generate"), policyContext) - if internal.MatchPolicyContext(logger, policyContext, e.configuration) { + if internal.MatchPolicyContext(logger, e.client, policyContext, e.configuration) { policyResponse := e.generateResponse(ctx, logger, policyContext) response = response.WithPolicyResponse(policyResponse) } @@ -142,7 +142,7 @@ func (e *engine) VerifyAndPatchImages( response := engineapi.NewEngineResponseFromPolicyContext(policyContext) ivm := engineapi.ImageVerificationMetadata{} logger := internal.LoggerWithPolicyContext(logging.WithName("engine.verify"), policyContext) - if internal.MatchPolicyContext(logger, policyContext, e.configuration) { + if internal.MatchPolicyContext(logger, e.client, policyContext, e.configuration) { policyResponse, patchedResource, innerIvm := e.verifyAndPatchImages(ctx, logger, policyContext) response, ivm = response. WithPolicyResponse(policyResponse). @@ -160,7 +160,7 @@ func (e *engine) ApplyBackgroundChecks( startTime := time.Now() response := engineapi.NewEngineResponseFromPolicyContext(policyContext) logger := internal.LoggerWithPolicyContext(logging.WithName("engine.background"), policyContext) - if internal.MatchPolicyContext(logger, policyContext, e.configuration) { + if internal.MatchPolicyContext(logger, e.client, policyContext, e.configuration) { policyResponse := e.applyBackgroundChecks(ctx, logger, policyContext) response = response.WithPolicyResponse(policyResponse) } diff --git a/pkg/engine/handlers/validation/validate_cel.go b/pkg/engine/handlers/validation/validate_cel.go index 14b8ea4ddd..f6e4492def 100644 --- a/pkg/engine/handlers/validation/validate_cel.go +++ b/pkg/engine/handlers/validation/validate_cel.go @@ -12,6 +12,7 @@ import ( "github.com/kyverno/kyverno/pkg/engine/internal" engineutils "github.com/kyverno/kyverno/pkg/engine/utils" celutils "github.com/kyverno/kyverno/pkg/utils/cel" + vaputils "github.com/kyverno/kyverno/pkg/validatingadmissionpolicy" admissionregistrationv1alpha1 "k8s.io/api/admissionregistration/v1alpha1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -108,7 +109,7 @@ func (h validateCELHandler) Process( optionalVars := cel.OptionalVariableDeclarations{HasParams: hasParam, HasAuthorizer: true} expressionOptionalVars := cel.OptionalVariableDeclarations{HasParams: hasParam, HasAuthorizer: false} // compile CEL expressions - compiler, err := celutils.NewCompiler(validations, auditAnnotations, matchConditions, variables) + compiler, err := celutils.NewCompiler(validations, auditAnnotations, vaputils.ConvertMatchConditionsV1(matchConditions), variables) if err != nil { return resource, handlers.WithError(rule, engineapi.Validation, "Error while creating composited compiler", err) } diff --git a/pkg/engine/internal/match.go b/pkg/engine/internal/match.go index 3de8df54af..c11c631956 100644 --- a/pkg/engine/internal/match.go +++ b/pkg/engine/internal/match.go @@ -1,15 +1,22 @@ package internal import ( + "context" + "github.com/go-logr/logr" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" "github.com/kyverno/kyverno/pkg/config" engineapi "github.com/kyverno/kyverno/pkg/engine/api" + celutils "github.com/kyverno/kyverno/pkg/utils/cel" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/admission" + "k8s.io/apiserver/pkg/admission/plugin/cel" + "k8s.io/apiserver/pkg/admission/plugin/webhook/matchconditions" ) -func MatchPolicyContext(logger logr.Logger, policyContext engineapi.PolicyContext, configuration config.Configuration) bool { +func MatchPolicyContext(logger logr.Logger, client engineapi.Client, policyContext engineapi.PolicyContext, configuration config.Configuration) bool { policy := policyContext.Policy() old := policyContext.OldResource() new := policyContext.NewResource() @@ -22,6 +29,13 @@ func MatchPolicyContext(logger logr.Logger, policyContext engineapi.PolicyContex logger.V(2).Info("configuration resource filters doesn't match resource") return false } + + if policy.GetSpec().GetMatchConditions() != nil { + if !checkMatchConditions(logger, client, policyContext, gvk, subresource) { + logger.V(2).Info("webhookConfiguration.matchConditions doesn't match request") + return false + } + } return true } @@ -51,3 +65,33 @@ func checkNamespacedPolicy(policy kyvernov1.PolicyInterface, resources ...unstru } return true } + +func checkMatchConditions(logger logr.Logger, client engineapi.Client, policyContext engineapi.PolicyContext, gvk schema.GroupVersionKind, subresource string) bool { + policy := policyContext.Policy() + old := policyContext.OldResource() + new := policyContext.NewResource() + new.SetGroupVersionKind(gvk) + old.SetGroupVersionKind(gvk) + gvr := schema.GroupVersionResource(policyContext.RequestResource()) + requestInfo := policyContext.AdmissionInfo().AdmissionUserInfo + userInfo := NewUser(requestInfo.Username, requestInfo.UID, requestInfo.Groups) + admissionAttributes := admission.NewAttributesRecord(new.DeepCopyObject(), old.DeepCopyObject(), gvk, new.GetNamespace(), new.GetName(), gvr, subresource, admission.Operation(policyContext.Operation()), nil, false, &userInfo) + scheme := runtime.NewScheme() + scheme.AddKnownTypes(gvk.GroupVersion()) + versionedAttr, err := admission.NewVersionedAttributes(admissionAttributes, admissionAttributes.GetKind(), admission.NewObjectInterfacesFromScheme(scheme)) + if err != nil { + logger.Error(err, "error creating versioned attributes") + return false + } + + optionalVars := cel.OptionalVariableDeclarations{HasParams: false, HasAuthorizer: false} + compiler, err := celutils.NewCompiler(nil, nil, policy.GetSpec().GetMatchConditions(), nil) + if err != nil { + logger.Error(err, "error creating composited compiler") + return false + } + matchConditionFilter := compiler.CompileMatchExpressions(optionalVars) + matcher := matchconditions.NewMatcher(matchConditionFilter, nil, policy.GetKind(), "", policy.GetName()) + result := matcher.Match(context.TODO(), versionedAttr, nil, nil) + return result.Matches +} diff --git a/pkg/utils/cel/cel.go b/pkg/utils/cel/cel.go index d399a84693..5950654e92 100644 --- a/pkg/utils/cel/cel.go +++ b/pkg/utils/cel/cel.go @@ -1,6 +1,7 @@ package cel import ( + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" admissionregistrationv1alpha1 "k8s.io/api/admissionregistration/v1alpha1" "k8s.io/apiserver/pkg/admission/plugin/cel" "k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy" @@ -13,14 +14,14 @@ type Compiler struct { // CEL expressions validateExpressions []admissionregistrationv1alpha1.Validation auditAnnotationExpressions []admissionregistrationv1alpha1.AuditAnnotation - matchExpressions []admissionregistrationv1alpha1.MatchCondition + matchExpressions []admissionregistrationv1.MatchCondition variables []admissionregistrationv1alpha1.Variable } func NewCompiler( validations []admissionregistrationv1alpha1.Validation, auditAnnotations []admissionregistrationv1alpha1.AuditAnnotation, - matchConditions []admissionregistrationv1alpha1.MatchCondition, + matchConditions []admissionregistrationv1.MatchCondition, variables []admissionregistrationv1alpha1.Variable, ) (*Compiler, error) { compositedCompiler, err := cel.NewCompositedCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion())) diff --git a/pkg/validatingadmissionpolicy/utils.go b/pkg/validatingadmissionpolicy/utils.go index ac14f11f65..a7afff160b 100644 --- a/pkg/validatingadmissionpolicy/utils.go +++ b/pkg/validatingadmissionpolicy/utils.go @@ -1,6 +1,7 @@ package validatingadmissionpolicy import ( + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" "k8s.io/api/admissionregistration/v1alpha1" "k8s.io/api/admissionregistration/v1beta1" ) @@ -37,6 +38,14 @@ func convertMatchConditions(v1alpha1conditions []v1alpha1.MatchCondition) []v1be return v1beta1conditions } +func ConvertMatchConditionsV1(v1alpha1conditions []v1alpha1.MatchCondition) []admissionregistrationv1.MatchCondition { + var v1conditions []admissionregistrationv1.MatchCondition + for _, m := range v1alpha1conditions { + v1conditions = append(v1conditions, admissionregistrationv1.MatchCondition(m)) + } + return v1conditions +} + func convertVariables(v1alpha1variables []v1alpha1.Variable) []v1beta1.Variable { var v1beta1variables []v1beta1.Variable for _, v := range v1alpha1variables { diff --git a/pkg/validatingadmissionpolicy/validatingadmissionpolicy.go b/pkg/validatingadmissionpolicy/validatingadmissionpolicy.go index 5b66737206..fe8065880a 100644 --- a/pkg/validatingadmissionpolicy/validatingadmissionpolicy.go +++ b/pkg/validatingadmissionpolicy/validatingadmissionpolicy.go @@ -202,7 +202,8 @@ func validateResource(policy v1alpha1.ValidatingAdmissionPolicy, binding *v1alph var ruleResp *engineapi.RuleResponse // compile CEL expressions - compiler, err := celutils.NewCompiler(policy.Spec.Validations, policy.Spec.AuditAnnotations, policy.Spec.MatchConditions, policy.Spec.Variables) + matchConditions := ConvertMatchConditionsV1(policy.Spec.MatchConditions) + compiler, err := celutils.NewCompiler(policy.Spec.Validations, policy.Spec.AuditAnnotations, matchConditions, policy.Spec.Variables) if err != nil { return engineResponse, err } diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/README.md b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/README.md new file mode 100644 index 0000000000..a7b09ddaed --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/README.md @@ -0,0 +1,12 @@ +## Description + +This test creates a policy with `matchConditions` and two pods, it then expects a background scan report to be created for the pod in the selected namespace `match-conditions-standard-ns` other than `default`. + +## Steps + +1. - Create the testing namespace `match-conditions-standard-ns` +1. - Create pods in `match-conditions-standard-ns` and `default` namespaces +1. - Create a cluster policy + - Assert the policy becomes ready +1. - Assert a policy report is created for the pod in `match-conditions-standard-ns` +1. - Assert a policy report is not created for the pod in `default` diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/chainsaw-test.yaml b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/chainsaw-test.yaml new file mode 100755 index 0000000000..8bc2bc82de --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/chainsaw-test.yaml @@ -0,0 +1,33 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + creationTimestamp: null + name: report-deletion +spec: + steps: + - name: step-00 + try: + - apply: + file: ns.yaml + - assert: + file: ns.yaml + - name: step-01 + try: + - apply: + file: pod.yaml + - assert: + file: pod.yaml + - name: step-02 + try: + - apply: + file: policy.yaml + - assert: + file: policy-assert.yaml + - name: step-03 + try: + - assert: + file: report-assert.yaml + - name: step-04 + try: + - error: + file: report-error.yaml diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/ns.yaml b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/ns.yaml new file mode 100644 index 0000000000..50e435799f --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/ns.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: match-conditions-standard-ns \ No newline at end of file diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/pod.yaml b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/pod.yaml new file mode 100644 index 0000000000..2c0164d5db --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/pod.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: pod-latest-tag +spec: + containers: + - image: nginx:latest + name: pod +--- +apiVersion: v1 +kind: Pod +metadata: + name: pod-latest-tag + namespace: match-conditions-standard-ns +spec: + containers: + - image: nginx:latest + name: pod \ No newline at end of file diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/policy-assert.yaml b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/policy-assert.yaml new file mode 100644 index 0000000000..6ac985a337 --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/policy-assert.yaml @@ -0,0 +1,9 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: cpol-match-conditions-standard +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/policy.yaml b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/policy.yaml new file mode 100644 index 0000000000..507f8e063a --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/policy.yaml @@ -0,0 +1,40 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + annotations: + pod-policies.kyverno.io/autogen-controllers: none + name: cpol-match-conditions-standard +spec: + admission: true + background: true + webhookConfiguration: + matchConditions: + - name: "select-namespace" + expression: '(object.metadata.namespace == "match-conditions-standard-ns")' + rules: + - match: + any: + - resources: + kinds: + - Pod + name: require-image-tag + validate: + message: An image tag is required + pattern: + spec: + containers: + - image: '*:*' + - match: + any: + - resources: + kinds: + - Pod + name: validate-image-tag + validate: + message: Using a mutable image tag e.g. 'latest' is not allowed + pattern: + spec: + containers: + - image: '!*:latest' + validationFailureAction: Enforce + failurePolicy: Ignore \ No newline at end of file diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/report-assert.yaml b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/report-assert.yaml new file mode 100644 index 0000000000..d01e6ade85 --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/report-assert.yaml @@ -0,0 +1,18 @@ +apiVersion: wgpolicyk8s.io/v1alpha2 +kind: PolicyReport +metadata: + namespace: match-conditions-standard-ns + ownerReferences: + - apiVersion: v1 + kind: Pod + name: pod-latest-tag +scope: + apiVersion: v1 + kind: Pod + name: pod-latest-tag +summary: + error: 0 + fail: 1 + pass: 1 + skip: 0 + warn: 0 diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/report-error.yaml b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/report-error.yaml new file mode 100644 index 0000000000..a7baea452c --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-standard/report-error.yaml @@ -0,0 +1,18 @@ +apiVersion: wgpolicyk8s.io/v1alpha2 +kind: PolicyReport +metadata: + namespace: default + ownerReferences: + - apiVersion: v1 + kind: Pod + name: pod-latest-tag +scope: + apiVersion: v1 + kind: Pod + name: pod-latest-tag +summary: + error: 0 + fail: 1 + pass: 1 + skip: 0 + warn: 0 diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/README.md b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/README.md new file mode 100644 index 0000000000..a7b09ddaed --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/README.md @@ -0,0 +1,12 @@ +## Description + +This test creates a policy with `matchConditions` and two pods, it then expects a background scan report to be created for the pod in the selected namespace `match-conditions-standard-ns` other than `default`. + +## Steps + +1. - Create the testing namespace `match-conditions-standard-ns` +1. - Create pods in `match-conditions-standard-ns` and `default` namespaces +1. - Create a cluster policy + - Assert the policy becomes ready +1. - Assert a policy report is created for the pod in `match-conditions-standard-ns` +1. - Assert a policy report is not created for the pod in `default` diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/chainsaw-test.yaml b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/chainsaw-test.yaml new file mode 100755 index 0000000000..04ac9d4ce5 --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/chainsaw-test.yaml @@ -0,0 +1,33 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + creationTimestamp: null + name: report-deletion +spec: + steps: + - name: step-00 + try: + - apply: + file: ns.yaml + - assert: + file: ns.yaml + - name: step-01 + try: + - apply: + file: pod.yaml + - assert: + file: pod.yaml + - name: step-02 + try: + - apply: + file: policy.yaml + - assert: + file: policy-assert.yaml + - name: step-03 + try: + - error: + file: report-error-1.yaml + - name: step-04 + try: + - error: + file: report-error-2.yaml diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/ns.yaml b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/ns.yaml new file mode 100644 index 0000000000..0df05d1fd4 --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/ns.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: match-conditions-userinfo-ns \ No newline at end of file diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/pod.yaml b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/pod.yaml new file mode 100644 index 0000000000..ecfc9e5574 --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/pod.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: pod-latest-tag +spec: + containers: + - image: nginx:latest + name: pod +--- +apiVersion: v1 +kind: Pod +metadata: + name: pod-latest-tag + namespace: match-conditions-userinfo-ns +spec: + containers: + - image: nginx:latest + name: pod \ No newline at end of file diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/policy-assert.yaml b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/policy-assert.yaml new file mode 100644 index 0000000000..51dd9a74bf --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/policy-assert.yaml @@ -0,0 +1,9 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: cpol-match-conditions-userinfo +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/policy.yaml b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/policy.yaml new file mode 100644 index 0000000000..d59f928dca --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/policy.yaml @@ -0,0 +1,42 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + annotations: + pod-policies.kyverno.io/autogen-controllers: none + name: cpol-match-conditions-userinfo +spec: + admission: true + background: true + webhookConfiguration: + matchConditions: + - name: "select-namespace" + expression: '(object.metadata.namespace == "match-conditions-userinfo-ns")' + - name: 'select-by-groups' + expression: '("system:masters" in request.userInfo.groups)' + rules: + - match: + any: + - resources: + kinds: + - Pod + name: require-image-tag + validate: + message: An image tag is required + pattern: + spec: + containers: + - image: '*:*' + - match: + any: + - resources: + kinds: + - Pod + name: validate-image-tag + validate: + message: Using a mutable image tag e.g. 'latest' is not allowed + pattern: + spec: + containers: + - image: '!*:latest' + validationFailureAction: Enforce + failurePolicy: Ignore \ No newline at end of file diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/report-error-1.yaml b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/report-error-1.yaml new file mode 100644 index 0000000000..4c3fdc0751 --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/report-error-1.yaml @@ -0,0 +1,18 @@ +apiVersion: wgpolicyk8s.io/v1alpha2 +kind: PolicyReport +metadata: + namespace: match-conditions-userinfo-ns + ownerReferences: + - apiVersion: v1 + kind: Pod + name: pod-latest-tag +scope: + apiVersion: v1 + kind: Pod + name: pod-latest-tag +summary: + error: 0 + fail: 1 + pass: 1 + skip: 0 + warn: 0 diff --git a/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/report-error-2.yaml b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/report-error-2.yaml new file mode 100644 index 0000000000..a7baea452c --- /dev/null +++ b/test/conformance/chainsaw/webhook-configurations/match-conditions-userinfo/report-error-2.yaml @@ -0,0 +1,18 @@ +apiVersion: wgpolicyk8s.io/v1alpha2 +kind: PolicyReport +metadata: + namespace: default + ownerReferences: + - apiVersion: v1 + kind: Pod + name: pod-latest-tag +scope: + apiVersion: v1 + kind: Pod + name: pod-latest-tag +summary: + error: 0 + fail: 1 + pass: 1 + skip: 0 + warn: 0