AuthZ: Redirect legacy resource permissions handler to k8s (part I) (#114199)

* Add K8s API redirect for GET resource permissions

* wire

* move restconfig to options

* address comments

* fix helper after adding RestConfigProvider

* Revert K8s redirect changes for service accounts, teams, and receivers

Keep only dashboard and folder redirect functionality for this PR.
Service accounts, teams, and receivers will be handled in a separate PR.

* address comments

* lint
This commit is contained in:
mohammad-hamid
2025-12-04 10:04:23 -05:00
committed by GitHub
parent ae4d2324d6
commit 3c5d905e0f
9 changed files with 222 additions and 21 deletions
@@ -11,8 +11,11 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/apiserver"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/team"
"github.com/grafana/grafana/pkg/services/user"
@@ -23,20 +26,22 @@ import (
var tracer = otel.Tracer("github.com/grafana/grafana/pkg/accesscontrol/resourcepermissions")
type api struct {
cfg *setting.Cfg
ac accesscontrol.AccessControl
router routing.RouteRegister
service *Service
permissions []string
cfg *setting.Cfg
ac accesscontrol.AccessControl
router routing.RouteRegister
service *Service
permissions []string
features featuremgmt.FeatureToggles
restConfigProvider apiserver.RestConfigProvider
}
func newApi(cfg *setting.Cfg, ac accesscontrol.AccessControl, router routing.RouteRegister, manager *Service) *api {
func newApi(cfg *setting.Cfg, ac accesscontrol.AccessControl, router routing.RouteRegister, manager *Service, features featuremgmt.FeatureToggles, restConfigProvider apiserver.RestConfigProvider) *api {
permissions := make([]string, 0, len(manager.permissions))
// reverse the permissions order for display
for i := len(manager.permissions) - 1; i >= 0; i-- {
permissions = append(permissions, manager.permissions[i])
}
return &api{cfg, ac, router, manager, permissions}
return &api{cfg, ac, router, manager, permissions, features, restConfigProvider}
}
func (a *api) registerEndpoints() {
@@ -176,6 +181,22 @@ func (a *api) getPermissions(c *contextmodel.ReqContext) response.Response {
resourceID := web.Params(c.Req)[":resourceID"]
//nolint:staticcheck // not yet migrated to OpenFeature
if a.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthZHandlerRedirect) &&
a.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthzResourcePermissionApis) {
k8sPermissions, err := a.getResourcePermissionsFromK8s(c.Req.Context(), c.Namespace, resourceID)
if err == nil {
return response.JSON(http.StatusOK, k8sPermissions)
}
span.RecordError(err)
logger := log.New("resource-permissions-api")
if errors.Is(err, ErrRestConfigNotAvailable) {
logger.Debug("k8s API not available for resource permissions, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource)
} else {
logger.Warn("Failed to get resource permissions from k8s API, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource)
}
}
permissions, err := a.service.GetPermissions(c.Req.Context(), c.SignedInUser, resourceID)
if err != nil {
return response.ErrOrFallback(http.StatusInternalServerError, "Failed to get permissions", err)