mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
fix mutate targets validation (#7387)
* fix mutate targets validation Signed-off-by: ShutingZhao <shuting@nirmata.com> * linter fixes Signed-off-by: ShutingZhao <shuting@nirmata.com> --------- Signed-off-by: ShutingZhao <shuting@nirmata.com>
This commit is contained in:
parent
cbce1c91b7
commit
4d5f832d01
7 changed files with 104 additions and 18 deletions
|
@ -405,22 +405,22 @@ func hasInvalidVariables(policy kyvernov1.PolicyInterface, background bool) erro
|
|||
}
|
||||
}
|
||||
|
||||
// skip variable checks on mutate.targets, they will be validated separately
|
||||
withoutTargets := ruleCopy.DeepCopy()
|
||||
for i := range withoutTargets.Mutation.Targets {
|
||||
withoutTargets.Mutation.Targets[i].RawAnyAllConditions = nil
|
||||
}
|
||||
ctx := buildContext(withoutTargets, background, false, nil)
|
||||
if _, err := variables.SubstituteAllInRule(logging.GlobalLogger(), ctx, *withoutTargets); !variables.CheckNotFoundErr(err) {
|
||||
return fmt.Errorf("variable substitution failed for rule %s: %s", withoutTargets.Name, err.Error())
|
||||
mutateTarget := false
|
||||
if ruleCopy.Mutation.Targets != nil {
|
||||
mutateTarget = true
|
||||
withTargetOnly := ruleWithoutPattern(ruleCopy)
|
||||
for i := range ruleCopy.Mutation.Targets {
|
||||
withTargetOnly.Mutation.Targets[i].ResourceSpec = ruleCopy.Mutation.Targets[i].ResourceSpec
|
||||
ctx := buildContext(withTargetOnly, background, false)
|
||||
if _, err := variables.SubstituteAllInRule(logging.GlobalLogger(), ctx, *withTargetOnly); !variables.CheckNotFoundErr(err) {
|
||||
return fmt.Errorf("invalid variables defined at mutate.targets[%d]: %s", i, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// perform variable checks with mutate.targets
|
||||
for _, target := range r.Mutation.Targets {
|
||||
ctx := buildContext(ruleCopy, background, true, target.Context)
|
||||
if _, err := variables.SubstituteAllInRule(logging.GlobalLogger(), ctx, *ruleCopy); !variables.CheckNotFoundErr(err) {
|
||||
return fmt.Errorf("variable substitution failed for rule target %s: %s", ruleCopy.Name, err.Error())
|
||||
}
|
||||
ctx := buildContext(ruleCopy, background, mutateTarget)
|
||||
if _, err := variables.SubstituteAllInRule(logging.GlobalLogger(), ctx, *ruleCopy); !variables.CheckNotFoundErr(err) {
|
||||
return fmt.Errorf("variable substitution failed for rule %s: %s", ruleCopy.Name, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -555,7 +555,15 @@ func imageRefHasVariables(verifyImages []kyvernov1.ImageVerification) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func buildContext(rule *kyvernov1.Rule, background bool, target bool, targetContext []kyvernov1.ContextEntry) *enginecontext.MockContext {
|
||||
func ruleWithoutPattern(ruleCopy *kyvernov1.Rule) *kyvernov1.Rule {
|
||||
withTargetOnly := new(kyvernov1.Rule)
|
||||
withTargetOnly.Mutation.Targets = make([]kyvernov1.TargetResourceSpec, len(ruleCopy.Mutation.Targets))
|
||||
withTargetOnly.Context = ruleCopy.Context
|
||||
withTargetOnly.RawAnyAllConditions = ruleCopy.RawAnyAllConditions
|
||||
return withTargetOnly
|
||||
}
|
||||
|
||||
func buildContext(rule *kyvernov1.Rule, background bool, target bool) *enginecontext.MockContext {
|
||||
re := getAllowedVariables(background, target)
|
||||
ctx := enginecontext.NewMockContext(re)
|
||||
addContextVariables(rule.Context, ctx)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: policy-bad.yaml
|
||||
shouldFail: true
|
||||
- file: policy-good.yaml
|
||||
shouldFail: false
|
|
@ -0,0 +1,12 @@
|
|||
## Description
|
||||
|
||||
This test ensures the variable `target` is allowed in a mutateExisting rule, except resource's spec definition under `mutate.targets`.
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
The good policy should be allowed to create while the bad policy that contains `target.metadata.annotations.dns` cannot be created as it's invalid.
|
||||
|
||||
|
||||
## Reference Issue(s)
|
||||
|
||||
https://github.com/kyverno/kyverno/issues/7379
|
|
@ -0,0 +1,29 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: target-variable-validation-cpol
|
||||
spec:
|
||||
mutateExistingOnPolicyUpdate: true
|
||||
schemaValidation: false
|
||||
background: true
|
||||
rules:
|
||||
- name: target-variable-validation-rule
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Secret
|
||||
mutate:
|
||||
targets:
|
||||
- apiVersion: v1
|
||||
kind: ConfigMap
|
||||
name: server-external
|
||||
namespace: "{{target.metadata.annotations.dns}}"
|
||||
- apiVersion: v1
|
||||
kind: ConfigMap
|
||||
name: server-internal
|
||||
namespace: external-dns
|
||||
patchesJson6902: |-
|
||||
- op: replace
|
||||
path: "/spec/endpoints/1/targets/0"
|
||||
value: "{{ request.object.data.prefix6 }}{{ target.metadata.annotations.dns_suffix }}"
|
|
@ -0,0 +1,30 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: target-variable-validation-cpol
|
||||
spec:
|
||||
mutateExistingOnPolicyUpdate: true
|
||||
schemaValidation: false
|
||||
background: true
|
||||
rules:
|
||||
- name: target-variable-validation-rule
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Secret
|
||||
mutate:
|
||||
targets:
|
||||
- apiVersion: v1
|
||||
kind: ConfigMap
|
||||
name: server-external
|
||||
# namespace: "{{target.metadata.annotations.dns}}"
|
||||
namespace: external-dns
|
||||
- apiVersion: v1
|
||||
kind: ConfigMap
|
||||
name: server-internal
|
||||
namespace: external-dns
|
||||
patchesJson6902: |-
|
||||
- op: replace
|
||||
path: "/spec/endpoints/1/targets/0"
|
||||
value: "{{ request.object.data.prefix6 }}{{ target.metadata.annotations.dns_suffix }}"
|
|
@ -1,7 +1,7 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
# - file: policy-1.yaml
|
||||
# shouldFail: true
|
||||
- file: policy-1.yaml
|
||||
shouldFail: true
|
||||
- file: policy-2.yaml
|
||||
shouldFail: true
|
||||
|
|
|
@ -17,7 +17,7 @@ spec:
|
|||
jmesPath: request.object.data.content
|
||||
- name: targetContent
|
||||
variable:
|
||||
jmesPath: target.data.content
|
||||
jmesPath: "{{target.data.content}}"
|
||||
preconditions:
|
||||
all:
|
||||
- key: "{{ request.object.metadata.name }}"
|
||||
|
|
Loading…
Reference in a new issue