mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
fix: CEL policies aren't applied to deleted resources (#10611)
Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
This commit is contained in:
parent
1647675190
commit
ad6ee93e3b
29 changed files with 167 additions and 22 deletions
|
@ -47,11 +47,6 @@ func (h validateCELHandler) Process(
|
||||||
_ engineapi.EngineContextLoader,
|
_ engineapi.EngineContextLoader,
|
||||||
exceptions []*kyvernov2.PolicyException,
|
exceptions []*kyvernov2.PolicyException,
|
||||||
) (unstructured.Unstructured, []engineapi.RuleResponse) {
|
) (unstructured.Unstructured, []engineapi.RuleResponse) {
|
||||||
if engineutils.IsDeleteRequest(policyContext) {
|
|
||||||
logger.V(3).Info("skipping CEL validation on deleted resource")
|
|
||||||
return resource, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if there is a policy exception matches the incoming resource
|
// check if there is a policy exception matches the incoming resource
|
||||||
exception := engineutils.MatchesException(exceptions, policyContext, logger)
|
exception := engineutils.MatchesException(exceptions, policyContext, logger)
|
||||||
if exception != nil {
|
if exception != nil {
|
||||||
|
@ -76,16 +71,12 @@ func (h validateCELHandler) Process(
|
||||||
|
|
||||||
// get resource's name, namespace, GroupVersionResource, and GroupVersionKind
|
// get resource's name, namespace, GroupVersionResource, and GroupVersionKind
|
||||||
gvr := schema.GroupVersionResource(policyContext.RequestResource())
|
gvr := schema.GroupVersionResource(policyContext.RequestResource())
|
||||||
gvk := resource.GroupVersionKind()
|
gvk, _ := policyContext.ResourceKind()
|
||||||
namespaceName := resource.GetNamespace()
|
|
||||||
resourceName := resource.GetName()
|
|
||||||
resourceKind, _ := policyContext.ResourceKind()
|
|
||||||
policyKind := policyContext.Policy().GetKind()
|
policyKind := policyContext.Policy().GetKind()
|
||||||
policyName := policyContext.Policy().GetName()
|
policyName := policyContext.Policy().GetName()
|
||||||
|
|
||||||
object := resource.DeepCopyObject()
|
// in case of UPDATE requests, set the oldObject to the current resource before it gets updated
|
||||||
// in case of update request, set the oldObject to the current resource before it gets updated
|
var object, oldObject runtime.Object
|
||||||
var oldObject runtime.Object
|
|
||||||
oldResource := policyContext.OldResource()
|
oldResource := policyContext.OldResource()
|
||||||
if oldResource.Object == nil {
|
if oldResource.Object == nil {
|
||||||
oldObject = nil
|
oldObject = nil
|
||||||
|
@ -93,6 +84,18 @@ func (h validateCELHandler) Process(
|
||||||
oldObject = oldResource.DeepCopyObject()
|
oldObject = oldResource.DeepCopyObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ns, name string
|
||||||
|
// in case of DELETE request, get the name and the namespace from the old object
|
||||||
|
if resource.Object == nil {
|
||||||
|
ns = oldResource.GetNamespace()
|
||||||
|
name = oldResource.GetName()
|
||||||
|
object = nil
|
||||||
|
} else {
|
||||||
|
ns = resource.GetNamespace()
|
||||||
|
name = resource.GetName()
|
||||||
|
object = resource.DeepCopyObject()
|
||||||
|
}
|
||||||
|
|
||||||
// check if the rule uses parameter resources
|
// check if the rule uses parameter resources
|
||||||
hasParam := rule.Validation.CEL.HasParam()
|
hasParam := rule.Validation.CEL.HasParam()
|
||||||
// extract preconditions written as CEL expressions
|
// extract preconditions written as CEL expressions
|
||||||
|
@ -129,11 +132,11 @@ func (h validateCELHandler) Process(
|
||||||
// Special case, the namespace object has the namespace of itself.
|
// Special case, the namespace object has the namespace of itself.
|
||||||
// unset it if the incoming object is a namespace
|
// unset it if the incoming object is a namespace
|
||||||
if gvk.Kind == "Namespace" && gvk.Version == "v1" && gvk.Group == "" {
|
if gvk.Kind == "Namespace" && gvk.Version == "v1" && gvk.Group == "" {
|
||||||
namespaceName = ""
|
ns = ""
|
||||||
}
|
}
|
||||||
if namespaceName != "" {
|
if ns != "" {
|
||||||
if h.client != nil {
|
if h.client != nil {
|
||||||
namespace, err = h.client.GetNamespace(ctx, namespaceName, metav1.GetOptions{})
|
namespace, err = h.client.GetNamespace(ctx, ns, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resource, handlers.WithResponses(
|
return resource, handlers.WithResponses(
|
||||||
engineapi.RuleError(rule.Name, engineapi.Validation, "Error getting the resource's namespace", err),
|
engineapi.RuleError(rule.Name, engineapi.Validation, "Error getting the resource's namespace", err),
|
||||||
|
@ -142,7 +145,7 @@ func (h validateCELHandler) Process(
|
||||||
} else {
|
} else {
|
||||||
namespace = &corev1.Namespace{
|
namespace = &corev1.Namespace{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: namespaceName,
|
Name: ns,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,16 +153,20 @@ func (h validateCELHandler) Process(
|
||||||
|
|
||||||
requestInfo := policyContext.AdmissionInfo()
|
requestInfo := policyContext.AdmissionInfo()
|
||||||
userInfo := internal.NewUser(requestInfo.AdmissionUserInfo.Username, requestInfo.AdmissionUserInfo.UID, requestInfo.AdmissionUserInfo.Groups)
|
userInfo := internal.NewUser(requestInfo.AdmissionUserInfo.Username, requestInfo.AdmissionUserInfo.UID, requestInfo.AdmissionUserInfo.Groups)
|
||||||
admissionAttributes := admission.NewAttributesRecord(object, oldObject, gvk, namespaceName, resourceName, gvr, "", admission.Operation(policyContext.Operation()), nil, false, &userInfo)
|
attr := admission.NewAttributesRecord(object, oldObject, gvk, ns, name, gvr, "", admission.Operation(policyContext.Operation()), nil, false, &userInfo)
|
||||||
versionedAttr, _ := admission.NewVersionedAttributes(admissionAttributes, admissionAttributes.GetKind(), nil)
|
o := admission.NewObjectInterfacesFromScheme(runtime.NewScheme())
|
||||||
authorizer := internal.NewAuthorizer(h.client, resourceKind)
|
versionedAttr, err := admission.NewVersionedAttributes(attr, attr.GetKind(), o)
|
||||||
|
if err != nil {
|
||||||
|
return resource, handlers.WithError(rule, engineapi.Validation, "error while creating versioned attributes", err)
|
||||||
|
}
|
||||||
|
authorizer := internal.NewAuthorizer(h.client, gvk)
|
||||||
// validate the incoming object against the rule
|
// validate the incoming object against the rule
|
||||||
var validationResults []validating.ValidateResult
|
var validationResults []validating.ValidateResult
|
||||||
if hasParam {
|
if hasParam {
|
||||||
paramKind := rule.Validation.CEL.ParamKind
|
paramKind := rule.Validation.CEL.ParamKind
|
||||||
paramRef := rule.Validation.CEL.ParamRef
|
paramRef := rule.Validation.CEL.ParamRef
|
||||||
|
|
||||||
params, err := collectParams(ctx, h.client, paramKind, paramRef, namespaceName)
|
params, err := collectParams(ctx, h.client, paramKind, paramRef, ns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resource, handlers.WithResponses(
|
return resource, handlers.WithResponses(
|
||||||
engineapi.RuleError(rule.Name, engineapi.Validation, "error in parameterized resource", err),
|
engineapi.RuleError(rule.Name, engineapi.Validation, "error in parameterized resource", err),
|
||||||
|
|
|
@ -14,6 +14,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Pod
|
- Pod
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
message: "hostPort must either be unset or set to 0"
|
message: "hostPort must either be unset or set to 0"
|
||||||
cel:
|
cel:
|
||||||
|
|
|
@ -13,6 +13,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Pod
|
- Pod
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
validationFailureAction: Enforce
|
validationFailureAction: Enforce
|
||||||
message: "hostPort must either be unset or set to 0"
|
message: "hostPort must either be unset or set to 0"
|
||||||
|
|
|
@ -12,6 +12,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Pod
|
- Pod
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
cel:
|
cel:
|
||||||
expressions:
|
expressions:
|
||||||
|
|
|
@ -12,6 +12,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Deployment
|
- Deployment
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
cel:
|
cel:
|
||||||
expressions:
|
expressions:
|
||||||
|
|
|
@ -12,6 +12,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Pod
|
- Pod
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
celPreconditions:
|
celPreconditions:
|
||||||
- name: "first match condition in CEL"
|
- name: "first match condition in CEL"
|
||||||
expression: "object.metadata.name.matches('nginx-pod')"
|
expression: "object.metadata.name.matches('nginx-pod')"
|
||||||
|
|
|
@ -12,6 +12,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Deployment
|
- Deployment
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
cel:
|
cel:
|
||||||
variables:
|
variables:
|
||||||
|
|
|
@ -12,6 +12,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- StatefulSet
|
- StatefulSet
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
cel:
|
cel:
|
||||||
expressions:
|
expressions:
|
||||||
|
|
|
@ -14,6 +14,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Pod
|
- Pod
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
cel:
|
cel:
|
||||||
expressions:
|
expressions:
|
||||||
|
|
|
@ -12,6 +12,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Namespace
|
- Namespace
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
cel:
|
cel:
|
||||||
paramKind:
|
paramKind:
|
||||||
|
|
|
@ -12,6 +12,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Namespace
|
- Namespace
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
cel:
|
cel:
|
||||||
paramKind:
|
paramKind:
|
||||||
|
|
|
@ -12,6 +12,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Deployment
|
- Deployment
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
cel:
|
cel:
|
||||||
paramKind:
|
paramKind:
|
||||||
|
|
|
@ -12,6 +12,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- StatefulSet
|
- StatefulSet
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
cel:
|
cel:
|
||||||
paramKind:
|
paramKind:
|
||||||
|
|
|
@ -11,6 +11,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Pod
|
- Pod
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
validationFailureAction: Enforce
|
validationFailureAction: Enforce
|
||||||
cel:
|
cel:
|
||||||
|
|
|
@ -11,6 +11,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Deployment
|
- Deployment
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
validationFailureAction: Enforce
|
validationFailureAction: Enforce
|
||||||
cel:
|
cel:
|
||||||
|
|
|
@ -11,6 +11,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Pod
|
- Pod
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
celPreconditions:
|
celPreconditions:
|
||||||
- name: "first match condition in CEL"
|
- name: "first match condition in CEL"
|
||||||
expression: "object.metadata.name.matches('nginx-pod')"
|
expression: "object.metadata.name.matches('nginx-pod')"
|
||||||
|
|
|
@ -11,6 +11,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Deployment
|
- Deployment
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
validationFailureAction: Enforce
|
validationFailureAction: Enforce
|
||||||
cel:
|
cel:
|
||||||
|
|
|
@ -11,6 +11,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- StatefulSet
|
- StatefulSet
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
validationFailureAction: Enforce
|
validationFailureAction: Enforce
|
||||||
cel:
|
cel:
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This test creates a policy that uses CEL expressions to deny the creation/deletion/update of any pod.
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
Any pod creation/deletion/update is blocked.
|
||||||
|
|
||||||
|
## Reference Issue(s)
|
||||||
|
|
||||||
|
10576
|
|
@ -0,0 +1,32 @@
|
||||||
|
apiVersion: chainsaw.kyverno.io/v1alpha1
|
||||||
|
kind: Test
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
name: deny
|
||||||
|
spec:
|
||||||
|
steps:
|
||||||
|
- name: step-01
|
||||||
|
try:
|
||||||
|
- script:
|
||||||
|
content: kubectl run nginx --image=nginx
|
||||||
|
- name: step-02
|
||||||
|
try:
|
||||||
|
- apply:
|
||||||
|
file: policy.yaml
|
||||||
|
- assert:
|
||||||
|
file: policy-assert.yaml
|
||||||
|
- name: step-03
|
||||||
|
try:
|
||||||
|
- script:
|
||||||
|
content: "if kubectl run --image=busybox foo\nthen \n exit 1\nelse \n exit
|
||||||
|
0\nfi\n"
|
||||||
|
- name: step-04
|
||||||
|
try:
|
||||||
|
- script:
|
||||||
|
content: "if kubectl label pod nginx app=nginx\nthen \n exit 1\nelse \n exit
|
||||||
|
0\nfi\n"
|
||||||
|
- name: step-05
|
||||||
|
try:
|
||||||
|
- script:
|
||||||
|
content: "if kubectl delete pod nginx\nthen \n exit 1\nelse \n exit
|
||||||
|
0\nfi\n"
|
|
@ -0,0 +1,9 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: restrict-operations-on-pod
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- reason: Succeeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
|
@ -0,0 +1,19 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: restrict-operations-on-pod
|
||||||
|
spec:
|
||||||
|
validationFailureAction: Enforce
|
||||||
|
background: true
|
||||||
|
rules:
|
||||||
|
- name: rule-1
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Pod
|
||||||
|
validate:
|
||||||
|
cel:
|
||||||
|
expressions:
|
||||||
|
- expression: "false"
|
||||||
|
message: Create, update and delete on pods is not allowed
|
|
@ -1,10 +1,11 @@
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Pod
|
kind: Pod
|
||||||
metadata:
|
metadata:
|
||||||
name: webserver
|
name: webserver-2
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: webserver
|
- name: webserver
|
||||||
image: nginx:latest
|
image: nginx:latest
|
||||||
ports:
|
ports:
|
||||||
- hostPort: 80
|
- hostPort: 80
|
||||||
|
containerPort: 80
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Pod
|
kind: Pod
|
||||||
metadata:
|
metadata:
|
||||||
name: webserver
|
name: webserver-1
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: webserver
|
- name: webserver
|
||||||
|
|
|
@ -13,6 +13,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Pod
|
- Pod
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
validationFailureAction: Enforce
|
validationFailureAction: Enforce
|
||||||
cel:
|
cel:
|
||||||
|
|
|
@ -11,6 +11,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Namespace
|
- Namespace
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
validationFailureAction: Enforce
|
validationFailureAction: Enforce
|
||||||
cel:
|
cel:
|
||||||
|
|
|
@ -11,6 +11,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Namespace
|
- Namespace
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
validationFailureAction: Enforce
|
validationFailureAction: Enforce
|
||||||
cel:
|
cel:
|
||||||
|
|
|
@ -11,6 +11,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- Deployment
|
- Deployment
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
validationFailureAction: Enforce
|
validationFailureAction: Enforce
|
||||||
cel:
|
cel:
|
||||||
|
|
|
@ -11,6 +11,9 @@ spec:
|
||||||
- resources:
|
- resources:
|
||||||
kinds:
|
kinds:
|
||||||
- StatefulSet
|
- StatefulSet
|
||||||
|
operations:
|
||||||
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
validate:
|
validate:
|
||||||
validationFailureAction: Enforce
|
validationFailureAction: Enforce
|
||||||
cel:
|
cel:
|
||||||
|
|
Loading…
Add table
Reference in a new issue