diff --git a/pkg/engine/mutation.go b/pkg/engine/mutation.go index 8f76efca9f..5e66b4d0e3 100644 --- a/pkg/engine/mutation.go +++ b/pkg/engine/mutation.go @@ -48,7 +48,7 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) { //TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that // dont statisfy a policy rule resource description if err := MatchesResourceDescription(resource, rule, policyContext.AdmissionInfo); err != nil { - logger.V(4).Info("resource fails the match description") + logger.V(4).Info("resource fails the match description", "reason", err.Error()) continue } diff --git a/pkg/engine/utils.go b/pkg/engine/utils.go index 4f2f7badec..035c2d5f07 100644 --- a/pkg/engine/utils.go +++ b/pkg/engine/utils.go @@ -18,6 +18,8 @@ import ( "k8s.io/apimachinery/pkg/labels" ) +var ExcludeRoles = []string{"system:nodes", "system:serviceaccounts:kube-system", "system:kube-scheduler"} + //EngineStats stores in the statistics for a single application of resource type EngineStats struct { // average time required to process the policy rules on a resource @@ -90,13 +92,18 @@ func doesResourceMatchConditionBlock(conditionBlock kyverno.ResourceDescription, } } } - if len(userInfo.Roles) > 0 { - if !doesSliceContainsAnyOfTheseValues(userInfo.Roles, admissionInfo.Roles...) { + + keys := append(admissionInfo.AdmissionUserInfo.Groups, admissionInfo.AdmissionUserInfo.Username) + + if len(userInfo.Roles) > 0 && + !DoesSliceContainsAnyOfTheseValues(keys, ExcludeRoles...) { + if !DoesSliceContainsAnyOfTheseValues(userInfo.Roles, admissionInfo.Roles...) { errs = append(errs, fmt.Errorf("user info does not match roles for the given conditionBlock")) } } - if len(userInfo.ClusterRoles) > 0 { - if !doesSliceContainsAnyOfTheseValues(userInfo.ClusterRoles, admissionInfo.ClusterRoles...) { + if len(userInfo.ClusterRoles) > 0 && + !DoesSliceContainsAnyOfTheseValues(keys, ExcludeRoles...) { + if !DoesSliceContainsAnyOfTheseValues(userInfo.ClusterRoles, admissionInfo.ClusterRoles...) { errs = append(errs, fmt.Errorf("user info does not match clustersRoles for the given conditionBlock")) } } @@ -142,7 +149,7 @@ func matchSubjects(ruleSubjects []rbacv1.Subject, userInfo authenticationv1.User return false } -func doesSliceContainsAnyOfTheseValues(slice []string, values ...string) bool { +func DoesSliceContainsAnyOfTheseValues(slice []string, values ...string) bool { var sliceElementsMap = make(map[string]bool, len(slice)) for _, sliceElement := range slice { diff --git a/pkg/engine/validation.go b/pkg/engine/validation.go index e7659069f1..0d28fcb32b 100644 --- a/pkg/engine/validation.go +++ b/pkg/engine/validation.go @@ -24,7 +24,14 @@ func Validate(policyContext PolicyContext) (resp response.EngineResponse) { oldR := policyContext.OldResource ctx := policyContext.Context admissionInfo := policyContext.AdmissionInfo - logger := log.Log.WithName("Validate").WithValues("policy", policy.Name, "kind", newR.GetKind(), "namespace", newR.GetNamespace(), "name", newR.GetName()) + logger := log.Log.WithName("Validate").WithValues("policy", policy.Name) + + if reflect.DeepEqual(newR, unstructured.Unstructured{}) { + logger = logger.WithValues("kind", oldR.GetKind(), "namespace", oldR.GetNamespace(), "name", oldR.GetName()) + } else { + logger = logger.WithValues("kind", newR.GetKind(), "namespace", newR.GetNamespace(), "name", newR.GetName()) + } + logger.V(4).Info("start processing", "startTime", startTime) defer func() { @@ -103,7 +110,7 @@ func isRequestDenied(log logr.Logger, ctx context.EvalInterface, policy kyverno. } if err := MatchesResourceDescription(resource, rule, admissionInfo); err != nil { - log.V(4).Info("resource fails the match description") + log.V(4).Info("resource fails the match description", "reason", err.Error()) continue } diff --git a/pkg/userinfo/roleRef.go b/pkg/userinfo/roleRef.go index d813f07f4e..f0c11f2fd0 100644 --- a/pkg/userinfo/roleRef.go +++ b/pkg/userinfo/roleRef.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/nirmata/kyverno/pkg/engine" v1beta1 "k8s.io/api/admission/v1beta1" authenticationv1 "k8s.io/api/authentication/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -20,6 +21,11 @@ const ( //GetRoleRef gets the list of roles and cluster roles for the incoming api-request func GetRoleRef(rbLister rbaclister.RoleBindingLister, crbLister rbaclister.ClusterRoleBindingLister, request *v1beta1.AdmissionRequest) (roles []string, clusterRoles []string, err error) { + keys := append(request.UserInfo.Groups, request.UserInfo.Username) + if engine.DoesSliceContainsAnyOfTheseValues(keys, engine.ExcludeRoles...) { + return + } + // rolebindings roleBindings, err := rbLister.List(labels.NewSelector()) if err != nil { @@ -101,7 +107,7 @@ func matchSubjectsMap(subject rbacv1.Subject, userInfo authenticationv1.UserInfo func matchServiceAccount(subject rbacv1.Subject, userInfo authenticationv1.UserInfo) bool { subjectServiceAccount := subject.Namespace + ":" + subject.Name if userInfo.Username[len(SaPrefix):] != subjectServiceAccount { - log.Log.V(3).Info(fmt.Sprintf("service account not match, expect %s, got %s", subjectServiceAccount, userInfo.Username[len(SaPrefix):])) + log.Log.V(6).Info(fmt.Sprintf("service account not match, expect %s, got %s", subjectServiceAccount, userInfo.Username[len(SaPrefix):])) return false } @@ -117,6 +123,6 @@ func matchUserOrGroup(subject rbacv1.Subject, userInfo authenticationv1.UserInfo } } - log.Log.V(3).Info(fmt.Sprintf("user/group '%v' info not found in request userInfo: %v", subject.Name, keys)) + log.Log.V(6).Info(fmt.Sprintf("user/group '%v' info not found in request userInfo: %v", subject.Name, keys)) return false } diff --git a/pkg/webhooks/mutation.go b/pkg/webhooks/mutation.go index 08db69c2b7..4ad5b35e94 100644 --- a/pkg/webhooks/mutation.go +++ b/pkg/webhooks/mutation.go @@ -52,7 +52,7 @@ func (ws *WebhookServer) HandleMutation( engineResponses = append(engineResponses, engineResponse) ws.statusListener.Send(mutateStats{resp: engineResponse}) if !engineResponse.IsSuccesful() { - logger.Info("failed to apply policy", "policy", policy.Name) + logger.Info("failed to apply policy", "policy", policy.Name, "failed rules", engineResponse.GetFailedRules()) continue } diff --git a/pkg/webhooks/server.go b/pkg/webhooks/server.go index cfd19d5bbc..4607639557 100644 --- a/pkg/webhooks/server.go +++ b/pkg/webhooks/server.go @@ -134,12 +134,11 @@ func NewWebhookServer( } mux := httprouter.New() - webhookTimeout := ws.webhookRegistrationClient.GetWebhookTimeOut() - mux.HandlerFunc("POST", config.MutatingWebhookServicePath, timeoutHandler(ws.handlerFunc(ws.resourceMutation, true), webhookTimeout)) - mux.HandlerFunc("POST", config.ValidatingWebhookServicePath, timeoutHandler(ws.handlerFunc(ws.resourceValidation, true), webhookTimeout)) - mux.HandlerFunc("POST", config.PolicyMutatingWebhookServicePath, timeoutHandler(ws.handlerFunc(ws.policyMutation, true), webhookTimeout)) - mux.HandlerFunc("POST", config.PolicyValidatingWebhookServicePath, timeoutHandler(ws.handlerFunc(ws.policyValidation, true), webhookTimeout)) - mux.HandlerFunc("POST", config.VerifyMutatingWebhookServicePath, timeoutHandler(ws.handlerFunc(ws.verifyHandler, false), webhookTimeout)) + 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)) + mux.HandlerFunc("POST", config.VerifyMutatingWebhookServicePath, ws.handlerFunc(ws.verifyHandler, false)) ws.server = http.Server{ Addr: ":443", // Listen on port for HTTPS requests diff --git a/pkg/webhooks/validation.go b/pkg/webhooks/validation.go index 2e0f885db3..6bd9ed1d25 100644 --- a/pkg/webhooks/validation.go +++ b/pkg/webhooks/validation.go @@ -14,6 +14,8 @@ import ( "github.com/nirmata/kyverno/pkg/engine/response" "github.com/nirmata/kyverno/pkg/policyviolation" v1beta1 "k8s.io/api/admission/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) // HandleValidation handles validating webhook admission request @@ -41,6 +43,17 @@ func (ws *WebhookServer) HandleValidation( return true, "" } + var deletionTimeStamp *metav1.Time + if reflect.DeepEqual(newR, unstructured.Unstructured{}) { + deletionTimeStamp = newR.GetDeletionTimestamp() + } else { + deletionTimeStamp = oldR.GetDeletionTimestamp() + } + + if deletionTimeStamp != nil && request.Operation == v1beta1.Update { + return true, "" + } + policyContext := engine.PolicyContext{ NewResource: newR, OldResource: oldR, @@ -63,7 +76,7 @@ func (ws *WebhookServer) HandleValidation( resp: engineResponse, }) if !engineResponse.IsSuccesful() { - logger.V(4).Info("failed to apply policy", "policy", policy.Name) + logger.V(4).Info("failed to apply policy", "policy", policy.Name, "failed rules", engineResponse.GetFailedRules()) continue }