From c32002837dc25bf5e611c57c1900ed34007ca9f0 Mon Sep 17 00:00:00 2001 From: Pooja Singh Date: Sat, 2 Oct 2021 00:09:29 +0530 Subject: [PATCH] supporting request object for generate policies (#2455) * supporting request object for generate policies Signed-off-by: NoSkillGirl * updated naming for operation Signed-off-by: NoSkillGirl * run make kustomize-crd Signed-off-by: NoSkillGirl --- charts/kyverno/templates/crds.yaml | 10 +++++++++ .../crds/kyverno.io_generaterequests.yaml | 10 +++++++++ definitions/install.yaml | 10 +++++++++ definitions/install_debug.yaml | 10 +++++++++ pkg/api/kyverno/v1/generaterequest_types.go | 10 +++++++++ pkg/generate/generate.go | 17 +++++++++++++++ pkg/generate/generate_controller.go | 3 +++ pkg/webhooks/generation.go | 21 ++++++++++++++----- 8 files changed, 86 insertions(+), 5 deletions(-) diff --git a/charts/kyverno/templates/crds.yaml b/charts/kyverno/templates/crds.yaml index 68561fe05a..59926fc198 100644 --- a/charts/kyverno/templates/crds.yaml +++ b/charts/kyverno/templates/crds.yaml @@ -2043,6 +2043,16 @@ spec: context: description: Context ... properties: + admissionRequestInfo: + description: Adding required request information to GR + properties: + admissionRequest: + description: Adding Admission Request to GR. + type: string + operation: + description: Current request operation + type: string + type: object userInfo: description: RequestInfo contains permission info carried in an admission request. properties: diff --git a/definitions/crds/kyverno.io_generaterequests.yaml b/definitions/crds/kyverno.io_generaterequests.yaml index 9e7072c42d..6ae8b54882 100644 --- a/definitions/crds/kyverno.io_generaterequests.yaml +++ b/definitions/crds/kyverno.io_generaterequests.yaml @@ -108,6 +108,16 @@ spec: type: string type: object type: object + admissionRequestInfo: + description: Adding required request information to GR + properties: + admissionRequest: + description: Adding Admission Request to GR. + type: string + operation: + description: Current request operation + type: string + type: object type: object policy: description: Specifies the name of the policy. diff --git a/definitions/install.yaml b/definitions/install.yaml index 3ce90b1a74..afe0e7c041 100644 --- a/definitions/install.yaml +++ b/definitions/install.yaml @@ -3029,6 +3029,16 @@ spec: context: description: Context ... properties: + admissionRequestInfo: + description: Adding required request information to GR + properties: + admissionRequest: + description: Adding Admission Request to GR. + type: string + operation: + description: Current request operation + type: string + type: object userInfo: description: RequestInfo contains permission info carried in an admission request. diff --git a/definitions/install_debug.yaml b/definitions/install_debug.yaml index 7c2f4a6aa3..63431b9574 100755 --- a/definitions/install_debug.yaml +++ b/definitions/install_debug.yaml @@ -2995,6 +2995,16 @@ spec: context: description: Context ... properties: + admissionRequestInfo: + description: Adding required request information to GR + properties: + admissionRequest: + description: Adding Admission Request to GR. + type: string + operation: + description: Current request operation + type: string + type: object userInfo: description: RequestInfo contains permission info carried in an admission request. diff --git a/pkg/api/kyverno/v1/generaterequest_types.go b/pkg/api/kyverno/v1/generaterequest_types.go index 7311c32d4d..8f1f53452f 100644 --- a/pkg/api/kyverno/v1/generaterequest_types.go +++ b/pkg/api/kyverno/v1/generaterequest_types.go @@ -1,6 +1,7 @@ package v1 import ( + "k8s.io/api/admission/v1beta1" authenticationv1 "k8s.io/api/authentication/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -45,6 +46,15 @@ type GenerateRequestSpec struct { type GenerateRequestContext struct { // +optional UserRequestInfo RequestInfo `json:"userInfo,omitempty" yaml:"userInfo,omitempty"` + // +optional + AdmissionRequestInfo AdmissionRequestInfoObject `json:"admissionRequestInfo,omitempty" yaml:"admissionRequestInfo,omitempty"` +} + +type AdmissionRequestInfoObject struct { + // +optional + AdmissionRequest string `json:"admissionRequest,omitempty" yaml:"admissionRequest,omitempty"` + // +optional + Operation v1beta1.Operation `json:"operation,omitempty" yaml:"operation,omitempty"` } // RequestInfo contains permission info carried in an admission request. diff --git a/pkg/generate/generate.go b/pkg/generate/generate.go index bae06323e3..ccc3c66a38 100644 --- a/pkg/generate/generate.go +++ b/pkg/generate/generate.go @@ -19,6 +19,7 @@ import ( "github.com/kyverno/kyverno/pkg/engine/utils" "github.com/kyverno/kyverno/pkg/engine/variables" kyvernoutils "github.com/kyverno/kyverno/pkg/utils" + "k8s.io/api/admission/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -99,6 +100,22 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern return nil, err } + requestString := gr.Spec.Context.AdmissionRequestInfo.AdmissionRequest + var request v1beta1.AdmissionRequest + err = json.Unmarshal([]byte(requestString), &request) + if err != nil { + logger.Error(err, "error parsing the request string") + } + + if gr.Spec.Context.AdmissionRequestInfo.Operation == v1beta1.Update { + request.Operation = gr.Spec.Context.AdmissionRequestInfo.Operation + } + + if err := ctx.AddRequest(&request); err != nil { + logger.Error(err, "failed to load request in context") + return nil, err + } + resourceRaw, err := resource.MarshalJSON() if err != nil { logger.Error(err, "failed to marshal resource") diff --git a/pkg/generate/generate_controller.go b/pkg/generate/generate_controller.go index 2e4bbafe1c..a2648832dc 100644 --- a/pkg/generate/generate_controller.go +++ b/pkg/generate/generate_controller.go @@ -4,6 +4,7 @@ import ( "reflect" "time" + "k8s.io/api/admission/v1beta1" "k8s.io/client-go/kubernetes" "github.com/go-logr/logr" @@ -230,6 +231,7 @@ func (c *Controller) updateGenericResource(old, cur interface{}) { // re-evaluate the GR as the resource was updated for _, gr := range grs { + gr.Spec.Context.AdmissionRequestInfo.Operation = v1beta1.Update c.enqueueGenerateRequest(gr) } } @@ -286,6 +288,7 @@ func (c *Controller) updatePolicy(old, cur interface{}) { // re-evaluate the GR as the policy was updated for _, gr := range grs { + gr.Spec.Context.AdmissionRequestInfo.Operation = v1beta1.Update c.enqueueGenerateRequest(gr) } } diff --git a/pkg/webhooks/generation.go b/pkg/webhooks/generation.go index d208a3569a..a644bd2ca7 100644 --- a/pkg/webhooks/generation.go +++ b/pkg/webhooks/generation.go @@ -7,6 +7,7 @@ import ( "strings" "time" + "github.com/gardener/controller-manager-library/pkg/logger" "github.com/go-logr/logr" kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1" @@ -107,7 +108,7 @@ func (ws *WebhookServer) handleGenerate( } // Adds Generate Request to a channel(queue size 1000) to generators - if failedResponse := applyGenerateRequest(ws.grGenerator, userRequestInfo, request.Operation, engineResponses...); err != nil { + if failedResponse := applyGenerateRequest(request, ws.grGenerator, userRequestInfo, request.Operation, engineResponses...); err != nil { // report failure event for _, failedGR := range failedResponse { events := failedEvents(fmt.Errorf("failed to create Generate Request: %v", failedGR.err), failedGR.gr, new) @@ -418,11 +419,20 @@ func (ws *WebhookServer) deleteGR(logger logr.Logger, engineResponse *response.E } } -func applyGenerateRequest(gnGenerator generate.GenerateRequests, userRequestInfo kyverno.RequestInfo, +func applyGenerateRequest(request *v1beta1.AdmissionRequest, gnGenerator generate.GenerateRequests, userRequestInfo kyverno.RequestInfo, action v1beta1.Operation, engineResponses ...*response.EngineResponse) (failedGenerateRequest []generateRequestResponse) { + requestBytes, err := json.Marshal(request) + if err != nil { + logger.Error(err, "error loading request into context") + } + admissionRequestInfo := kyverno.AdmissionRequestInfoObject{ + AdmissionRequest: string(requestBytes), + Operation: action, + } + for _, er := range engineResponses { - gr := transform(userRequestInfo, er) + gr := transform(admissionRequestInfo, userRequestInfo, er) if err := gnGenerator.Apply(gr, action); err != nil { failedGenerateRequest = append(failedGenerateRequest, generateRequestResponse{gr: gr, err: err}) } @@ -431,7 +441,7 @@ func applyGenerateRequest(gnGenerator generate.GenerateRequests, userRequestInfo return } -func transform(userRequestInfo kyverno.RequestInfo, er *response.EngineResponse) kyverno.GenerateRequestSpec { +func transform(admissionRequestInfo kyverno.AdmissionRequestInfoObject, userRequestInfo kyverno.RequestInfo, er *response.EngineResponse) kyverno.GenerateRequestSpec { gr := kyverno.GenerateRequestSpec{ Policy: er.PolicyResponse.Policy.Name, Resource: kyverno.ResourceSpec{ @@ -441,7 +451,8 @@ func transform(userRequestInfo kyverno.RequestInfo, er *response.EngineResponse) APIVersion: er.PolicyResponse.Resource.APIVersion, }, Context: kyverno.GenerateRequestContext{ - UserRequestInfo: userRequestInfo, + UserRequestInfo: userRequestInfo, + AdmissionRequestInfo: admissionRequestInfo, }, }