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
|
||||
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.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty"`
|
||||
|
|
|
@ -187,6 +187,17 @@ func (r *Rule) HasValidate() bool {
|
|||
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
|
||||
func (r *Rule) HasGenerate() bool {
|
||||
return !datautils.DeepEqual(r.Generation, Generation{})
|
||||
|
|
|
@ -1698,6 +1698,11 @@ func (in *Validation) DeepCopyInto(out *Validation) {
|
|||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.AllowExistingViolations != nil {
|
||||
in, out := &in.AllowExistingViolations, &out.AllowExistingViolations
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.Manifests != nil {
|
||||
in, out := &in.Manifests, &out.Manifests
|
||||
*out = new(Manifests)
|
||||
|
|
|
@ -2888,6 +2888,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting violating
|
||||
resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -7852,6 +7857,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -17553,6 +17563,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
|
|
@ -2889,6 +2889,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting violating
|
||||
resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -7854,6 +7859,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -17556,6 +17566,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
|
|
@ -2882,6 +2882,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting violating
|
||||
resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -7846,6 +7851,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -17547,6 +17557,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
|
|
@ -2883,6 +2883,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting violating
|
||||
resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -7848,6 +7853,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -17550,6 +17560,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
|
|
@ -2882,6 +2882,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting violating
|
||||
resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -7846,6 +7851,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -17547,6 +17557,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
|
|
@ -2883,6 +2883,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting violating
|
||||
resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -7848,6 +7853,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -17550,6 +17560,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
|
|
@ -8205,6 +8205,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting violating
|
||||
resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -13169,6 +13174,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -22870,6 +22880,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -28163,6 +28178,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting violating
|
||||
resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -33128,6 +33148,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
AnyPattern specifies list of validation patterns. At least one of the patterns
|
||||
|
@ -42830,6 +42855,11 @@ spec:
|
|||
validate:
|
||||
description: Validation is used to validate matching resources.
|
||||
properties:
|
||||
allowExistingViolations:
|
||||
default: true
|
||||
description: AllowExistingViolations allows prexisting
|
||||
violating resources to continue violating a policy.
|
||||
type: boolean
|
||||
anyPattern:
|
||||
description: |-
|
||||
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>
|
||||
<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/>
|
||||
<em>
|
||||
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>
|
||||
<td><code>message</code>
|
||||
|
||||
|
|
|
@ -27,17 +27,18 @@ import (
|
|||
// ValidationApplyConfiguration represents an declarative configuration of the Validation type for use
|
||||
// with apply.
|
||||
type ValidationApplyConfiguration struct {
|
||||
FailureAction *v1.ValidationFailureAction `json:"failureAction,omitempty"`
|
||||
FailureActionOverrides []ValidationFailureActionOverrideApplyConfiguration `json:"failureActionOverrides,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
Manifests *ManifestsApplyConfiguration `json:"manifests,omitempty"`
|
||||
ForEachValidation []ForEachValidationApplyConfiguration `json:"foreach,omitempty"`
|
||||
RawPattern *apiextensionsv1.JSON `json:"pattern,omitempty"`
|
||||
RawAnyPattern *apiextensionsv1.JSON `json:"anyPattern,omitempty"`
|
||||
Deny *DenyApplyConfiguration `json:"deny,omitempty"`
|
||||
PodSecurity *PodSecurityApplyConfiguration `json:"podSecurity,omitempty"`
|
||||
CEL *CELApplyConfiguration `json:"cel,omitempty"`
|
||||
Assert *v1alpha1.Any `json:"assert,omitempty"`
|
||||
FailureAction *v1.ValidationFailureAction `json:"failureAction,omitempty"`
|
||||
FailureActionOverrides []ValidationFailureActionOverrideApplyConfiguration `json:"failureActionOverrides,omitempty"`
|
||||
AllowExistingViolations *bool `json:"allowExistingViolations,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
Manifests *ManifestsApplyConfiguration `json:"manifests,omitempty"`
|
||||
ForEachValidation []ForEachValidationApplyConfiguration `json:"foreach,omitempty"`
|
||||
RawPattern *apiextensionsv1.JSON `json:"pattern,omitempty"`
|
||||
RawAnyPattern *apiextensionsv1.JSON `json:"anyPattern,omitempty"`
|
||||
Deny *DenyApplyConfiguration `json:"deny,omitempty"`
|
||||
PodSecurity *PodSecurityApplyConfiguration `json:"podSecurity,omitempty"`
|
||||
CEL *CELApplyConfiguration `json:"cel,omitempty"`
|
||||
Assert *v1alpha1.Any `json:"assert,omitempty"`
|
||||
}
|
||||
|
||||
// ValidationApplyConfiguration constructs an declarative configuration of the Validation type for use with
|
||||
|
@ -67,6 +68,14 @@ func (b *ValidationApplyConfiguration) WithFailureActionOverrides(values ...*Val
|
|||
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
|
||||
// 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.
|
||||
|
|
|
@ -19,6 +19,7 @@ type PolicyContext interface {
|
|||
SetResources(oldResource, newResource unstructured.Unstructured) error
|
||||
AdmissionInfo() kyvernov2.RequestInfo
|
||||
Operation() kyvernov1.AdmissionOperation
|
||||
SetOperation(op kyvernov1.AdmissionOperation) error
|
||||
NamespaceLabels() map[string]string
|
||||
RequestResource() metav1.GroupVersionResource
|
||||
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"
|
||||
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
|
@ -111,6 +112,20 @@ func (h validateAssertHandler) Process(
|
|||
}
|
||||
// compose a response
|
||||
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
|
||||
for _, err := range errs {
|
||||
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),
|
||||
)
|
||||
}
|
||||
|
||||
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"
|
||||
pssutils "github.com/kyverno/kyverno/pkg/pss/utils"
|
||||
"github.com/kyverno/kyverno/pkg/utils/api"
|
||||
"github.com/pkg/errors"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
@ -36,9 +37,22 @@ func (h validatePssHandler) Process(
|
|||
policyContext engineapi.PolicyContext,
|
||||
resource unstructured.Unstructured,
|
||||
rule kyvernov1.Rule,
|
||||
_ engineapi.EngineContextLoader,
|
||||
engineLoader engineapi.EngineContextLoader,
|
||||
exceptions []*kyvernov2.PolicyException,
|
||||
) (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) {
|
||||
logger.V(3).Info("skipping PSS validation on deleted resource")
|
||||
return resource, nil
|
||||
|
@ -62,12 +76,10 @@ func (h validatePssHandler) Process(
|
|||
key, err := cache.MetaNamespaceKeyFunc(&polex)
|
||||
if err != nil {
|
||||
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)
|
||||
return resource, handlers.WithResponses(
|
||||
engineapi.RuleSkip(rule.Name, engineapi.Validation, "rule is skipped due to policy exception "+key, rule.ReportProperties).WithExceptions([]kyvernov2.PolicyException{polex}),
|
||||
)
|
||||
return resource, 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)
|
||||
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{
|
||||
Spec: *podSpec,
|
||||
|
@ -86,7 +98,7 @@ func (h validatePssHandler) Process(
|
|||
}
|
||||
levelVersion, err := pss.ParseVersion(podSecurity.Level, podSecurity.Version)
|
||||
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)
|
||||
pssChecks = convertChecks(pssChecks, resource.GetKind())
|
||||
|
@ -98,9 +110,7 @@ func (h validatePssHandler) Process(
|
|||
}
|
||||
if allowed {
|
||||
msg := fmt.Sprintf("Validation rule '%s' passed.", rule.Name)
|
||||
return resource, handlers.WithResponses(
|
||||
engineapi.RulePass(rule.Name, engineapi.Validation, msg, rule.ReportProperties).WithPodSecurityChecks(podSecurityChecks),
|
||||
)
|
||||
return resource, engineapi.RulePass(rule.Name, engineapi.Validation, msg, rule.ReportProperties).WithPodSecurityChecks(podSecurityChecks)
|
||||
} else {
|
||||
// apply pod security exceptions if exist
|
||||
var excludes []kyvernov1.PodSecurityStandard
|
||||
|
@ -109,7 +119,7 @@ func (h validatePssHandler) Process(
|
|||
key, err := cache.MetaNamespaceKeyFunc(&matchedExceptions[i])
|
||||
if err != nil {
|
||||
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)
|
||||
excludes = append(excludes, exception.Spec.PodSecurity...)
|
||||
|
@ -119,17 +129,73 @@ func (h validatePssHandler) Process(
|
|||
if len(pssChecks) == 0 && err == nil {
|
||||
podSecurityChecks.Checks = pssChecks
|
||||
logger.V(3).Info("policy rule is skipped due to policy exceptions", "exceptions", keys)
|
||||
return resource, handlers.WithResponses(
|
||||
engineapi.RuleSkip(rule.Name, engineapi.Validation, "rule is skipped due to policy exceptions "+strings.Join(keys, ", "), rule.ReportProperties).WithExceptions(matchedExceptions).WithPodSecurityChecks(podSecurityChecks),
|
||||
)
|
||||
return resource, 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))
|
||||
return resource, handlers.WithResponses(
|
||||
engineapi.RuleFail(rule.Name, engineapi.Validation, msg, rule.ReportProperties).WithPodSecurityChecks(podSecurityChecks),
|
||||
)
|
||||
ruleResponse := 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) {
|
||||
if kind == "DaemonSet" || kind == "Deployment" || kind == "Job" || kind == "StatefulSet" || kind == "ReplicaSet" || kind == "ReplicationController" {
|
||||
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)
|
||||
}
|
||||
|
||||
var ruleResponse *engineapi.RuleResponse
|
||||
if v.deny != nil {
|
||||
return v.validateDeny()
|
||||
}
|
||||
|
||||
if v.pattern != nil || v.anyPattern != nil {
|
||||
ruleResponse = v.validateDeny()
|
||||
} else if v.pattern != nil || v.anyPattern != nil {
|
||||
if err = v.substitutePatterns(); err != nil {
|
||||
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) {
|
||||
priorResp, err := v.validateOldObject(ctx)
|
||||
if err != nil {
|
||||
return engineapi.RuleError(v.rule.Name, engineapi.Validation, "failed to validate old object", err, v.rule.ReportProperties)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
allowExisitingViolations := v.rule.HasValidateAllowExistingViolations()
|
||||
if engineutils.IsUpdateRequest(v.policyContext) && allowExisitingViolations && v.nesting == 0 { // is update request and is the root level validate
|
||||
priorResp, err := v.validateOldObject(ctx)
|
||||
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())
|
||||
}
|
||||
|
||||
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 {
|
||||
ruleResponse := v.validateForEach(ctx)
|
||||
return ruleResponse
|
||||
}
|
||||
|
||||
v.log.V(2).Info("invalid validation rule: podSecurity, cel, patterns, or deny expected")
|
||||
return nil
|
||||
return ruleResponse
|
||||
}
|
||||
|
||||
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()
|
||||
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 {
|
||||
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)
|
||||
|
||||
|
@ -188,6 +192,10 @@ func (v *validator) validateOldObject(ctx context.Context) (*engineapi.RuleRespo
|
|||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ func Test_validateOldObject(t *testing.T) {
|
|||
return nil
|
||||
}
|
||||
|
||||
policyContext := buildTestNamespaceLabelsContext(t)
|
||||
policyContext := buildTestNamespaceLabelsContext(t, validateDenyPolicy, resource, oldResource)
|
||||
rule := policyContext.Policy().GetSpec().Rules[0]
|
||||
v := newValidator(logr.Discard(), mockCL, policyContext, rule)
|
||||
|
||||
|
@ -32,8 +32,27 @@ func Test_validateOldObject(t *testing.T) {
|
|||
assert.Equal(t, api.RuleStatusFail, resp2.Status())
|
||||
}
|
||||
|
||||
func buildTestNamespaceLabelsContext(t *testing.T) api.PolicyContext {
|
||||
policy := `{
|
||||
func buildTestNamespaceLabelsContext(t *testing.T, policy string, resource string, oldResource string) api.PolicyContext {
|
||||
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",
|
||||
"kind": "ClusterPolicy",
|
||||
"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",
|
||||
"kind": "Namespace",
|
||||
"kind": "Pod",
|
||||
"metadata": {
|
||||
"annotations": {},
|
||||
"labels": {
|
||||
|
@ -118,12 +187,49 @@ func buildTestNamespaceLabelsContext(t *testing.T) api.PolicyContext {
|
|||
},
|
||||
"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",
|
||||
"kind": "Namespace",
|
||||
"kind": "Pod",
|
||||
"metadata": {
|
||||
"labels": {
|
||||
"kubernetes.io/metadata.name": "test",
|
||||
|
@ -131,8 +237,43 @@ func buildTestNamespaceLabelsContext(t *testing.T) api.PolicyContext {
|
|||
},
|
||||
"name": "test"
|
||||
},
|
||||
"spec": {}
|
||||
}`
|
||||
|
||||
return buildContext(t, kyvernov1.Update, policy, resource, oldResource)
|
||||
}
|
||||
"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": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
}`
|
||||
)
|
||||
|
|
|
@ -106,6 +106,14 @@ func (c *PolicyContext) Operation() kyvernov1.AdmissionOperation {
|
|||
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 {
|
||||
return c.namespaceLabels
|
||||
}
|
||||
|
|
|
@ -110,5 +110,5 @@ func IsSameRuleResponse(r1 *engineapi.RuleResponse, r2 *engineapi.RuleResponse)
|
|||
|
||||
func IsUpdateRequest(ctx engineapi.PolicyContext) bool {
|
||||
// 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$/^debug$/^(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$/^exclude$/^(exclude-namespace|exclude-namespace(deprecated))\\[.*\\]$",
|
||||
"^validate$/^clusterpolicy$/^standard$/^operations$/^(only-update|only-update(deprecated))\\[.*\\]$",
|
||||
|
|
|
@ -15,4 +15,5 @@ spec:
|
|||
kinds:
|
||||
- Pod
|
||||
validate:
|
||||
allowExistingViolations: false
|
||||
deny: {}
|
||||
|
|
|
@ -14,5 +14,6 @@ spec:
|
|||
kinds:
|
||||
- Pod
|
||||
validate:
|
||||
allowExistingViolations: false
|
||||
failureAction: Enforce
|
||||
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
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: badpod
|
||||
name: badpod-validate-existing
|
||||
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
|
||||
echo "Test failed, updating violating preexisting resource should not throw error"
|
||||
exit 1
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: badpod
|
||||
name: badpod-validate-existing
|
||||
namespace: default
|
||||
labels:
|
||||
foo: bad
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: goodpod
|
||||
name: goodpod-validate-existing
|
||||
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
|
||||
echo "Test succeed, updating violating resource throws error"
|
||||
exit 0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: goodpod
|
||||
name: goodpod-validate-existing
|
||||
namespace: default
|
||||
labels:
|
||||
foo: bar
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: check-labels
|
||||
name: check-labels-validate-existing
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: check-labels
|
||||
name: check-labels-validate-existing
|
||||
spec:
|
||||
background: true
|
||||
rules:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
kubectl label po badpod foo=bar --overwrite
|
||||
if kubectl label po badpod foo=bad1 --overwrite 2>&1 | grep -q "validation error: rule check-labels"
|
||||
kubectl label po badpod-validate-existing foo=bar --overwrite
|
||||
if kubectl label po badpod-validate-existing foo=bad1 --overwrite 2>&1 | grep -q "validation error: rule check-labels"
|
||||
then
|
||||
echo "Test succeed, updating violating resource throws error"
|
||||
exit 0
|
||||
|
|
Loading…
Reference in a new issue