diff --git a/cmd/kyverno/main.go b/cmd/kyverno/main.go index d8b87f11dc..2f59d073db 100644 --- a/cmd/kyverno/main.go +++ b/cmd/kyverno/main.go @@ -278,7 +278,7 @@ func main() { // Sync openAPI definitions of resources openAPISync := openapi.NewCRDSync(client, openAPIController) - supportMudateValidate := utils.HigherThanKubernetesVersion(client, log.Log, 1, 14, 0) + supportMutateValidate := utils.HigherThanKubernetesVersion(client, log.Log, 1, 14, 0) // WEBHOOK // - https server to provide endpoints called based on rules defined in Mutating & Validation webhook configuration @@ -304,7 +304,7 @@ func main() { grgen, rWebhookWatcher, auditHandler, - supportMudateValidate, + supportMutateValidate, cleanUp, log.Log.WithName("WebhookServer"), openAPIController, diff --git a/pkg/kyverno/apply/command.go b/pkg/kyverno/apply/command.go index 7cf27230c6..208532b370 100644 --- a/pkg/kyverno/apply/command.go +++ b/pkg/kyverno/apply/command.go @@ -5,8 +5,12 @@ import ( "errors" "fmt" "io/ioutil" + + "github.com/nirmata/kyverno/pkg/engine/context" + "os" "path/filepath" + "strings" "time" @@ -50,7 +54,8 @@ func Command() *cobra.Command { var cmd *cobra.Command var resourcePaths []string var cluster bool - var mutateLogPath string + var mutatelogPath, variablesString string + variables := make(map[string]string) kubernetesConfig := genericclioptions.NewConfigFlags(true) @@ -63,11 +68,17 @@ func Command() *cobra.Command { if err != nil { if !sanitizedError.IsErrorSanitized(err) { log.Log.Error(err, "failed to sanitize") - err = fmt.Errorf("Internal error") + err = fmt.Errorf("internal error") } } }() + kvpairs := strings.Split(strings.Trim(variablesString, " "), ",") + for _, kvpair := range kvpairs { + kvs := strings.Split(strings.Trim(kvpair, " "), "=") + variables[strings.Trim(kvs[0], " ")] = strings.Trim(kvs[1], " ") + } + if len(resourcePaths) == 0 && !cluster { return sanitizedError.NewWithError(fmt.Sprintf("resource file(s) or cluster required"), err) } @@ -150,7 +161,7 @@ func Command() *cobra.Command { } for _, resource := range resources { - applyPolicyOnResource(policy, resource, rc) + err = applyPolicyOnResource(policy, resource, mutatelogPath, mutatelogPathIsDir, variables, rc) if err != nil { return sanitizedError.NewWithError(fmt.Errorf("failed to apply policy %v on resource %v", policy.Name, resource.GetName()).Error(), err) } @@ -170,7 +181,8 @@ func Command() *cobra.Command { cmd.Flags().StringArrayVarP(&resourcePaths, "resource", "r", []string{}, "Path to resource files") cmd.Flags().BoolVarP(&cluster, "cluster", "c", false, "Checks if policies should be applied to cluster in the current context") - cmd.Flags().StringVarP(&mutateLogPath, "output", "o", "", "Prints the mutated resources in provided file/directory") + cmd.Flags().StringVarP(&mutatelogPath, "output", "o", "", "Prints the mutated resources in provided file/directory") + cmd.Flags().StringVarP(&variablesString, "set", "s", "", "Variables that are required") return cmd } @@ -300,13 +312,29 @@ func getResource(path string) ([]*unstructured.Unstructured, error) { } // applyPolicyOnResource - function to apply policy on resource -func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unstructured, rc *resultCounts) { +func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unstructured, mutatelogPath string, mutatelogPathIsDir bool, variables map[string]string, rc *resultCounts) error { responseError := false resPath := fmt.Sprintf("%s/%s/%s", resource.GetNamespace(), resource.GetKind(), resource.GetName()) log.Log.V(3).Info("applying policy on resource", "policy", policy.Name, "resource", resPath) - mutateResponse := engine.Mutate(engine.PolicyContext{Policy: *policy, NewResource: *resource}) + // build context + ctx := context.NewContext() + for key, value := range variables { + startString := "" + endString := "" + for _, k := range strings.Split(key, ".") { + startString += fmt.Sprintf(`{"%s":`, k) + endString += `}` + } + + midString := fmt.Sprintf(`"%s"`, value) + finalString := startString + midString + endString + var jsonData = []byte(finalString) + ctx.AddJSON(jsonData) + } + + mutateResponse := engine.Mutate(engine.PolicyContext{Policy: *policy, NewResource: *resource, Context: ctx}) if !mutateResponse.IsSuccessful() { fmt.Printf("Failed to apply mutate policy %s -> resource %s", policy.Name, resPath) for i, r := range mutateResponse.PolicyResponse.Rules { @@ -329,7 +357,7 @@ func applyPolicyOnResource(policy *v1.ClusterPolicy, resource *unstructured.Unst } } - validateResponse := engine.Validate(engine.PolicyContext{Policy: *policy, NewResource: mutateResponse.PatchedResource}) + validateResponse := engine.Validate(engine.PolicyContext{Policy: *policy, NewResource: mutateResponse.PatchedResource, Context: ctx}) if !validateResponse.IsSuccessful() { fmt.Printf("\npolicy %s -> resource %s failed: \n", policy.Name, resPath) for i, r := range validateResponse.PolicyResponse.Rules { diff --git a/pkg/kyverno/common/common.go b/pkg/kyverno/common/common.go index afe45f46cd..0f736d1e81 100644 --- a/pkg/kyverno/common/common.go +++ b/pkg/kyverno/common/common.go @@ -9,7 +9,6 @@ import ( "io/ioutil" "os" "path/filepath" - "regexp" jsonpatch "github.com/evanphx/json-patch" "github.com/go-logr/logr" @@ -69,10 +68,10 @@ func GetPolicies(paths []string) (policies []*v1.ClusterPolicy, error error) { } } - for i := range policies { - setFalse := false - policies[i].Spec.Background = &setFalse - } + // for i := range policies { + // setFalse := false + // policies[i].Spec.Background = &setFalse + // } return policies, nil } @@ -152,11 +151,11 @@ func GetPoliciesValidation(policyPaths []string) ([]*v1.ClusterPolicy, *openapi. } // PolicyHasVariables - check for variables in policy -func PolicyHasVariables(policy v1.ClusterPolicy) bool { - policyRaw, _ := json.Marshal(policy) - regex := regexp.MustCompile(`\{\{([^{}]*)\}\}`) - return len(regex.FindAllStringSubmatch(string(policyRaw), -1)) > 0 -} +// func PolicyHasVariables(policy v1.ClusterPolicy) bool { +// policyRaw, _ := json.Marshal(policy) +// regex := regexp.MustCompile(`\{\{([^{}]*)\}\}`) +// return len(regex.FindAllStringSubmatch(string(policyRaw), -1)) > 0 +// } // MutatePolicy - applies mutation to a policy func MutatePolicy(policy *v1.ClusterPolicy, logger logr.Logger) (*v1.ClusterPolicy, error) { diff --git a/pkg/kyverno/validate/command.go b/pkg/kyverno/validate/command.go index 41ababbb29..8744c19535 100644 --- a/pkg/kyverno/validate/command.go +++ b/pkg/kyverno/validate/command.go @@ -49,12 +49,12 @@ func Command() *cobra.Command { invalidPolicyFound := false for _, policy := range policies { - if common.PolicyHasVariables(*policy) { - invalidPolicyFound = true - fmt.Printf("Policy %s is invalid.\n", policy.Name) - log.Log.Error(errors.New("'validate' does not support policies with variables"), "Policy "+policy.Name+" is invalid") - continue - } + // if common.PolicyHasVariables(*policy) { + // invalidPolicyFound = true + // fmt.Printf("Policy %s is invalid.\n", policy.Name) + // log.Log.Error(errors.New("'validate' does not support policies with variables"), "Policy "+policy.Name+" is invalid") + // continue + // } err := policy2.Validate(utils.MarshalPolicy(*policy), nil, true, openAPIController) if err != nil { fmt.Printf("Policy %s is invalid.\n", policy.Name) diff --git a/pkg/policymutation/policymutation.go b/pkg/policymutation/policymutation.go index 5cc5c2b4a5..c0cf128c70 100644 --- a/pkg/policymutation/policymutation.go +++ b/pkg/policymutation/policymutation.go @@ -79,7 +79,7 @@ func defaultvalidationFailureAction(policy *kyverno.ClusterPolicy, log logr.Logg // set ValidationFailureAction to "audit" if not specified Audit := common.Audit if policy.Spec.ValidationFailureAction == "" { - log.V(4).Info("setting defautl value", "spec.validationFailureAction", Audit) + log.V(4).Info("setting default value", "spec.validationFailureAction", Audit) jsonPatch := struct { Path string `json:"path"` diff --git a/pkg/webhooks/policymutation.go b/pkg/webhooks/policymutation.go index 995490f4c1..b6f738f396 100644 --- a/pkg/webhooks/policymutation.go +++ b/pkg/webhooks/policymutation.go @@ -18,7 +18,7 @@ func (ws *WebhookServer) policyMutation(request *v1beta1.AdmissionRequest) *v1be //TODO: can this happen? wont this be picked by OpenAPI spec schema ? if err := json.Unmarshal(raw, &policy); err != nil { - logger.Error(err, "faield to unmarshall policy admission request") + logger.Error(err, "failed to unmarshall policy admission request") return &v1beta1.AdmissionResponse{ Allowed: true, Result: &metav1.Status{ diff --git a/pkg/webhooks/server.go b/pkg/webhooks/server.go index 0af3eb2bbc..b25c8a547d 100644 --- a/pkg/webhooks/server.go +++ b/pkg/webhooks/server.go @@ -110,7 +110,7 @@ type WebhookServer struct { log logr.Logger openAPIController *openapi.Controller - supportMudateValidate bool + supportMutateValidate bool } // NewWebhookServer creates new instance of WebhookServer accordingly to given configuration @@ -133,7 +133,7 @@ func NewWebhookServer( grGenerator *generate.Generator, resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister, auditHandler AuditHandler, - supportMudateValidate bool, + supportMutateValidate bool, cleanUp chan<- struct{}, log logr.Logger, openAPIController *openapi.Controller, @@ -177,11 +177,11 @@ func NewWebhookServer( auditHandler: auditHandler, log: log, openAPIController: openAPIController, - supportMudateValidate: supportMudateValidate, + supportMutateValidate: supportMutateValidate, } mux := httprouter.New() - mux.HandlerFunc("POST", config.MutatingWebhookServicePath, ws.handlerFunc(ws.resourceMutation, true)) + mux.HandlerFunc("POST", config.MutatingWebhookServicePath, ws.handlerFunc(ws.ResourceMutation, true)) mux.HandlerFunc("POST", config.ValidatingWebhookServicePath, ws.handlerFunc(ws.resourceValidation, true)) mux.HandlerFunc("POST", config.PolicyMutatingWebhookServicePath, ws.handlerFunc(ws.policyMutation, true)) mux.HandlerFunc("POST", config.PolicyValidatingWebhookServicePath, ws.handlerFunc(ws.policyValidation, true)) @@ -260,9 +260,9 @@ func writeResponse(rw http.ResponseWriter, admissionReview *v1beta1.AdmissionRev } } -func (ws *WebhookServer) resourceMutation(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse { +func (ws *WebhookServer) ResourceMutation(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse { - logger := ws.log.WithName("resourceMutation").WithValues("uid", request.UID, "kind", request.Kind.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation) + logger := ws.log.WithName("ResourceMutation").WithValues("uid", request.UID, "kind", request.Kind.Kind, "namespace", request.Namespace, "name", request.Name, "operation", request.Operation) if excludeKyvernoResources(request.Kind.Kind) { return &v1beta1.AdmissionResponse{ @@ -329,7 +329,7 @@ func (ws *WebhookServer) resourceMutation(request *v1beta1.AdmissionRequest) *v1 var patches []byte patchedResource := request.Object.Raw - if ws.supportMudateValidate { + if ws.supportMutateValidate { // MUTATION // mutation failure should not block the resource creation // any mutation failure is reported as the violation @@ -398,7 +398,7 @@ func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) * } } - if !ws.supportMudateValidate { + if !ws.supportMutateValidate { logger.Info("mutate and validate rules are not supported prior to Kubernetes 1.14.0") return &v1beta1.AdmissionResponse{ Allowed: true,