diff --git a/cmd/cli/kubectl-kyverno/processor/policy_processor.go b/cmd/cli/kubectl-kyverno/processor/policy_processor.go index cf693d8004..5800faefaf 100644 --- a/cmd/cli/kubectl-kyverno/processor/policy_processor.go +++ b/cmd/cli/kubectl-kyverno/processor/policy_processor.go @@ -98,6 +98,9 @@ func (p *PolicyProcessor) ApplyPoliciesOnResource() ([]engineapi.EngineResponse, var responses []engineapi.EngineResponse // mutate for _, policy := range p.Policies { + if !policyHasMutate(policy) { + continue + } policyContext, err := p.makePolicyContext(jp, cfg, resource, policy, namespaceLabels, gvk, subresource) if err != nil { return responses, err @@ -112,6 +115,9 @@ func (p *PolicyProcessor) ApplyPoliciesOnResource() ([]engineapi.EngineResponse, } // verify images for _, policy := range p.Policies { + if !policyHasVerifyImages(policy) { + continue + } policyContext, err := p.makePolicyContext(jp, cfg, resource, policy, namespaceLabels, gvk, subresource) if err != nil { return responses, err @@ -151,6 +157,9 @@ func (p *PolicyProcessor) ApplyPoliciesOnResource() ([]engineapi.EngineResponse, } // validate for _, policy := range p.Policies { + if !policyHasValidateOrVerifyImageChecks(policy) { + continue + } policyContext, err := p.makePolicyContext(jp, cfg, resource, policy, namespaceLabels, gvk, subresource) if err != nil { return responses, err @@ -230,6 +239,12 @@ func (p *PolicyProcessor) makePolicyContext( return nil, fmt.Errorf("failed to update old resource in json context (%w)", err) } } + if operation == kyvernov1.Delete { + policyContext = policyContext.WithOldResource(resource) + if err := policyContext.JSONContext().AddOldResource(resource.Object); err != nil { + return nil, fmt.Errorf("failed to update old resource in json context (%w)", err) + } + } policyContext = policyContext. WithPolicy(policy). WithNamespaceLabels(namespaceLabels). diff --git a/cmd/cli/kubectl-kyverno/processor/utils.go b/cmd/cli/kubectl-kyverno/processor/utils.go index d083ecf1c2..7693d5083b 100644 --- a/cmd/cli/kubectl-kyverno/processor/utils.go +++ b/cmd/cli/kubectl-kyverno/processor/utils.go @@ -12,3 +12,31 @@ func policyHasGenerate(policy kyvernov1.PolicyInterface) bool { } return false } + +func policyHasMutate(policy kyvernov1.PolicyInterface) bool { + for _, rule := range policy.GetSpec().Rules { + if rule.HasMutate() { + return true + } + } + return false +} + +func policyHasValidateOrVerifyImageChecks(policy kyvernov1.PolicyInterface) bool { + for _, rule := range policy.GetSpec().Rules { + // engine.validate handles both validate and verifyImageChecks atm + if rule.HasValidate() || rule.HasVerifyImageChecks() { + return true + } + } + return false +} + +func policyHasVerifyImages(policy kyvernov1.PolicyInterface) bool { + for _, rule := range policy.GetSpec().Rules { + if rule.HasVerifyImages() { + return true + } + } + return false +} diff --git a/pkg/engine/policycontext/policy_context.go b/pkg/engine/policycontext/policy_context.go index 7986294cfb..9282f9d673 100644 --- a/pkg/engine/policycontext/policy_context.go +++ b/pkg/engine/policycontext/policy_context.go @@ -193,8 +193,14 @@ func NewPolicyContext( configuration config.Configuration, ) (*PolicyContext, error) { enginectx := enginectx.NewContext(jp) - if err := enginectx.AddResource(resource.Object); err != nil { - return nil, err + if operation != kyvernov1.Delete { + if err := enginectx.AddResource(resource.Object); err != nil { + return nil, err + } + } else { + if err := enginectx.AddOldResource(resource.Object); err != nil { + return nil, err + } } if err := enginectx.AddNamespace(resource.GetNamespace()); err != nil { return nil, err diff --git a/test/cli/test/deny-pod-delete-match-opn-block/README.md b/test/cli/test/deny-pod-delete-match-opn-block/README.md new file mode 100644 index 0000000000..3b6c6e2745 --- /dev/null +++ b/test/cli/test/deny-pod-delete-match-opn-block/README.md @@ -0,0 +1,11 @@ +## Description + +This test checks to ensure that a pod cannot be deleted when the operation is specified in the match block. + +## Expected Behavior + +If the downstream resource is deleted, the test fails. If it remains, the test passes. + +## Reference Issue(s) + +https://github.com/kyverno/kyverno/issues/8644 diff --git a/test/cli/test/deny-pod-delete-match-opn-block/deny-pod-delete-match-opn-block.yaml b/test/cli/test/deny-pod-delete-match-opn-block/deny-pod-delete-match-opn-block.yaml new file mode 100644 index 0000000000..8a228bc3a6 --- /dev/null +++ b/test/cli/test/deny-pod-delete-match-opn-block/deny-pod-delete-match-opn-block.yaml @@ -0,0 +1,20 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: deny-pod-delete-match-opn-block +spec: + validationFailureAction: Enforce + background: false + rules: + - name: deny-pod-delete-match-opn-block + match: + any: + - resources: + kinds: + - Pod + operations: + - DELETE + validate: + message: Pod cannot be deleted + deny: {} + diff --git a/test/cli/test/deny-pod-delete-match-opn-block/kyverno-test.yaml b/test/cli/test/deny-pod-delete-match-opn-block/kyverno-test.yaml new file mode 100644 index 0000000000..865332e4b3 --- /dev/null +++ b/test/cli/test/deny-pod-delete-match-opn-block/kyverno-test.yaml @@ -0,0 +1,16 @@ +apiVersion: cli.kyverno.io/v1alpha1 +kind: Test +metadata: + name: deny-pod-delete-match-opn-block-test +policies: +- deny-pod-delete-match-opn-block.yaml +resources: +- resources.yaml +results: +- kind: Pod + policy: deny-pod-delete-match-opn-block + resources: + - test-delete + result: fail + rule: deny-pod-delete-match-opn-block +variables: values.yaml diff --git a/test/cli/test/deny-pod-delete-match-opn-block/resources.yaml b/test/cli/test/deny-pod-delete-match-opn-block/resources.yaml new file mode 100644 index 0000000000..c1756c55f5 --- /dev/null +++ b/test/cli/test/deny-pod-delete-match-opn-block/resources.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Pod +metadata: + name: test-delete +spec: + containers: + - name: busybox + image: busybox:1.28 + + diff --git a/test/cli/test/deny-pod-delete-match-opn-block/values.yaml b/test/cli/test/deny-pod-delete-match-opn-block/values.yaml new file mode 100644 index 0000000000..789de42cf3 --- /dev/null +++ b/test/cli/test/deny-pod-delete-match-opn-block/values.yaml @@ -0,0 +1,9 @@ +apiVersion: cli.kyverno.io/v1alpha1 +kind: Values +policies: +- name: deny-pod-delete-match-opn-block + resources: + - name: test-delete + values: + request.operation: DELETE + diff --git a/test/cli/test/deny-pod-delete-validate-deny/README.md b/test/cli/test/deny-pod-delete-validate-deny/README.md new file mode 100644 index 0000000000..4b2e943211 --- /dev/null +++ b/test/cli/test/deny-pod-delete-validate-deny/README.md @@ -0,0 +1,11 @@ +## Description + +This test checks to ensure that a pod cannot be deleted, but can be created or updated. The test ensures that deletion operations can be specified in `validate.deny` expressions and not just `operations[]` under a `match` block. + +## Expected Behavior + +If the downstream resource is deleted, the test fails. If it remains, the test passes. + +## Reference Issue(s) + +https://github.com/kyverno/kyverno/issues/8644 diff --git a/test/cli/test/deny-pod-delete-validate-deny/deny-pod-delete-validate-deny.yaml b/test/cli/test/deny-pod-delete-validate-deny/deny-pod-delete-validate-deny.yaml new file mode 100644 index 0000000000..f532c01347 --- /dev/null +++ b/test/cli/test/deny-pod-delete-validate-deny/deny-pod-delete-validate-deny.yaml @@ -0,0 +1,22 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: deny-pod-delete-validate-deny +spec: + validationFailureAction: Enforce + background: false + rules: + - name: deny-pod-delete-validate-deny + match: + any: + - resources: + kinds: + - Pod + validate: + message: Pod cannot be deleted + deny: + conditions: + any: + - key: "{{request.operation}}" + operator: Equals + value: DELETE diff --git a/test/cli/test/deny-pod-delete-validate-deny/kyverno-test.yaml b/test/cli/test/deny-pod-delete-validate-deny/kyverno-test.yaml new file mode 100644 index 0000000000..7fe1acbdd3 --- /dev/null +++ b/test/cli/test/deny-pod-delete-validate-deny/kyverno-test.yaml @@ -0,0 +1,23 @@ +apiVersion: cli.kyverno.io/v1alpha1 +kind: Test +metadata: + name: deny-pod-delete-validate-deny-test +policies: +- deny-pod-delete-validate-deny.yaml +resources: +- resources.yaml +results: +- kind: Pod + policy: deny-pod-delete-validate-deny + resources: + - test-pod-delete + result: fail + rule: deny-pod-delete-validate-deny +- kind: Pod + policy: deny-pod-delete-validate-deny + resources: + - test-pod-create + - test-pod-update + result: pass + rule: deny-pod-delete-validate-deny +variables: values.yaml diff --git a/test/cli/test/deny-pod-delete-validate-deny/resources.yaml b/test/cli/test/deny-pod-delete-validate-deny/resources.yaml new file mode 100644 index 0000000000..ca2a27e5f5 --- /dev/null +++ b/test/cli/test/deny-pod-delete-validate-deny/resources.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Pod +metadata: + name: test-pod-delete +spec: + containers: + - name: container1 + image: dummyimagename +--- +apiVersion: v1 +kind: Pod +metadata: + name: test-pod-create +spec: + containers: + - name: container2 + image: dummyimagename +--- +apiVersion: v1 +kind: Pod +metadata: + name: test-pod-update +spec: + containers: + - name: container3 + image: dummyimagename diff --git a/test/cli/test/deny-pod-delete-validate-deny/values.yaml b/test/cli/test/deny-pod-delete-validate-deny/values.yaml new file mode 100644 index 0000000000..5d42f8c46f --- /dev/null +++ b/test/cli/test/deny-pod-delete-validate-deny/values.yaml @@ -0,0 +1,11 @@ +apiVersion: cli.kyverno.io/v1alpha1 +kind: Values +policies: +- name: deny-pod-delete-validate-deny + resources: + - name: test-pod-delete + values: + request.operation: DELETE + - name: test-pod-update + values: + request.operation: UPDATE