diff --git a/pkg/cache/cluster.go b/pkg/cache/cluster.go index 1b820a678..20bb840dc 100644 --- a/pkg/cache/cluster.go +++ b/pkg/cache/cluster.go @@ -24,8 +24,6 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/dynamic" - "k8s.io/client-go/kubernetes" - authType1 "k8s.io/client-go/kubernetes/typed/authorization/v1" "k8s.io/client-go/rest" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/pager" @@ -477,10 +475,6 @@ func (c *clusterCache) startMissingWatches() error { if err != nil { return err } - clientset, err := kubernetes.NewForConfig(c.config) - if err != nil { - return err - } namespacedResources := make(map[schema.GroupKind]bool) for i := range apis { api := apis[i] @@ -491,10 +485,14 @@ func (c *clusterCache) startMissingWatches() error { err := c.processApi(client, api, func(resClient dynamic.ResourceInterface, ns string) error { resourceVersion, err := c.loadInitialState(ctx, api, resClient, ns) - if err != nil && c.respectRBAC != RespectRbacDisabled && (k8sErrors.IsForbidden(err) || k8sErrors.IsUnauthorized(err)) { + if err != nil && c.isRestrictedResource(err) { keep := false if c.respectRBAC == RespectRbacStrict { - k, permErr := c.checkPermission(ctx, clientset.AuthorizationV1().SelfSubjectAccessReviews(), api) + k, permErr := c.checkPermission(ctx, client.Resource(schema.GroupVersionResource{ + Group: "authorization.k8s.io", + Version: "v1", + Resource: "SelfSubjectAccessReviews", + }), api) if permErr != nil { return fmt.Errorf("failed to check permissions for resource %s: %w, original error=%v", api.GroupKind.String(), permErr, err.Error()) } @@ -741,9 +739,16 @@ func (c *clusterCache) processApi(client dynamic.Interface, api kube.APIResource return nil } +// isRestrictedResource checks if the kube api call is unauthorized or forbidden +func (c *clusterCache) isRestrictedResource(err error) bool { + c.log.Info("checkingggg restrictedddd") + return c.respectRBAC != RespectRbacDisabled && (k8sErrors.IsForbidden(err) || k8sErrors.IsUnauthorized(err)) +} + // checkPermission runs a self subject access review to check if the controller has permissions to list the resource -func (c *clusterCache) checkPermission(ctx context.Context, reviewInterface authType1.SelfSubjectAccessReviewInterface, api kube.APIResourceInfo) (keep bool, err error) { - sar := &authorizationv1.SelfSubjectAccessReview{ +func (c *clusterCache) checkPermission(ctx context.Context, reviewInterface dynamic.ResourceInterface, api kube.APIResourceInfo) (keep bool, err error) { + c.log.Info("checkingggg permmm") + sar, err := kube.ToUnstructured(&authorizationv1.SelfSubjectAccessReview{ Spec: authorizationv1.SelfSubjectAccessReviewSpec{ ResourceAttributes: &authorizationv1.ResourceAttributes{ Namespace: "*", @@ -751,6 +756,9 @@ func (c *clusterCache) checkPermission(ctx context.Context, reviewInterface auth Resource: api.GroupVersionResource.Resource, }, }, + }) + if err != nil { + return false, err } switch { @@ -760,23 +768,33 @@ func (c *clusterCache) checkPermission(ctx context.Context, reviewInterface auth if err != nil { return true, err } - if resp != nil && resp.Status.Allowed { - return true, nil + if resp != nil { + allowed, ok, err := unstructured.NestedBool(resp.Object, "status", "allowed") + if err != nil || !ok { + return true, fmt.Errorf("failed to read self subject access review response, err: %v", err) + } + return allowed, nil + } else { + // unsupported, remove from watch list + return false, nil } - // unsupported, remove from watch list - return false, nil // if manage some namespaces and resource is namespaced case len(c.namespaces) != 0 && api.Meta.Namespaced: for _, ns := range c.namespaces { - sar.Spec.ResourceAttributes.Namespace = ns + if err := unstructured.SetNestedField(sar.Object, ns, "spec", "resourceAttributes", "namespace"); err != nil { + return false, err + } resp, err := reviewInterface.Create(ctx, sar, metav1.CreateOptions{}) if err != nil { - return true, err + return false, err } - if resp != nil && resp.Status.Allowed { - return true, nil + if resp != nil { + allowed, ok, err := unstructured.NestedBool(resp.Object, "status", "allowed") + if err != nil || !ok { + return true, fmt.Errorf("failed to read self subject access review response, err: %v", err) + } + return allowed, nil } else { - // unsupported, remove from watch list return false, nil } } @@ -832,10 +850,6 @@ func (c *clusterCache) sync() error { if err != nil { return err } - clientset, err := kubernetes.NewForConfig(config) - if err != nil { - return err - } lock := sync.Mutex{} err = kube.RunAllAsync(len(apis), func(i int) error { api := apis[i] @@ -861,10 +875,14 @@ func (c *clusterCache) sync() error { }) }) if err != nil { - if c.respectRBAC != RespectRbacDisabled && (k8sErrors.IsForbidden(err) || k8sErrors.IsUnauthorized(err)) { + if c.isRestrictedResource(err) { keep := false if c.respectRBAC == RespectRbacStrict { - k, permErr := c.checkPermission(ctx, clientset.AuthorizationV1().SelfSubjectAccessReviews(), api) + k, permErr := c.checkPermission(ctx, client.Resource(schema.GroupVersionResource{ + Group: "authorization.k8s.io", + Version: "v1", + Resource: "SelfSubjectAccessReviews", + }), api) if permErr != nil { return fmt.Errorf("failed to check permissions for resource %s: %w, original error=%v", api.GroupKind.String(), permErr, err.Error()) }