mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-15 17:51:20 +00:00
Merge pull request #862 from realshuting/744_deny_requests
fix #838 - skip adding crd if no schema is defined
This commit is contained in:
commit
930811d457
12 changed files with 96 additions and 56 deletions
|
@ -46,9 +46,9 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
|
|||
|
||||
// check if the resource satisfies the filter conditions defined in the rule
|
||||
//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
|
||||
// dont satisfy 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
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ import (
|
|||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
var ExcludeUserInfo = []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 &&
|
||||
!utils.SliceContains(keys, ExcludeUserInfo...) {
|
||||
if !utils.SliceContains(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 &&
|
||||
!utils.SliceContains(keys, ExcludeUserInfo...) {
|
||||
if !utils.SliceContains(userInfo.ClusterRoles, admissionInfo.ClusterRoles...) {
|
||||
errs = append(errs, fmt.Errorf("user info does not match clustersRoles for the given conditionBlock"))
|
||||
}
|
||||
}
|
||||
|
@ -142,22 +149,6 @@ func matchSubjects(ruleSubjects []rbacv1.Subject, userInfo authenticationv1.User
|
|||
return false
|
||||
}
|
||||
|
||||
func doesSliceContainsAnyOfTheseValues(slice []string, values ...string) bool {
|
||||
|
||||
var sliceElementsMap = make(map[string]bool, len(slice))
|
||||
for _, sliceElement := range slice {
|
||||
sliceElementsMap[sliceElement] = true
|
||||
}
|
||||
|
||||
for _, value := range values {
|
||||
if sliceElementsMap[value] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
//MatchesResourceDescription checks if the resource matches resource description of the rule or not
|
||||
func MatchesResourceDescription(resourceRef unstructured.Unstructured, ruleRef kyverno.Rule, admissionInfoRef kyverno.RequestInfo) error {
|
||||
rule := *ruleRef.DeepCopy()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -141,7 +148,7 @@ func validateResource(log logr.Logger, ctx context.EvalInterface, policy kyverno
|
|||
|
||||
// check if the resource satisfies the filter conditions defined in the rule
|
||||
// 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
|
||||
// dont satisfy a policy rule resource description
|
||||
if err := MatchesResourceDescription(resource, rule, admissionInfo); err != nil {
|
||||
log.V(4).Info("resource fails the match description", "reason", err.Error())
|
||||
continue
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -138,6 +138,11 @@ func (o *Controller) parseCRD(crd unstructured.Unstructured) {
|
|||
}
|
||||
}
|
||||
|
||||
if openV3schema == nil {
|
||||
log.Log.V(3).Info("skip adding schema, CRD has no properties", "name", crdName)
|
||||
return
|
||||
}
|
||||
|
||||
schemaRaw, _ := json.Marshal(openV3schema)
|
||||
if len(schemaRaw) < 1 {
|
||||
log.Log.V(3).Info("could not parse crd schema", "name", crdName)
|
||||
|
|
|
@ -89,7 +89,7 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
|
|||
log logr.Logger) (*PolicyController, error) {
|
||||
// Event broad caster
|
||||
eventBroadcaster := record.NewBroadcaster()
|
||||
eventBroadcaster.StartLogging(log.Info)
|
||||
eventBroadcaster.StartLogging(log.V(5).Info)
|
||||
eventInterface, err := client.GetEventsInterface()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -4,6 +4,8 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/engine"
|
||||
"github.com/nirmata/kyverno/pkg/utils"
|
||||
v1beta1 "k8s.io/api/admission/v1beta1"
|
||||
authenticationv1 "k8s.io/api/authentication/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
|
@ -20,6 +22,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 utils.SliceContains(keys, engine.ExcludeUserInfo...) {
|
||||
return
|
||||
}
|
||||
|
||||
// rolebindings
|
||||
roleBindings, err := rbLister.List(labels.NewSelector())
|
||||
if err != nil {
|
||||
|
@ -101,10 +108,10 @@ 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):]))
|
||||
return false
|
||||
}
|
||||
|
||||
log.Log.V(3).Info(fmt.Sprintf("found a matched service account not match: %s", subjectServiceAccount))
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -113,10 +120,10 @@ func matchUserOrGroup(subject rbacv1.Subject, userInfo authenticationv1.UserInfo
|
|||
keys := append(userInfo.Groups, userInfo.Username)
|
||||
for _, key := range keys {
|
||||
if subject.Name == key {
|
||||
log.Log.V(3).Info(fmt.Sprintf("found a matched user/group '%v' in request userInfo: %v", subject.Name, keys))
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
log.Log.V(3).Info(fmt.Sprintf("user/group '%v' info not found in request userInfo: %v", subject.Name, keys))
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -173,3 +173,19 @@ func HigherThanKubernetesVersion(client *client.Client, log logr.Logger, k8smajo
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func SliceContains(slice []string, values ...string) bool {
|
||||
|
||||
var sliceElementsMap = make(map[string]bool, len(slice))
|
||||
for _, sliceElement := range slice {
|
||||
sliceElementsMap[sliceElement] = true
|
||||
}
|
||||
|
||||
for _, value := range values {
|
||||
if sliceElementsMap[value] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ func (wrc *WebhookRegistrationClient) CreateResourceMutatingWebhookConfiguration
|
|||
}
|
||||
_, err := wrc.client.CreateResource(MutatingWebhookConfigurationKind, "", *config, false)
|
||||
if errorsapi.IsAlreadyExists(err) {
|
||||
logger.V(4).Info("resource mutating webhook configuration already exists. not creating one", "name", config.Name)
|
||||
logger.V(6).Info("resource mutating webhook configuration already exists", "name", config.Name)
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -145,7 +145,7 @@ func (wrc *WebhookRegistrationClient) CreateResourceValidatingWebhookConfigurati
|
|||
|
||||
_, err := wrc.client.CreateResource(ValidatingWebhookConfigurationKind, "", *config, false)
|
||||
if errorsapi.IsAlreadyExists(err) {
|
||||
logger.V(4).Info("resource already exists. not create one")
|
||||
logger.V(6).Info("resource validating webhook configuration already exists", "name", config.Name)
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue