mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
fix: allow changes to preexisting resources that violate a validate foreach, cel or pss policy (#10033)
* feat: allow changes to preexisting resources that violate a validate foreach, cel or pss policy Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: do old object verification as create operation this fixes the case where we are checking request.operation in a deny condition Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: update the json context in set operation Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: typo Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: update error message Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: add match and exclude check Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: match exclude in if Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * feat: add option to disable validation of old object Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: tests Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: unit tests Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * feat: chainsaw tests Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: update readme Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: conflicts Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: chainsaw tests Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: tests Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: ci Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: nil ptr error Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: linter Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: linter Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * feat: old obj verification in assert Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: codegen Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * feat: chainsaw tests Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * feat: chainsaw test for assert Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: cleanup Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: chainsaw tests Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: pss Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * feat: common functions for allow existing violations Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: types Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: typos Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: pss old resource Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * feat: chainsaw test for PSS Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: use old objects Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: more merge changes Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: e2e matrxix Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: refactor and dont return error when old obj validation fails Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: return resp when not matched Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * fix: add logs and return skip when old object validation fails Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * Update validate_resource.go Co-authored-by: shuting <shutting06@gmail.com> Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * Update validate_pss.go Co-authored-by: shuting <shutting06@gmail.com> Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> * Update validate_assert.go Co-authored-by: shuting <shutting06@gmail.com> Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> --------- Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com> Co-authored-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: shuting <shuting@nirmata.com> Co-authored-by: shuting <shutting06@gmail.com>
This commit is contained in:
parent
02e27ec3d4
commit
1ef9b876e1
72 changed files with 1269 additions and 81 deletions
|
@ -473,6 +473,11 @@ type Validation struct {
|
||||||
// +optional
|
// +optional
|
||||||
FailureActionOverrides []ValidationFailureActionOverride `json:"failureActionOverrides,omitempty"`
|
FailureActionOverrides []ValidationFailureActionOverride `json:"failureActionOverrides,omitempty"`
|
||||||
|
|
||||||
|
// AllowExistingViolations allows prexisting violating resources to continue violating a policy.
|
||||||
|
// +kubebuilder:validation:Optional
|
||||||
|
// +kubebuilder:default=true
|
||||||
|
AllowExistingViolations *bool `json:"allowExistingViolations,omitempty" yaml:"allowExistingViolations,omitempty"`
|
||||||
|
|
||||||
// Message specifies a custom message to be displayed on failure.
|
// Message specifies a custom message to be displayed on failure.
|
||||||
// +optional
|
// +optional
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
|
|
|
@ -187,6 +187,17 @@ func (r *Rule) HasValidate() bool {
|
||||||
return !datautils.DeepEqual(r.Validation, Validation{})
|
return !datautils.DeepEqual(r.Validation, Validation{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasValidateAllowExistingViolations() checks for allowExisitingViolations under validate rule
|
||||||
|
func (r *Rule) HasValidateAllowExistingViolations() bool {
|
||||||
|
var allowExisitingViolations bool
|
||||||
|
if r.Validation.AllowExistingViolations == nil {
|
||||||
|
allowExisitingViolations = true
|
||||||
|
} else {
|
||||||
|
allowExisitingViolations = *r.Validation.AllowExistingViolations
|
||||||
|
}
|
||||||
|
return allowExisitingViolations
|
||||||
|
}
|
||||||
|
|
||||||
// HasGenerate checks for generate rule
|
// HasGenerate checks for generate rule
|
||||||
func (r *Rule) HasGenerate() bool {
|
func (r *Rule) HasGenerate() bool {
|
||||||
return !datautils.DeepEqual(r.Generation, Generation{})
|
return !datautils.DeepEqual(r.Generation, Generation{})
|
||||||
|
|
|
@ -1698,6 +1698,11 @@ func (in *Validation) DeepCopyInto(out *Validation) {
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if in.AllowExistingViolations != nil {
|
||||||
|
in, out := &in.AllowExistingViolations, &out.AllowExistingViolations
|
||||||
|
*out = new(bool)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
if in.Manifests != nil {
|
if in.Manifests != nil {
|
||||||
in, out := &in.Manifests, &out.Manifests
|
in, out := &in.Manifests, &out.Manifests
|
||||||
*out = new(Manifests)
|
*out = new(Manifests)
|
||||||
|
|
|
@ -2888,6 +2888,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting violating
|
||||||
|
resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -7852,6 +7857,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -17553,6 +17563,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
|
|
@ -2889,6 +2889,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting violating
|
||||||
|
resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -7854,6 +7859,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -17556,6 +17566,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
|
|
@ -2882,6 +2882,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting violating
|
||||||
|
resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -7846,6 +7851,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -17547,6 +17557,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
|
|
@ -2883,6 +2883,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting violating
|
||||||
|
resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -7848,6 +7853,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -17550,6 +17560,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
|
|
@ -2882,6 +2882,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting violating
|
||||||
|
resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -7846,6 +7851,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -17547,6 +17557,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
|
|
@ -2883,6 +2883,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting violating
|
||||||
|
resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -7848,6 +7853,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -17550,6 +17560,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
|
|
@ -8205,6 +8205,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting violating
|
||||||
|
resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -13169,6 +13174,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -22870,6 +22880,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -28163,6 +28178,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting violating
|
||||||
|
resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -33128,6 +33148,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
@ -42830,6 +42855,11 @@ spec:
|
||||||
validate:
|
validate:
|
||||||
description: Validation is used to validate matching resources.
|
description: Validation is used to validate matching resources.
|
||||||
properties:
|
properties:
|
||||||
|
allowExistingViolations:
|
||||||
|
default: true
|
||||||
|
description: AllowExistingViolations allows prexisting
|
||||||
|
violating resources to continue violating a policy.
|
||||||
|
type: boolean
|
||||||
anyPattern:
|
anyPattern:
|
||||||
description: |-
|
description: |-
|
||||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||||
|
|
|
@ -4802,6 +4802,17 @@ namespace-wise. It overrides FailureAction for the specified namespaces.</p>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
|
<code>allowExistingViolations</code><br/>
|
||||||
|
<em>
|
||||||
|
bool
|
||||||
|
</em>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<p>AllowExistingViolations allows prexisting violating resources to continue violating a policy.</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
<code>message</code><br/>
|
<code>message</code><br/>
|
||||||
<em>
|
<em>
|
||||||
string
|
string
|
||||||
|
|
|
@ -9669,6 +9669,35 @@ namespace-wise. It overrides FailureAction for the specified namespaces.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><code>allowExistingViolations</code>
|
||||||
|
|
||||||
|
<span style="color:blue;"> *</span>
|
||||||
|
|
||||||
|
</br>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<span style="font-family: monospace">bool</span>
|
||||||
|
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
|
||||||
|
<p>AllowExistingViolations allows prexisting violating resources to continue violating a policy.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>message</code>
|
<td><code>message</code>
|
||||||
|
|
||||||
|
|
|
@ -27,17 +27,18 @@ import (
|
||||||
// ValidationApplyConfiguration represents an declarative configuration of the Validation type for use
|
// ValidationApplyConfiguration represents an declarative configuration of the Validation type for use
|
||||||
// with apply.
|
// with apply.
|
||||||
type ValidationApplyConfiguration struct {
|
type ValidationApplyConfiguration struct {
|
||||||
FailureAction *v1.ValidationFailureAction `json:"failureAction,omitempty"`
|
FailureAction *v1.ValidationFailureAction `json:"failureAction,omitempty"`
|
||||||
FailureActionOverrides []ValidationFailureActionOverrideApplyConfiguration `json:"failureActionOverrides,omitempty"`
|
FailureActionOverrides []ValidationFailureActionOverrideApplyConfiguration `json:"failureActionOverrides,omitempty"`
|
||||||
Message *string `json:"message,omitempty"`
|
AllowExistingViolations *bool `json:"allowExistingViolations,omitempty"`
|
||||||
Manifests *ManifestsApplyConfiguration `json:"manifests,omitempty"`
|
Message *string `json:"message,omitempty"`
|
||||||
ForEachValidation []ForEachValidationApplyConfiguration `json:"foreach,omitempty"`
|
Manifests *ManifestsApplyConfiguration `json:"manifests,omitempty"`
|
||||||
RawPattern *apiextensionsv1.JSON `json:"pattern,omitempty"`
|
ForEachValidation []ForEachValidationApplyConfiguration `json:"foreach,omitempty"`
|
||||||
RawAnyPattern *apiextensionsv1.JSON `json:"anyPattern,omitempty"`
|
RawPattern *apiextensionsv1.JSON `json:"pattern,omitempty"`
|
||||||
Deny *DenyApplyConfiguration `json:"deny,omitempty"`
|
RawAnyPattern *apiextensionsv1.JSON `json:"anyPattern,omitempty"`
|
||||||
PodSecurity *PodSecurityApplyConfiguration `json:"podSecurity,omitempty"`
|
Deny *DenyApplyConfiguration `json:"deny,omitempty"`
|
||||||
CEL *CELApplyConfiguration `json:"cel,omitempty"`
|
PodSecurity *PodSecurityApplyConfiguration `json:"podSecurity,omitempty"`
|
||||||
Assert *v1alpha1.Any `json:"assert,omitempty"`
|
CEL *CELApplyConfiguration `json:"cel,omitempty"`
|
||||||
|
Assert *v1alpha1.Any `json:"assert,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidationApplyConfiguration constructs an declarative configuration of the Validation type for use with
|
// ValidationApplyConfiguration constructs an declarative configuration of the Validation type for use with
|
||||||
|
@ -67,6 +68,14 @@ func (b *ValidationApplyConfiguration) WithFailureActionOverrides(values ...*Val
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithAllowExistingViolations sets the AllowExistingViolations field in the declarative configuration to the given value
|
||||||
|
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||||
|
// If called multiple times, the AllowExistingViolations field is set to the value of the last call.
|
||||||
|
func (b *ValidationApplyConfiguration) WithAllowExistingViolations(value bool) *ValidationApplyConfiguration {
|
||||||
|
b.AllowExistingViolations = &value
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
// WithMessage sets the Message field in the declarative configuration to the given value
|
// WithMessage sets the Message field in the declarative configuration to the given value
|
||||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||||
// If called multiple times, the Message field is set to the value of the last call.
|
// If called multiple times, the Message field is set to the value of the last call.
|
||||||
|
|
|
@ -19,6 +19,7 @@ type PolicyContext interface {
|
||||||
SetResources(oldResource, newResource unstructured.Unstructured) error
|
SetResources(oldResource, newResource unstructured.Unstructured) error
|
||||||
AdmissionInfo() kyvernov2.RequestInfo
|
AdmissionInfo() kyvernov2.RequestInfo
|
||||||
Operation() kyvernov1.AdmissionOperation
|
Operation() kyvernov1.AdmissionOperation
|
||||||
|
SetOperation(op kyvernov1.AdmissionOperation) error
|
||||||
NamespaceLabels() map[string]string
|
NamespaceLabels() map[string]string
|
||||||
RequestResource() metav1.GroupVersionResource
|
RequestResource() metav1.GroupVersionResource
|
||||||
ResourceKind() (schema.GroupVersionKind, string)
|
ResourceKind() (schema.GroupVersionKind, string)
|
||||||
|
|
46
pkg/engine/handlers/validation/utils.go
Normal file
46
pkg/engine/handlers/validation/utils.go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package validation
|
||||||
|
|
||||||
|
import (
|
||||||
|
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||||
|
kyvernov2 "github.com/kyverno/kyverno/api/kyverno/v2"
|
||||||
|
kyvernov2beta1 "github.com/kyverno/kyverno/api/kyverno/v2beta1"
|
||||||
|
"github.com/kyverno/kyverno/pkg/utils/match"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
)
|
||||||
|
|
||||||
|
func matchResource(resource unstructured.Unstructured, rule kyvernov1.Rule) bool {
|
||||||
|
if rule.MatchResources.All != nil || rule.MatchResources.Any != nil {
|
||||||
|
matched := match.CheckMatchesResources(
|
||||||
|
resource,
|
||||||
|
kyvernov2beta1.MatchResources{
|
||||||
|
Any: rule.MatchResources.Any,
|
||||||
|
All: rule.MatchResources.All,
|
||||||
|
},
|
||||||
|
make(map[string]string),
|
||||||
|
kyvernov2.RequestInfo{},
|
||||||
|
resource.GroupVersionKind(),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
if matched != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rule.ExcludeResources.All != nil || rule.ExcludeResources.Any != nil {
|
||||||
|
excluded := match.CheckMatchesResources(
|
||||||
|
resource,
|
||||||
|
kyvernov2beta1.MatchResources{
|
||||||
|
Any: rule.ExcludeResources.Any,
|
||||||
|
All: rule.ExcludeResources.All,
|
||||||
|
},
|
||||||
|
make(map[string]string),
|
||||||
|
kyvernov2.RequestInfo{},
|
||||||
|
resource.GroupVersionKind(),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
if excluded == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/kyverno/kyverno/pkg/engine/handlers"
|
"github.com/kyverno/kyverno/pkg/engine/handlers"
|
||||||
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
|
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -111,6 +112,20 @@ func (h validateAssertHandler) Process(
|
||||||
}
|
}
|
||||||
// compose a response
|
// compose a response
|
||||||
if len(errs) != 0 {
|
if len(errs) != 0 {
|
||||||
|
allowExisitingViolations := rule.HasValidateAllowExistingViolations()
|
||||||
|
if engineutils.IsUpdateRequest(policyContext) && allowExisitingViolations {
|
||||||
|
errs, err := validateOldObject(ctx, policyContext, rule, payload, bindings)
|
||||||
|
if err != nil {
|
||||||
|
logger.V(2).Info("warning: failed to validate old object, skipping the rule evaluation as pre-existing violations are allowed", "rule", rule.Name, "error", err.Error())
|
||||||
|
return resource, handlers.WithSkip(rule, engineapi.Validation, "failed to validate old object, skipping as preexisting violations are allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.V(3).Info("old object verification", "errors", errs)
|
||||||
|
if len(errs) != 0 {
|
||||||
|
logger.V(3).Info("skipping modified resource as validation results have not changed")
|
||||||
|
return resource, handlers.WithSkip(rule, engineapi.Validation, "skipping modified resource as validation results have not changed")
|
||||||
|
}
|
||||||
|
}
|
||||||
var responses []*engineapi.RuleResponse
|
var responses []*engineapi.RuleResponse
|
||||||
for _, err := range errs {
|
for _, err := range errs {
|
||||||
responses = append(responses, engineapi.RuleFail(rule.Name, engineapi.Validation, err.Error(), rule.ReportProperties))
|
responses = append(responses, engineapi.RuleFail(rule.Name, engineapi.Validation, err.Error(), rule.ReportProperties))
|
||||||
|
@ -122,3 +137,26 @@ func (h validateAssertHandler) Process(
|
||||||
engineapi.RulePass(rule.Name, engineapi.Validation, msg, rule.ReportProperties),
|
engineapi.RulePass(rule.Name, engineapi.Validation, msg, rule.ReportProperties),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateOldObject(ctx context.Context, policyContext engineapi.PolicyContext, rule kyvernov1.Rule, payload map[string]any, bindings binding.Bindings) (field.ErrorList, error) {
|
||||||
|
if policyContext.Operation() != kyvernov1.Update {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
oldResource := policyContext.OldResource()
|
||||||
|
|
||||||
|
if ok := matchResource(oldResource, rule); !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
payload["object"] = policyContext.OldResource().Object
|
||||||
|
payload["oldObject"] = nil
|
||||||
|
payload["operation"] = kyvernov1.Create
|
||||||
|
|
||||||
|
asserttion := assert.Parse(ctx, rule.Validation.Assert.Value)
|
||||||
|
errs, err := assert.Assert(ctx, nil, asserttion, payload, bindings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to apply assertion: %w", err)
|
||||||
|
}
|
||||||
|
return errs, nil
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/kyverno/kyverno/pkg/pss"
|
"github.com/kyverno/kyverno/pkg/pss"
|
||||||
pssutils "github.com/kyverno/kyverno/pkg/pss/utils"
|
pssutils "github.com/kyverno/kyverno/pkg/pss/utils"
|
||||||
"github.com/kyverno/kyverno/pkg/utils/api"
|
"github.com/kyverno/kyverno/pkg/utils/api"
|
||||||
|
"github.com/pkg/errors"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
batchv1 "k8s.io/api/batch/v1"
|
batchv1 "k8s.io/api/batch/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
@ -36,9 +37,22 @@ func (h validatePssHandler) Process(
|
||||||
policyContext engineapi.PolicyContext,
|
policyContext engineapi.PolicyContext,
|
||||||
resource unstructured.Unstructured,
|
resource unstructured.Unstructured,
|
||||||
rule kyvernov1.Rule,
|
rule kyvernov1.Rule,
|
||||||
_ engineapi.EngineContextLoader,
|
engineLoader engineapi.EngineContextLoader,
|
||||||
exceptions []*kyvernov2.PolicyException,
|
exceptions []*kyvernov2.PolicyException,
|
||||||
) (unstructured.Unstructured, []engineapi.RuleResponse) {
|
) (unstructured.Unstructured, []engineapi.RuleResponse) {
|
||||||
|
resource, ruleResp := h.validate(ctx, logger, policyContext, resource, rule, engineLoader, exceptions)
|
||||||
|
return resource, handlers.WithResponses(ruleResp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h validatePssHandler) validate(
|
||||||
|
ctx context.Context,
|
||||||
|
logger logr.Logger,
|
||||||
|
policyContext engineapi.PolicyContext,
|
||||||
|
resource unstructured.Unstructured,
|
||||||
|
rule kyvernov1.Rule,
|
||||||
|
engineLoader engineapi.EngineContextLoader,
|
||||||
|
exceptions []*kyvernov2.PolicyException,
|
||||||
|
) (unstructured.Unstructured, *engineapi.RuleResponse) {
|
||||||
if engineutils.IsDeleteRequest(policyContext) {
|
if engineutils.IsDeleteRequest(policyContext) {
|
||||||
logger.V(3).Info("skipping PSS validation on deleted resource")
|
logger.V(3).Info("skipping PSS validation on deleted resource")
|
||||||
return resource, nil
|
return resource, nil
|
||||||
|
@ -62,12 +76,10 @@ func (h validatePssHandler) Process(
|
||||||
key, err := cache.MetaNamespaceKeyFunc(&polex)
|
key, err := cache.MetaNamespaceKeyFunc(&polex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to compute policy exception key", "namespace", polex.GetNamespace(), "name", polex.GetName())
|
logger.Error(err, "failed to compute policy exception key", "namespace", polex.GetNamespace(), "name", polex.GetName())
|
||||||
return resource, handlers.WithError(rule, engineapi.Validation, "failed to compute exception key", err)
|
return resource, engineapi.RuleError(rule.Name, engineapi.Validation, "failed to compute exception key", err, rule.ReportProperties)
|
||||||
}
|
}
|
||||||
logger.V(3).Info("policy rule is skipped due to policy exception", "exception", key)
|
logger.V(3).Info("policy rule is skipped due to policy exception", "exception", key)
|
||||||
return resource, handlers.WithResponses(
|
return resource, engineapi.RuleSkip(rule.Name, engineapi.Validation, "rule is skipped due to policy exception "+key, rule.ReportProperties).WithExceptions([]kyvernov2.PolicyException{polex})
|
||||||
engineapi.RuleSkip(rule.Name, engineapi.Validation, "rule is skipped due to policy exception "+key, rule.ReportProperties).WithExceptions([]kyvernov2.PolicyException{polex}),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +90,7 @@ func (h validatePssHandler) Process(
|
||||||
}
|
}
|
||||||
podSpec, metadata, err := getSpec(resource)
|
podSpec, metadata, err := getSpec(resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resource, handlers.WithError(rule, engineapi.Validation, "Error while getting new resource", err)
|
return resource, engineapi.RuleError(rule.Name, engineapi.Validation, "Error while getting new resource", err, rule.ReportProperties)
|
||||||
}
|
}
|
||||||
pod := &corev1.Pod{
|
pod := &corev1.Pod{
|
||||||
Spec: *podSpec,
|
Spec: *podSpec,
|
||||||
|
@ -86,7 +98,7 @@ func (h validatePssHandler) Process(
|
||||||
}
|
}
|
||||||
levelVersion, err := pss.ParseVersion(podSecurity.Level, podSecurity.Version)
|
levelVersion, err := pss.ParseVersion(podSecurity.Level, podSecurity.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resource, handlers.WithError(rule, engineapi.Validation, "failed to parse pod security api version", err)
|
return resource, engineapi.RuleError(rule.Name, engineapi.Validation, "failed to parse pod security api version", err, rule.ReportProperties)
|
||||||
}
|
}
|
||||||
allowed, pssChecks := pss.EvaluatePod(levelVersion, podSecurity.Exclude, pod)
|
allowed, pssChecks := pss.EvaluatePod(levelVersion, podSecurity.Exclude, pod)
|
||||||
pssChecks = convertChecks(pssChecks, resource.GetKind())
|
pssChecks = convertChecks(pssChecks, resource.GetKind())
|
||||||
|
@ -98,9 +110,7 @@ func (h validatePssHandler) Process(
|
||||||
}
|
}
|
||||||
if allowed {
|
if allowed {
|
||||||
msg := fmt.Sprintf("Validation rule '%s' passed.", rule.Name)
|
msg := fmt.Sprintf("Validation rule '%s' passed.", rule.Name)
|
||||||
return resource, handlers.WithResponses(
|
return resource, engineapi.RulePass(rule.Name, engineapi.Validation, msg, rule.ReportProperties).WithPodSecurityChecks(podSecurityChecks)
|
||||||
engineapi.RulePass(rule.Name, engineapi.Validation, msg, rule.ReportProperties).WithPodSecurityChecks(podSecurityChecks),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
// apply pod security exceptions if exist
|
// apply pod security exceptions if exist
|
||||||
var excludes []kyvernov1.PodSecurityStandard
|
var excludes []kyvernov1.PodSecurityStandard
|
||||||
|
@ -109,7 +119,7 @@ func (h validatePssHandler) Process(
|
||||||
key, err := cache.MetaNamespaceKeyFunc(&matchedExceptions[i])
|
key, err := cache.MetaNamespaceKeyFunc(&matchedExceptions[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to compute policy exception key", "namespace", exception.GetNamespace(), "name", exception.GetName())
|
logger.Error(err, "failed to compute policy exception key", "namespace", exception.GetNamespace(), "name", exception.GetName())
|
||||||
return resource, handlers.WithError(rule, engineapi.Validation, "failed to compute exception key", err)
|
return resource, engineapi.RuleError(rule.Name, engineapi.Validation, "failed to compute exception key", err, rule.ReportProperties)
|
||||||
}
|
}
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
excludes = append(excludes, exception.Spec.PodSecurity...)
|
excludes = append(excludes, exception.Spec.PodSecurity...)
|
||||||
|
@ -119,17 +129,73 @@ func (h validatePssHandler) Process(
|
||||||
if len(pssChecks) == 0 && err == nil {
|
if len(pssChecks) == 0 && err == nil {
|
||||||
podSecurityChecks.Checks = pssChecks
|
podSecurityChecks.Checks = pssChecks
|
||||||
logger.V(3).Info("policy rule is skipped due to policy exceptions", "exceptions", keys)
|
logger.V(3).Info("policy rule is skipped due to policy exceptions", "exceptions", keys)
|
||||||
return resource, handlers.WithResponses(
|
return resource, engineapi.RuleSkip(rule.Name, engineapi.Validation, "rule is skipped due to policy exceptions "+strings.Join(keys, ", "), rule.ReportProperties).WithExceptions(matchedExceptions).WithPodSecurityChecks(podSecurityChecks)
|
||||||
engineapi.RuleSkip(rule.Name, engineapi.Validation, "rule is skipped due to policy exceptions "+strings.Join(keys, ", "), rule.ReportProperties).WithExceptions(matchedExceptions).WithPodSecurityChecks(podSecurityChecks),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
msg := fmt.Sprintf(`Validation rule '%s' failed. It violates PodSecurity "%s:%s": %s`, rule.Name, podSecurity.Level, podSecurity.Version, pss.FormatChecksPrint(pssChecks))
|
msg := fmt.Sprintf(`Validation rule '%s' failed. It violates PodSecurity "%s:%s": %s`, rule.Name, podSecurity.Level, podSecurity.Version, pss.FormatChecksPrint(pssChecks))
|
||||||
return resource, handlers.WithResponses(
|
ruleResponse := engineapi.RuleFail(rule.Name, engineapi.Validation, msg, rule.ReportProperties).WithPodSecurityChecks(podSecurityChecks)
|
||||||
engineapi.RuleFail(rule.Name, engineapi.Validation, msg, rule.ReportProperties).WithPodSecurityChecks(podSecurityChecks),
|
allowExisitingViolations := rule.HasValidateAllowExistingViolations()
|
||||||
)
|
if engineutils.IsUpdateRequest(policyContext) && allowExisitingViolations {
|
||||||
|
logger.V(4).Info("is update request")
|
||||||
|
priorResp, err := h.validateOldObject(ctx, logger, policyContext, resource, rule, engineLoader, exceptions)
|
||||||
|
if err != nil {
|
||||||
|
logger.V(2).Info("warning: failed to validate old object, skipping the rule evaluation as pre-existing violations are allowed", "rule", rule.Name, "error", err.Error())
|
||||||
|
return resource, engineapi.RuleSkip(rule.Name, engineapi.Validation, "failed to validate old object, skipping as preexisting violations are allowed", rule.ReportProperties)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ruleResponse.Status() == priorResp.Status() {
|
||||||
|
logger.V(3).Info("skipping modified resource as validation results have not changed", "oldResp", priorResp, "newResp", ruleResponse)
|
||||||
|
if ruleResponse.Status() == engineapi.RuleStatusPass {
|
||||||
|
return resource, ruleResponse
|
||||||
|
}
|
||||||
|
return resource, engineapi.RuleSkip(rule.Name, engineapi.Validation, "skipping modified resource as validation results have not changed", rule.ReportProperties)
|
||||||
|
}
|
||||||
|
logger.V(4).Info("old object response is different", "oldResp", priorResp, "newResp", ruleResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource, ruleResponse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h validatePssHandler) validateOldObject(
|
||||||
|
ctx context.Context,
|
||||||
|
logger logr.Logger,
|
||||||
|
policyContext engineapi.PolicyContext,
|
||||||
|
resource unstructured.Unstructured,
|
||||||
|
rule kyvernov1.Rule,
|
||||||
|
engineLoader engineapi.EngineContextLoader,
|
||||||
|
exceptions []*kyvernov2.PolicyException,
|
||||||
|
) (*engineapi.RuleResponse, error) {
|
||||||
|
if policyContext.Operation() != kyvernov1.Update {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newResource := policyContext.NewResource()
|
||||||
|
oldResource := policyContext.OldResource()
|
||||||
|
emptyResource := unstructured.Unstructured{}
|
||||||
|
|
||||||
|
if ok := matchResource(oldResource, rule); !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err := policyContext.SetResources(emptyResource, oldResource); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to set resources")
|
||||||
|
}
|
||||||
|
if err := policyContext.SetOperation(kyvernov1.Create); err != nil { // simulates the condition when old object was "created"
|
||||||
|
return nil, errors.Wrapf(err, "failed to set operation")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, resp := h.validate(ctx, logger, policyContext, oldResource, rule, engineLoader, exceptions)
|
||||||
|
|
||||||
|
if err := policyContext.SetResources(oldResource, newResource); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to reset resources")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := policyContext.SetOperation(kyvernov1.Update); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to reset operation")
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
func convertChecks(checks []pssutils.PSSCheckResult, kind string) (newChecks []pssutils.PSSCheckResult) {
|
func convertChecks(checks []pssutils.PSSCheckResult, kind string) (newChecks []pssutils.PSSCheckResult) {
|
||||||
if kind == "DaemonSet" || kind == "Deployment" || kind == "Job" || kind == "StatefulSet" || kind == "ReplicaSet" || kind == "ReplicationController" {
|
if kind == "DaemonSet" || kind == "Deployment" || kind == "Job" || kind == "StatefulSet" || kind == "ReplicaSet" || kind == "ReplicationController" {
|
||||||
for i := range checks {
|
for i := range checks {
|
||||||
|
|
|
@ -131,42 +131,39 @@ func (v *validator) validate(ctx context.Context) *engineapi.RuleResponse {
|
||||||
return engineapi.RuleSkip(v.rule.Name, engineapi.Validation, s, v.rule.ReportProperties)
|
return engineapi.RuleSkip(v.rule.Name, engineapi.Validation, s, v.rule.ReportProperties)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ruleResponse *engineapi.RuleResponse
|
||||||
if v.deny != nil {
|
if v.deny != nil {
|
||||||
return v.validateDeny()
|
ruleResponse = v.validateDeny()
|
||||||
}
|
} else if v.pattern != nil || v.anyPattern != nil {
|
||||||
|
|
||||||
if v.pattern != nil || v.anyPattern != nil {
|
|
||||||
if err = v.substitutePatterns(); err != nil {
|
if err = v.substitutePatterns(); err != nil {
|
||||||
return engineapi.RuleError(v.rule.Name, engineapi.Validation, "variable substitution failed", err, v.rule.ReportProperties)
|
return engineapi.RuleError(v.rule.Name, engineapi.Validation, "variable substitution failed", err, v.rule.ReportProperties)
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleResponse := v.validateResourceWithRule()
|
ruleResponse = v.validateResourceWithRule()
|
||||||
|
} else if v.forEach != nil {
|
||||||
|
ruleResponse = v.validateForEach(ctx)
|
||||||
|
} else {
|
||||||
|
v.log.V(2).Info("invalid validation rule: podSecurity, cel, patterns, or deny expected")
|
||||||
|
}
|
||||||
|
|
||||||
if engineutils.IsUpdateRequest(v.policyContext) {
|
allowExisitingViolations := v.rule.HasValidateAllowExistingViolations()
|
||||||
priorResp, err := v.validateOldObject(ctx)
|
if engineutils.IsUpdateRequest(v.policyContext) && allowExisitingViolations && v.nesting == 0 { // is update request and is the root level validate
|
||||||
if err != nil {
|
priorResp, err := v.validateOldObject(ctx)
|
||||||
return engineapi.RuleError(v.rule.Name, engineapi.Validation, "failed to validate old object", err, v.rule.ReportProperties)
|
if err != nil {
|
||||||
}
|
v.log.V(2).Info("warning: failed to validate old object, skipping the rule evaluation as pre-existing violations are allowed", "rule", v.rule.Name, "error", err.Error())
|
||||||
|
return engineapi.RuleSkip(v.rule.Name, engineapi.Validation, "failed to validate old object, skipping as preexisting violations are allowed", ruleResponse.Properties())
|
||||||
if engineutils.IsSameRuleResponse(ruleResponse, priorResp) {
|
|
||||||
v.log.V(3).Info("skipping modified resource as validation results have not changed")
|
|
||||||
if ruleResponse.Status() == engineapi.RuleStatusPass {
|
|
||||||
return ruleResponse
|
|
||||||
}
|
|
||||||
return engineapi.RuleSkip(v.rule.Name, engineapi.Validation, "skipping modified resource as validation results have not changed", v.rule.ReportProperties)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ruleResponse
|
if engineutils.IsSameRuleResponse(ruleResponse, priorResp) {
|
||||||
|
v.log.V(3).Info("skipping modified resource as validation results have not changed")
|
||||||
|
if ruleResponse.Status() == engineapi.RuleStatusPass {
|
||||||
|
return ruleResponse
|
||||||
|
}
|
||||||
|
return engineapi.RuleSkip(v.rule.Name, engineapi.Validation, "skipping modified resource as validation results have not changed", v.rule.ReportProperties)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.forEach != nil {
|
return ruleResponse
|
||||||
ruleResponse := v.validateForEach(ctx)
|
|
||||||
return ruleResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
v.log.V(2).Info("invalid validation rule: podSecurity, cel, patterns, or deny expected")
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *validator) validateOldObject(ctx context.Context) (*engineapi.RuleResponse, error) {
|
func (v *validator) validateOldObject(ctx context.Context) (*engineapi.RuleResponse, error) {
|
||||||
|
@ -178,9 +175,16 @@ func (v *validator) validateOldObject(ctx context.Context) (*engineapi.RuleRespo
|
||||||
oldResource := v.policyContext.OldResource()
|
oldResource := v.policyContext.OldResource()
|
||||||
emptyResource := unstructured.Unstructured{}
|
emptyResource := unstructured.Unstructured{}
|
||||||
|
|
||||||
|
if ok := matchResource(oldResource, v.rule); !ok {
|
||||||
|
return engineapi.RuleSkip(v.rule.Name, engineapi.Validation, "resource not matched", v.rule.ReportProperties), nil
|
||||||
|
}
|
||||||
|
|
||||||
if err := v.policyContext.SetResources(emptyResource, oldResource); err != nil {
|
if err := v.policyContext.SetResources(emptyResource, oldResource); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to set resources")
|
return nil, errors.Wrapf(err, "failed to set resources")
|
||||||
}
|
}
|
||||||
|
if err := v.policyContext.SetOperation(kyvernov1.Create); err != nil { // simulates the condition when old object was "created"
|
||||||
|
return nil, errors.Wrapf(err, "failed to set operation")
|
||||||
|
}
|
||||||
|
|
||||||
resp := v.validate(ctx)
|
resp := v.validate(ctx)
|
||||||
|
|
||||||
|
@ -188,6 +192,10 @@ func (v *validator) validateOldObject(ctx context.Context) (*engineapi.RuleRespo
|
||||||
return nil, errors.Wrapf(err, "failed to reset resources")
|
return nil, errors.Wrapf(err, "failed to reset resources")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := v.policyContext.SetOperation(kyvernov1.Update); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to reset operation")
|
||||||
|
}
|
||||||
|
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ func Test_validateOldObject(t *testing.T) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
policyContext := buildTestNamespaceLabelsContext(t)
|
policyContext := buildTestNamespaceLabelsContext(t, validateDenyPolicy, resource, oldResource)
|
||||||
rule := policyContext.Policy().GetSpec().Rules[0]
|
rule := policyContext.Policy().GetSpec().Rules[0]
|
||||||
v := newValidator(logr.Discard(), mockCL, policyContext, rule)
|
v := newValidator(logr.Discard(), mockCL, policyContext, rule)
|
||||||
|
|
||||||
|
@ -32,8 +32,27 @@ func Test_validateOldObject(t *testing.T) {
|
||||||
assert.Equal(t, api.RuleStatusFail, resp2.Status())
|
assert.Equal(t, api.RuleStatusFail, resp2.Status())
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildTestNamespaceLabelsContext(t *testing.T) api.PolicyContext {
|
func buildTestNamespaceLabelsContext(t *testing.T, policy string, resource string, oldResource string) api.PolicyContext {
|
||||||
policy := `{
|
return buildContext(t, kyvernov1.Update, policy, resource, oldResource)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_validateOldObjectForeach(t *testing.T) {
|
||||||
|
mockCL := func(ctx context.Context, contextEntries []kyvernov1.ContextEntry, jsonContext enginecontext.Interface) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
policyContext := buildTestNamespaceLabelsContext(t, validateForeachPolicy, resource, oldResource)
|
||||||
|
rule := policyContext.Policy().GetSpec().Rules[0]
|
||||||
|
v := newValidator(logr.Discard(), mockCL, policyContext, rule)
|
||||||
|
|
||||||
|
ctx := context.TODO()
|
||||||
|
resp := v.validate(ctx)
|
||||||
|
assert.NotNil(t, resp)
|
||||||
|
assert.Equal(t, api.RuleStatusSkip, resp.Status())
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
validateDenyPolicy = `{
|
||||||
"apiVersion": "kyverno.io/v1",
|
"apiVersion": "kyverno.io/v1",
|
||||||
"kind": "ClusterPolicy",
|
"kind": "ClusterPolicy",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
|
@ -105,11 +124,61 @@ func buildTestNamespaceLabelsContext(t *testing.T) api.PolicyContext {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
resource := `{
|
validateForeachPolicy = `{
|
||||||
|
"apiVersion": "kyverno.io/v1",
|
||||||
|
"kind": "ClusterPolicy",
|
||||||
|
"metadata": {
|
||||||
|
"name": "validate-image-list"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"admission": true,
|
||||||
|
"background": true,
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"match": {
|
||||||
|
"any": [
|
||||||
|
{
|
||||||
|
"resources": {
|
||||||
|
"kinds": [
|
||||||
|
"Pod"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "check-image",
|
||||||
|
"validate": {
|
||||||
|
"failureAction": "Audit",
|
||||||
|
"allowExistingViolations": true,
|
||||||
|
"foreach": [
|
||||||
|
{
|
||||||
|
"deny": {
|
||||||
|
"conditions": {
|
||||||
|
"all": [
|
||||||
|
{
|
||||||
|
"key": "{{ element }}",
|
||||||
|
"operator": "NotEquals",
|
||||||
|
"value": "ghcr.io"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"list": "request.object.spec.containers[].image"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"message": "images must begin with ghcr.io"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
resource = `{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Namespace",
|
"kind": "Pod",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"annotations": {},
|
"annotations": {},
|
||||||
"labels": {
|
"labels": {
|
||||||
|
@ -118,12 +187,49 @@ func buildTestNamespaceLabelsContext(t *testing.T) api.PolicyContext {
|
||||||
},
|
},
|
||||||
"name": "test"
|
"name": "test"
|
||||||
},
|
},
|
||||||
"spec": {}
|
"spec": {
|
||||||
}`
|
"containers": [
|
||||||
|
{
|
||||||
|
"image": "ghcr.io/test-webserver",
|
||||||
|
"name": "test1",
|
||||||
|
"volumeMounts": [
|
||||||
|
{
|
||||||
|
"mountPath": "/tmp/cache",
|
||||||
|
"name": "cache-volume"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image": "ghcr.io/test-webserver",
|
||||||
|
"name": "test2",
|
||||||
|
"volumeMounts": [
|
||||||
|
{
|
||||||
|
"mountPath": "/tmp/cache",
|
||||||
|
"name": "cache-volume"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mountPath": "/gce",
|
||||||
|
"name": "gce"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"volumes": [
|
||||||
|
{
|
||||||
|
"name": "cache-volume",
|
||||||
|
"emptyDir": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "gce",
|
||||||
|
"gcePersistentDisk": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
oldResource := `{
|
oldResource = `{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Namespace",
|
"kind": "Pod",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"labels": {
|
"labels": {
|
||||||
"kubernetes.io/metadata.name": "test",
|
"kubernetes.io/metadata.name": "test",
|
||||||
|
@ -131,8 +237,43 @@ func buildTestNamespaceLabelsContext(t *testing.T) api.PolicyContext {
|
||||||
},
|
},
|
||||||
"name": "test"
|
"name": "test"
|
||||||
},
|
},
|
||||||
"spec": {}
|
"spec": {
|
||||||
}`
|
"containers": [
|
||||||
|
{
|
||||||
return buildContext(t, kyvernov1.Update, policy, resource, oldResource)
|
"image": "ghcr.io/test-webserver",
|
||||||
}
|
"name": "test1",
|
||||||
|
"volumeMounts": [
|
||||||
|
{
|
||||||
|
"mountPath": "/tmp/cache",
|
||||||
|
"name": "cache-volume"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"image": "ghcr.io/test-webserver",
|
||||||
|
"name": "test2",
|
||||||
|
"volumeMounts": [
|
||||||
|
{
|
||||||
|
"mountPath": "/tmp/cache",
|
||||||
|
"name": "cache-volume"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mountPath": "/gce",
|
||||||
|
"name": "gce"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"volumes": [
|
||||||
|
{
|
||||||
|
"name": "cache-volume",
|
||||||
|
"emptyDir": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "gce",
|
||||||
|
"gcePersistentDisk": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
|
|
@ -106,6 +106,14 @@ func (c *PolicyContext) Operation() kyvernov1.AdmissionOperation {
|
||||||
return c.operation
|
return c.operation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *PolicyContext) SetOperation(op kyvernov1.AdmissionOperation) error {
|
||||||
|
c.operation = op
|
||||||
|
if err := c.jsonContext.AddOperation(string(op)); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to replace old object in the JSON context")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *PolicyContext) NamespaceLabels() map[string]string {
|
func (c *PolicyContext) NamespaceLabels() map[string]string {
|
||||||
return c.namespaceLabels
|
return c.namespaceLabels
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,5 +110,5 @@ func IsSameRuleResponse(r1 *engineapi.RuleResponse, r2 *engineapi.RuleResponse)
|
||||||
|
|
||||||
func IsUpdateRequest(ctx engineapi.PolicyContext) bool {
|
func IsUpdateRequest(ctx engineapi.PolicyContext) bool {
|
||||||
// is the OldObject and NewObject are available, the request is an UPDATE
|
// is the OldObject and NewObject are available, the request is an UPDATE
|
||||||
return ctx.OldResource().Object != nil && ctx.NewResource().Object != nil
|
return (ctx.OldResource().Object != nil && ctx.NewResource().Object != nil) || ctx.Operation() == kyvernov1.Update
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This test ensures that request.oldObject is not null on UPDATE operations when there are multiple rules in a policy.
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
The namespace update operation is allowed.
|
||||||
|
|
||||||
|
## Reference Issue(s)
|
||||||
|
|
||||||
|
https://github.com/kyverno/kyverno/issues/9885
|
|
@ -0,0 +1,34 @@
|
||||||
|
apiVersion: chainsaw.kyverno.io/v1alpha1
|
||||||
|
kind: Test
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
name: check-old-object
|
||||||
|
spec:
|
||||||
|
steps:
|
||||||
|
- name: step-01
|
||||||
|
try:
|
||||||
|
- create:
|
||||||
|
file: ns.yaml
|
||||||
|
- assert:
|
||||||
|
file: ns-ready.yaml
|
||||||
|
- name: step-02
|
||||||
|
try:
|
||||||
|
- create:
|
||||||
|
file: policy.yaml
|
||||||
|
- assert:
|
||||||
|
file: policy-ready.yaml
|
||||||
|
- name: step-03
|
||||||
|
try:
|
||||||
|
- update:
|
||||||
|
file: ns-update.yaml
|
||||||
|
- name: step-04
|
||||||
|
try:
|
||||||
|
- update:
|
||||||
|
file: ns-update-good.yaml
|
||||||
|
- name: step-05
|
||||||
|
try:
|
||||||
|
- update:
|
||||||
|
file: ns-update-bad.yaml
|
||||||
|
expect:
|
||||||
|
- check:
|
||||||
|
($error != null): true
|
|
@ -0,0 +1,7 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: test
|
||||||
|
labels:
|
||||||
|
kubernetes.io/metadata.name: test
|
||||||
|
size: unknown
|
|
@ -0,0 +1,7 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: test
|
||||||
|
labels:
|
||||||
|
kubernetes.io/metadata.name: test
|
||||||
|
size: bad
|
|
@ -0,0 +1,7 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: test
|
||||||
|
labels:
|
||||||
|
kubernetes.io/metadata.name: test
|
||||||
|
size: large
|
|
@ -0,0 +1,7 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: test
|
||||||
|
labels:
|
||||||
|
kubernetes.io/metadata.name: test
|
||||||
|
size: extralarge
|
|
@ -0,0 +1,7 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: test
|
||||||
|
labels:
|
||||||
|
kubernetes.io/metadata.name: test
|
||||||
|
size: unknown
|
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: check-old-object
|
|
@ -0,0 +1,36 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: check-old-object
|
||||||
|
spec:
|
||||||
|
background: false
|
||||||
|
rules:
|
||||||
|
- name: require-labels
|
||||||
|
match:
|
||||||
|
all:
|
||||||
|
- resources:
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
|
kinds:
|
||||||
|
- Namespace
|
||||||
|
context:
|
||||||
|
- name: small
|
||||||
|
variable:
|
||||||
|
value: small
|
||||||
|
- name: medium
|
||||||
|
variable:
|
||||||
|
value: medium
|
||||||
|
- name: large
|
||||||
|
variable:
|
||||||
|
value: large
|
||||||
|
validate:
|
||||||
|
failureAction: Enforce
|
||||||
|
message: "The label `size` is required"
|
||||||
|
assert:
|
||||||
|
object:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
size:
|
||||||
|
(@ == $small || @ == $medium || @ == $large): true
|
||||||
|
|
|
@ -128,7 +128,7 @@
|
||||||
"^validate$/^clusterpolicy$/^standard$/^cel$/^parameter-resources$/^namespaced$/^(match-clusterscoped-resource|set-paramref-namespace|unset-paramref-namespace)\\[.*\\]$",
|
"^validate$/^clusterpolicy$/^standard$/^cel$/^parameter-resources$/^namespaced$/^(match-clusterscoped-resource|set-paramref-namespace|unset-paramref-namespace)\\[.*\\]$",
|
||||||
"^validate$/^clusterpolicy$/^standard$/^debug$/^(with-pod|with-subresource|with-wildcard)\\[.*\\]$",
|
"^validate$/^clusterpolicy$/^standard$/^debug$/^(with-pod|with-subresource|with-wildcard)\\[.*\\]$",
|
||||||
"^validate$/^clusterpolicy$/^standard$/^debug-deprecated$/^(with-pod|with-subresource|with-wildcard)\\[.*\\]$",
|
"^validate$/^clusterpolicy$/^standard$/^debug-deprecated$/^(with-pod|with-subresource|with-wildcard)\\[.*\\]$",
|
||||||
"^validate$/^clusterpolicy$/^standard$/^enforce$/^(api-initiated-pod-eviction|block-pod-exec-requests|bypass-with-policy-exception|csr|enforce-validate-existing|failure-policy-ignore-anchor|ns-selector-with-wildcard-kind|operator-allnotin-01|operator-anyin-boolean|resource-apply-block|scaling-with-kubectl-scale)\\[.*\\]$",
|
"^validate$/^clusterpolicy$/^standard$/^enforce$/^(api-initiated-pod-eviction|block-pod-exec-requests|bypass-with-policy-exception|csr|enforce-validate-existing|enforce-validate-existing-allow-existing-violations|enforce-validate-existing-deny|enforce-validate-existing-pss|failure-policy-ignore-anchor|ns-selector-with-wildcard-kind|operator-allnotin-01|operator-anyin-boolean|resource-apply-block|scaling-with-kubectl-scale)\\[.*\\]$",
|
||||||
"^validate$/^clusterpolicy$/^standard$/^enforce-deprecated$/^(api-initiated-pod-eviction|block-pod-exec-requests|bypass-with-policy-exception|csr|enforce-validate-existing|failure-policy-ignore-anchor|ns-selector-with-wildcard-kind|operator-allnotin-01|operator-anyin-boolean|resource-apply-block|scaling-with-kubectl-scale)\\[.*\\]$",
|
"^validate$/^clusterpolicy$/^standard$/^enforce-deprecated$/^(api-initiated-pod-eviction|block-pod-exec-requests|bypass-with-policy-exception|csr|enforce-validate-existing|failure-policy-ignore-anchor|ns-selector-with-wildcard-kind|operator-allnotin-01|operator-anyin-boolean|resource-apply-block|scaling-with-kubectl-scale)\\[.*\\]$",
|
||||||
"^validate$/^clusterpolicy$/^standard$/^exclude$/^(exclude-namespace|exclude-namespace(deprecated))\\[.*\\]$",
|
"^validate$/^clusterpolicy$/^standard$/^exclude$/^(exclude-namespace|exclude-namespace(deprecated))\\[.*\\]$",
|
||||||
"^validate$/^clusterpolicy$/^standard$/^operations$/^(only-update|only-update(deprecated))\\[.*\\]$",
|
"^validate$/^clusterpolicy$/^standard$/^operations$/^(only-update|only-update(deprecated))\\[.*\\]$",
|
||||||
|
|
|
@ -15,4 +15,5 @@ spec:
|
||||||
kinds:
|
kinds:
|
||||||
- Pod
|
- Pod
|
||||||
validate:
|
validate:
|
||||||
|
allowExistingViolations: false
|
||||||
deny: {}
|
deny: {}
|
||||||
|
|
|
@ -14,5 +14,6 @@ spec:
|
||||||
kinds:
|
kinds:
|
||||||
- Pod
|
- Pod
|
||||||
validate:
|
validate:
|
||||||
|
allowExistingViolations: false
|
||||||
failureAction: Enforce
|
failureAction: Enforce
|
||||||
deny: {}
|
deny: {}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This test mainly verifies that an enforce validate policy blocks changes in old objects that were present before policy was created when `allowExistingViolations` is set to `false`
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
1. A bad pod is created that violates the policy.
|
||||||
|
2. The policy is applied.
|
||||||
|
3. Violating changes in bad pod causes error becuase `allowExistingViolations` is set to `false`
|
||||||
|
|
||||||
|
## Reference Issue(s)
|
||||||
|
|
||||||
|
10084
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: badpod-allow-existing
|
||||||
|
namespace: default
|
|
@ -0,0 +1,8 @@
|
||||||
|
if kubectl label po badpod-allow-existing foo=bad1 --overwrite 2>&1 | grep -q "validation error: rule check-labels"
|
||||||
|
then
|
||||||
|
echo "Test succeed, updating violating preexisting resource does throw error"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "Test failed, updating violating preexisting resource should throw error"
|
||||||
|
exit 1
|
||||||
|
fi
|
|
@ -0,0 +1,14 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: badpod-allow-existing
|
||||||
|
namespace: default
|
||||||
|
labels:
|
||||||
|
foo: bad
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: container01
|
||||||
|
image: busybox:1.35
|
||||||
|
args:
|
||||||
|
- sleep
|
||||||
|
- 1d
|
|
@ -0,0 +1,25 @@
|
||||||
|
apiVersion: chainsaw.kyverno.io/v1alpha1
|
||||||
|
kind: Test
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
name: enforce-validate-existing
|
||||||
|
spec:
|
||||||
|
steps:
|
||||||
|
- name: step-01
|
||||||
|
try:
|
||||||
|
- apply:
|
||||||
|
file: bad-pod.yaml
|
||||||
|
- assert:
|
||||||
|
file: bad-pod-ready.yaml
|
||||||
|
- name: step-02
|
||||||
|
try:
|
||||||
|
- apply:
|
||||||
|
file: policy.yaml
|
||||||
|
- assert:
|
||||||
|
file: policy-ready.yaml
|
||||||
|
- name: step-03
|
||||||
|
try:
|
||||||
|
- script:
|
||||||
|
content: ./bad-pod-update-test.sh
|
||||||
|
timeout: 30s
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: check-labels-allow-existing
|
|
@ -0,0 +1,22 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: check-labels-allow-existing
|
||||||
|
spec:
|
||||||
|
background: true
|
||||||
|
rules:
|
||||||
|
- name: check-labels
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
validate:
|
||||||
|
failureAction: Enforce
|
||||||
|
allowExistingViolations: false
|
||||||
|
deny:
|
||||||
|
conditions:
|
||||||
|
any:
|
||||||
|
- key: "{{ request.object.metadata.labels.foo || '' }}"
|
||||||
|
operator: NotEquals
|
||||||
|
value: 'bar'
|
|
@ -0,0 +1,15 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This test mainly verifies that an enforce validate policy does not block changes in old objects that were present before policy was created
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
1. A pod is created that violates the policy.
|
||||||
|
2. The policy is applied.
|
||||||
|
3. A pod is created that follows the policy.
|
||||||
|
4. Violating changes on bad pad does not cause error.
|
||||||
|
5. Violating changes in good pod causes error.
|
||||||
|
6. The bad pod once passed the policy, will be tracked by the policy and return error on bad changes.
|
||||||
|
## Reference Issue(s)
|
||||||
|
|
||||||
|
8837
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: badpod-deny
|
||||||
|
namespace: default
|
|
@ -0,0 +1,8 @@
|
||||||
|
if kubectl label po badpod-deny foo=bad1 --overwrite 2>&1 | grep -q "validation error: rule check-labels"
|
||||||
|
then
|
||||||
|
echo "Test failed, updating violating preexisting resource should not throw error"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Test succeed, updating violating preexisting resource does not throw error"
|
||||||
|
exit 0
|
||||||
|
fi
|
|
@ -0,0 +1,14 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: badpod-deny
|
||||||
|
namespace: default
|
||||||
|
labels:
|
||||||
|
foo: bad
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: container01
|
||||||
|
image: busybox:1.35
|
||||||
|
args:
|
||||||
|
- sleep
|
||||||
|
- 1d
|
|
@ -0,0 +1,40 @@
|
||||||
|
apiVersion: chainsaw.kyverno.io/v1alpha1
|
||||||
|
kind: Test
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
name: enforce-validate-existing
|
||||||
|
spec:
|
||||||
|
steps:
|
||||||
|
- name: step-01
|
||||||
|
try:
|
||||||
|
- apply:
|
||||||
|
file: bad-pod.yaml
|
||||||
|
- assert:
|
||||||
|
file: bad-pod-ready.yaml
|
||||||
|
- name: step-02
|
||||||
|
try:
|
||||||
|
- apply:
|
||||||
|
file: policy.yaml
|
||||||
|
- assert:
|
||||||
|
file: policy-ready.yaml
|
||||||
|
- name: step-03
|
||||||
|
try:
|
||||||
|
- apply:
|
||||||
|
file: good-pod.yaml
|
||||||
|
- assert:
|
||||||
|
file: good-pod-ready.yaml
|
||||||
|
- name: step-04
|
||||||
|
try:
|
||||||
|
- script:
|
||||||
|
content: ./bad-pod-update-test.sh
|
||||||
|
timeout: 30s
|
||||||
|
- name: step-05
|
||||||
|
try:
|
||||||
|
- script:
|
||||||
|
content: ./good-pod-update-test.sh
|
||||||
|
timeout: 30s
|
||||||
|
- name: step-06
|
||||||
|
try:
|
||||||
|
- script:
|
||||||
|
content: ./update-bad-pod-to-comply.sh
|
||||||
|
timeout: 30s
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: goodpod-deny
|
||||||
|
namespace: default
|
|
@ -0,0 +1,8 @@
|
||||||
|
if kubectl label po goodpod-deny foo=bad1 --overwrite 2>&1 | grep -q "validation error: rule check-labels"
|
||||||
|
then
|
||||||
|
echo "Test succeed, updating violating resource throws error"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "Test failed, updating violating resource did not throw error"
|
||||||
|
exit 1
|
||||||
|
fi
|
|
@ -0,0 +1,14 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: goodpod-deny
|
||||||
|
namespace: default
|
||||||
|
labels:
|
||||||
|
foo: bar
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: container01
|
||||||
|
image: busybox:1.35
|
||||||
|
args:
|
||||||
|
- sleep
|
||||||
|
- 1d
|
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: check-labels-deny
|
|
@ -0,0 +1,21 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: check-labels-deny
|
||||||
|
spec:
|
||||||
|
background: true
|
||||||
|
rules:
|
||||||
|
- name: check-labels
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
validate:
|
||||||
|
failureAction: Enforce
|
||||||
|
deny:
|
||||||
|
conditions:
|
||||||
|
any:
|
||||||
|
- key: "{{ request.object.metadata.labels.foo || '' }}"
|
||||||
|
operator: NotEquals
|
||||||
|
value: 'bar'
|
|
@ -0,0 +1,9 @@
|
||||||
|
kubectl label po badpod-deny foo=bar --overwrite
|
||||||
|
if kubectl label po badpod-deny foo=bad1 --overwrite 2>&1 | grep -q "validation error: rule check-labels"
|
||||||
|
then
|
||||||
|
echo "Test succeed, updating violating resource throws error"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "Test failed, updating violating resource did not throw error"
|
||||||
|
exit 1
|
||||||
|
fi
|
|
@ -0,0 +1,17 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This test mainly verifies that an pss validate policy does not block changes in old objects that were present before policy was created
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
1. A pod is created that violates the policy.
|
||||||
|
2. The policy is applied.
|
||||||
|
3. The bad pod is updated with a bad change, it is applied
|
||||||
|
4. The bad pod is made to comply
|
||||||
|
5. A bad change in that pod does not go through
|
||||||
|
6. A good pod is created
|
||||||
|
7. Violating changes in good pod causes error.
|
||||||
|
|
||||||
|
## Reference Issue(s)
|
||||||
|
|
||||||
|
8837
|
|
@ -0,0 +1,6 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: bad-deployment
|
||||||
|
labels:
|
||||||
|
app: nginx
|
|
@ -0,0 +1,41 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: bad-deployment
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1
|
||||||
|
seccompProfile:
|
||||||
|
type: Localhost
|
||||||
|
localhostProfile: operator/default/profile1.json
|
||||||
|
hostNetwork: false
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: ghcr.io/kyverno/test-nginx:dontpull
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
runAsNonRoot: true
|
||||||
|
seccompProfile:
|
||||||
|
type: Localhost
|
||||||
|
localhostProfile: operator/default/profile1.json
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
add:
|
||||||
|
- NET_BIND_SERVICE
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: bad-deployment
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1
|
||||||
|
seccompProfile:
|
||||||
|
type: Localhost
|
||||||
|
localhostProfile: operator/default/profile1.json
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: ghcr.io/kyverno/test-nginx:dontpull
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: true
|
||||||
|
runAsNonRoot: true
|
||||||
|
seccompProfile:
|
||||||
|
type: Localhost
|
||||||
|
localhostProfile: operator/default/profile1.json
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
add:
|
||||||
|
- NET_BIND_SERVICE
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: bad-deployment
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: ghcr.io/kyverno/test-nginx:dontpull-new-image
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: true
|
||||||
|
runAsNonRoot: true
|
||||||
|
seccompProfile:
|
||||||
|
type: Localhost
|
||||||
|
localhostProfile: operator/default/profile1.json
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
add:
|
||||||
|
- NET_BIND_SERVICE
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: bad-deployment
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1
|
||||||
|
seccompProfile:
|
||||||
|
type: Localhost
|
||||||
|
localhostProfile: operator/default/profile1.json
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: ghcr.io/kyverno/test-nginx:dontpull
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: true
|
||||||
|
runAsNonRoot: true
|
||||||
|
seccompProfile:
|
||||||
|
type: Localhost
|
||||||
|
localhostProfile: operator/default/profile1.json
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
add:
|
||||||
|
- NET_BIND_SERVICE
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
apiVersion: chainsaw.kyverno.io/v1alpha1
|
||||||
|
kind: Test
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
name: enforce-validate-existing
|
||||||
|
spec:
|
||||||
|
steps:
|
||||||
|
- name: step-01
|
||||||
|
try:
|
||||||
|
- apply:
|
||||||
|
file: bad-deploy.yaml
|
||||||
|
- assert:
|
||||||
|
file: bad-deploy-ready.yaml
|
||||||
|
- name: step-02
|
||||||
|
try:
|
||||||
|
- apply:
|
||||||
|
file: policy.yaml
|
||||||
|
- assert:
|
||||||
|
file: policy-ready.yaml
|
||||||
|
- name: step-03
|
||||||
|
try:
|
||||||
|
- apply:
|
||||||
|
file: bad-deploy-update.yaml
|
||||||
|
- name: step-04
|
||||||
|
try:
|
||||||
|
- apply:
|
||||||
|
file: bad-deploy-update-comply.yaml
|
||||||
|
- name: step-05
|
||||||
|
try:
|
||||||
|
- apply:
|
||||||
|
file: bad-deploy-update-remove-comply.yaml
|
||||||
|
expect:
|
||||||
|
- check:
|
||||||
|
($error != `null`): true
|
||||||
|
- name: step-06
|
||||||
|
try:
|
||||||
|
- apply:
|
||||||
|
file: good-deploy.yaml
|
||||||
|
- name: step-07
|
||||||
|
try:
|
||||||
|
- apply:
|
||||||
|
file: good-deploy-update.yaml
|
||||||
|
expect:
|
||||||
|
- check:
|
||||||
|
($error != `null`): true
|
|
@ -0,0 +1,6 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: good-deployment
|
||||||
|
labels:
|
||||||
|
app: nginx
|
|
@ -0,0 +1,40 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: good-deployment
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1
|
||||||
|
seccompProfile:
|
||||||
|
type: Localhost
|
||||||
|
localhostProfile: operator/default/profile1.json
|
||||||
|
hostNetwork: false
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: ghcr.io/kyverno/test-nginx:dontpull
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: true
|
||||||
|
runAsNonRoot: true
|
||||||
|
seccompProfile:
|
||||||
|
type: Localhost
|
||||||
|
localhostProfile: operator/default/profile1.json
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
add:
|
||||||
|
- NET_BIND_SERVICE
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: good-deployment
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nginx
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nginx
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1
|
||||||
|
seccompProfile:
|
||||||
|
type: Localhost
|
||||||
|
localhostProfile: operator/default/profile1.json
|
||||||
|
hostNetwork: false
|
||||||
|
containers:
|
||||||
|
- name: nginx
|
||||||
|
image: ghcr.io/kyverno/test-nginx:dontpull
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
runAsNonRoot: true
|
||||||
|
seccompProfile:
|
||||||
|
type: Localhost
|
||||||
|
localhostProfile: operator/default/profile1.json
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
add:
|
||||||
|
- NET_BIND_SERVICE
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: podsecurity-subrule-baseline
|
|
@ -0,0 +1,19 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: podsecurity-subrule-baseline
|
||||||
|
spec:
|
||||||
|
background: true
|
||||||
|
validationFailureAction: Enforce
|
||||||
|
rules:
|
||||||
|
- name: baseline
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
- Deployment
|
||||||
|
validate:
|
||||||
|
podSecurity:
|
||||||
|
level: restricted
|
||||||
|
version: latest
|
|
@ -1,5 +1,5 @@
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Pod
|
kind: Pod
|
||||||
metadata:
|
metadata:
|
||||||
name: badpod
|
name: badpod-validate-existing
|
||||||
namespace: default
|
namespace: default
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
if kubectl label po badpod foo=bad1 --overwrite 2>&1 | grep -q "validation error: rule check-labels"
|
if kubectl label po badpod-validate-existing foo=bad1 --overwrite 2>&1 | grep -q "validation error: rule check-labels"
|
||||||
then
|
then
|
||||||
echo "Test failed, updating violating preexisting resource should not throw error"
|
echo "Test failed, updating violating preexisting resource should not throw error"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Pod
|
kind: Pod
|
||||||
metadata:
|
metadata:
|
||||||
name: badpod
|
name: badpod-validate-existing
|
||||||
namespace: default
|
namespace: default
|
||||||
labels:
|
labels:
|
||||||
foo: bad
|
foo: bad
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Pod
|
kind: Pod
|
||||||
metadata:
|
metadata:
|
||||||
name: goodpod
|
name: goodpod-validate-existing
|
||||||
namespace: default
|
namespace: default
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
if kubectl label po goodpod foo=bad1 --overwrite 2>&1 | grep -q "validation error: rule check-labels"
|
if kubectl label po goodpod-validate-existing foo=bad1 --overwrite 2>&1 | grep -q "validation error: rule check-labels"
|
||||||
then
|
then
|
||||||
echo "Test succeed, updating violating resource throws error"
|
echo "Test succeed, updating violating resource throws error"
|
||||||
exit 0
|
exit 0
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Pod
|
kind: Pod
|
||||||
metadata:
|
metadata:
|
||||||
name: goodpod
|
name: goodpod-validate-existing
|
||||||
namespace: default
|
namespace: default
|
||||||
labels:
|
labels:
|
||||||
foo: bar
|
foo: bar
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
apiVersion: kyverno.io/v1
|
apiVersion: kyverno.io/v1
|
||||||
kind: ClusterPolicy
|
kind: ClusterPolicy
|
||||||
metadata:
|
metadata:
|
||||||
name: check-labels
|
name: check-labels-validate-existing
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
apiVersion: kyverno.io/v1
|
apiVersion: kyverno.io/v1
|
||||||
kind: ClusterPolicy
|
kind: ClusterPolicy
|
||||||
metadata:
|
metadata:
|
||||||
name: check-labels
|
name: check-labels-validate-existing
|
||||||
spec:
|
spec:
|
||||||
background: true
|
background: true
|
||||||
rules:
|
rules:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
kubectl label po badpod foo=bar --overwrite
|
kubectl label po badpod-validate-existing foo=bar --overwrite
|
||||||
if kubectl label po badpod foo=bad1 --overwrite 2>&1 | grep -q "validation error: rule check-labels"
|
if kubectl label po badpod-validate-existing foo=bad1 --overwrite 2>&1 | grep -q "validation error: rule check-labels"
|
||||||
then
|
then
|
||||||
echo "Test succeed, updating violating resource throws error"
|
echo "Test succeed, updating violating resource throws error"
|
||||||
exit 0
|
exit 0
|
||||||
|
|
Loading…
Reference in a new issue