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:
@@ -442,7 +442,7 @@ func setupServer(b testing.TB, sc benchScenario, features featuremgmt.FeatureTog
|
||||
features, tracing.InitializeTracerForTest(), sc.db, permreg.ProvidePermissionRegistry(), nil,
|
||||
)
|
||||
folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions(
|
||||
cfg, features, routing.NewRouteRegister(), sc.db, ac, license, folderServiceWithFlagOn, acSvc, sc.teamSvc, sc.userSvc, actionSets)
|
||||
cfg, features, routing.NewRouteRegister(), sc.db, ac, license, folderServiceWithFlagOn, acSvc, sc.teamSvc, sc.userSvc, actionSets, apiserver.WithoutRestConfig)
|
||||
require.NoError(b, err)
|
||||
dashboardSvc, err := dashboardservice.ProvideDashboardServiceImpl(
|
||||
sc.cfg,
|
||||
@@ -474,7 +474,7 @@ func setupServer(b testing.TB, sc benchScenario, features featuremgmt.FeatureTog
|
||||
require.NoError(b, err)
|
||||
|
||||
_, err = ossaccesscontrol.ProvideDashboardPermissions(
|
||||
cfg, features, routing.NewRouteRegister(), sc.db, ac, license, dashboardSvc, folderServiceWithFlagOn, acSvc, sc.teamSvc, sc.userSvc, actionSets, dashboardSvc)
|
||||
cfg, features, routing.NewRouteRegister(), sc.db, ac, license, dashboardSvc, folderServiceWithFlagOn, acSvc, sc.teamSvc, sc.userSvc, actionSets, dashboardSvc, apiserver.WithoutRestConfig)
|
||||
require.NoError(b, err)
|
||||
|
||||
starSvc := startest.NewStarServiceFake()
|
||||
|
||||
Generated
+4
-4
@@ -584,7 +584,7 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
|
||||
}
|
||||
filestoreService := filestore.ProvideService(inMemory)
|
||||
fileStoreManager := dashboards.ProvideFileStoreManager(pluginstoreService, filestoreService)
|
||||
folderPermissionsService, err := ossaccesscontrol.ProvideFolderPermissions(cfg, featureToggles, routeRegisterImpl, sqlStore, accessControl, ossLicensingService, folderimplService, acimplService, teamService, userService, actionSetService)
|
||||
folderPermissionsService, err := ossaccesscontrol.ProvideFolderPermissions(cfg, featureToggles, routeRegisterImpl, sqlStore, accessControl, ossLicensingService, folderimplService, acimplService, teamService, userService, actionSetService, eventualRestConfigProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -715,7 +715,7 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api
|
||||
pluginassetsService := pluginassets2.ProvideService(pluginManagementCfg, pluginscdnService, signatureSignature, pluginstoreService)
|
||||
avatarCacheServer := avatar.ProvideAvatarCacheServer(cfg)
|
||||
prefService := prefimpl.ProvideService(sqlStore, cfg)
|
||||
dashboardPermissionsService, err := ossaccesscontrol.ProvideDashboardPermissions(cfg, featureToggles, routeRegisterImpl, sqlStore, accessControl, ossLicensingService, dashboardService, folderimplService, acimplService, teamService, userService, actionSetService, dashboardServiceImpl)
|
||||
dashboardPermissionsService, err := ossaccesscontrol.ProvideDashboardPermissions(cfg, featureToggles, routeRegisterImpl, sqlStore, accessControl, ossLicensingService, dashboardService, folderimplService, acimplService, teamService, userService, actionSetService, dashboardServiceImpl, eventualRestConfigProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1235,7 +1235,7 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
|
||||
}
|
||||
filestoreService := filestore.ProvideService(inMemory)
|
||||
fileStoreManager := dashboards.ProvideFileStoreManager(pluginstoreService, filestoreService)
|
||||
folderPermissionsService, err := ossaccesscontrol.ProvideFolderPermissions(cfg, featureToggles, routeRegisterImpl, sqlStore, accessControl, ossLicensingService, folderimplService, acimplService, teamService, userService, actionSetService)
|
||||
folderPermissionsService, err := ossaccesscontrol.ProvideFolderPermissions(cfg, featureToggles, routeRegisterImpl, sqlStore, accessControl, ossLicensingService, folderimplService, acimplService, teamService, userService, actionSetService, eventualRestConfigProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1368,7 +1368,7 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac
|
||||
pluginassetsService := pluginassets2.ProvideService(pluginManagementCfg, pluginscdnService, signatureSignature, pluginstoreService)
|
||||
avatarCacheServer := avatar.ProvideAvatarCacheServer(cfg)
|
||||
prefService := prefimpl.ProvideService(sqlStore, cfg)
|
||||
dashboardPermissionsService, err := ossaccesscontrol.ProvideDashboardPermissions(cfg, featureToggles, routeRegisterImpl, sqlStore, accessControl, ossLicensingService, dashboardService, folderimplService, acimplService, teamService, userService, actionSetService, dashboardServiceImpl)
|
||||
dashboardPermissionsService, err := ossaccesscontrol.ProvideDashboardPermissions(cfg, featureToggles, routeRegisterImpl, sqlStore, accessControl, ossLicensingService, dashboardService, folderimplService, acimplService, teamService, userService, actionSetService, dashboardServiceImpl, eventualRestConfigProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -4,12 +4,14 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
dashboardv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
@@ -99,7 +101,7 @@ func ProvideDashboardPermissions(
|
||||
cfg *setting.Cfg, features featuremgmt.FeatureToggles, router routing.RouteRegister, sql db.DB, ac accesscontrol.AccessControl,
|
||||
license licensing.Licensing, dashboardService dashboards.DashboardService, folderService folder.Service, service accesscontrol.Service,
|
||||
teamService team.Service, userService user.Service, actionSetService resourcepermissions.ActionSetService,
|
||||
dashboardPermissionsRegistration dashboards.PermissionsRegistrationService,
|
||||
dashboardPermissionsRegistration dashboards.PermissionsRegistrationService, restConfigProvider apiserver.RestConfigProvider,
|
||||
) (*DashboardPermissionsService, error) {
|
||||
getDashboard := func(ctx context.Context, orgID int64, resourceID string) (*dashboards.Dashboard, error) {
|
||||
query := &dashboards.GetDashboardQuery{UID: resourceID, OrgID: orgID}
|
||||
@@ -117,6 +119,7 @@ func ProvideDashboardPermissions(
|
||||
options := resourcepermissions.Options{
|
||||
Resource: "dashboards",
|
||||
ResourceAttribute: "uid",
|
||||
APIGroup: dashboardv1.APIGroup,
|
||||
ResourceValidator: func(ctx context.Context, orgID int64, resourceID string) error {
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.ossaccesscontrol.ProvideDashboardPermissions.ResourceValidator")
|
||||
defer span.End()
|
||||
@@ -166,9 +169,10 @@ func ProvideDashboardPermissions(
|
||||
"Edit": getDashboardEditActions(features),
|
||||
"Admin": getDashboardAdminActions(features),
|
||||
},
|
||||
ReaderRoleName: "Permission reader",
|
||||
WriterRoleName: "Permission writer",
|
||||
RoleGroup: "Dashboards",
|
||||
ReaderRoleName: "Permission reader",
|
||||
WriterRoleName: "Permission writer",
|
||||
RoleGroup: "Dashboards",
|
||||
RestConfigProvider: restConfigProvider,
|
||||
}
|
||||
|
||||
srv, err := resourcepermissions.New(cfg, options, features, router, license, ac, service, sql, teamService, userService, actionSetService)
|
||||
|
||||
@@ -4,12 +4,14 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
folderv1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
@@ -90,6 +92,7 @@ func ProvideFolderPermissions(
|
||||
cfg *setting.Cfg, features featuremgmt.FeatureToggles, router routing.RouteRegister, sql db.DB, accesscontrol accesscontrol.AccessControl,
|
||||
license licensing.Licensing, folderService folder.Service, service accesscontrol.Service,
|
||||
teamService team.Service, userService user.Service, actionSetService resourcepermissions.ActionSetService,
|
||||
restConfigProvider apiserver.RestConfigProvider,
|
||||
) (*FolderPermissionsService, error) {
|
||||
if err := registerFolderRoles(cfg, features, service); err != nil {
|
||||
return nil, err
|
||||
@@ -98,6 +101,7 @@ func ProvideFolderPermissions(
|
||||
options := resourcepermissions.Options{
|
||||
Resource: "folders",
|
||||
ResourceAttribute: "uid",
|
||||
APIGroup: folderv1.APIGroup,
|
||||
ResourceValidator: func(ctx context.Context, orgID int64, resourceID string) error {
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.ossaccesscontrol.ProvideFolderPermissions.ResourceValidator")
|
||||
defer span.End()
|
||||
@@ -139,9 +143,10 @@ func ProvideFolderPermissions(
|
||||
"Edit": append(getDashboardEditActions(features), FolderEditActions...),
|
||||
"Admin": append(getDashboardAdminActions(features), FolderAdminActions...),
|
||||
},
|
||||
ReaderRoleName: "Permission reader",
|
||||
WriterRoleName: "Permission writer",
|
||||
RoleGroup: "Folders",
|
||||
ReaderRoleName: "Permission reader",
|
||||
WriterRoleName: "Permission writer",
|
||||
RoleGroup: "Folders",
|
||||
RestConfigProvider: restConfigProvider,
|
||||
}
|
||||
srv, err := resourcepermissions.New(cfg, options, features, router, license, accesscontrol, service, sql, teamService, userService, actionSetService)
|
||||
if err != nil {
|
||||
|
||||
@@ -93,5 +93,6 @@ func ProvideFolderPermissions(
|
||||
teamSvc,
|
||||
userSvc,
|
||||
actionSets,
|
||||
apiserver.WithoutRestConfig,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
package resourcepermissions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/authlib/types"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/dynamic"
|
||||
|
||||
iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/team"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
)
|
||||
|
||||
var ErrRestConfigNotAvailable = errors.New("k8s rest config provider not available")
|
||||
|
||||
func (a *api) getDynamicClient(ctx context.Context) (dynamic.Interface, error) {
|
||||
if a.restConfigProvider == nil {
|
||||
return nil, ErrRestConfigNotAvailable
|
||||
}
|
||||
|
||||
restConfig, err := a.restConfigProvider.GetRestConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get rest config: %w", err)
|
||||
}
|
||||
|
||||
dynamicClient, err := dynamic.NewForConfig(restConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create dynamic client: %w", err)
|
||||
}
|
||||
|
||||
return dynamicClient, nil
|
||||
}
|
||||
|
||||
func (a *api) getResourcePermissionsFromK8s(ctx context.Context, namespace string, resourceID string) (getResourcePermissionsResponse, error) {
|
||||
dynamicClient, err := a.getDynamicClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resourcePermName := a.buildResourcePermissionName(resourceID)
|
||||
|
||||
resourcePermResource := dynamicClient.Resource(iamv0.ResourcePermissionInfo.GroupVersionResource()).Namespace(namespace)
|
||||
unstructuredObj, err := resourcePermResource.Get(ctx, resourcePermName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if k8serrors.IsNotFound(err) {
|
||||
return getResourcePermissionsResponse{}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("failed to get resource permission from k8s: %w", err)
|
||||
}
|
||||
|
||||
var resourcePerm iamv0.ResourcePermission
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructuredObj.Object, &resourcePerm); err != nil {
|
||||
return nil, fmt.Errorf("failed to convert to typed resource permission: %w", err)
|
||||
}
|
||||
|
||||
return a.convertK8sResourcePermissionToDTO(&resourcePerm, namespace)
|
||||
}
|
||||
|
||||
func (a *api) convertK8sResourcePermissionToDTO(resourcePerm *iamv0.ResourcePermission, namespace string) (getResourcePermissionsResponse, error) {
|
||||
permissions := resourcePerm.Spec.Permissions
|
||||
if len(permissions) == 0 {
|
||||
return getResourcePermissionsResponse{}, nil
|
||||
}
|
||||
|
||||
namespaceInfo, err := types.ParseNamespace(namespace)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse namespace %q: %w", namespace, err)
|
||||
}
|
||||
orgID := namespaceInfo.OrgID
|
||||
|
||||
dto := make(getResourcePermissionsResponse, 0, len(permissions))
|
||||
|
||||
for _, perm := range permissions {
|
||||
kind := perm.Kind
|
||||
name := perm.Name
|
||||
verb := perm.Verb
|
||||
|
||||
if name == "" || verb == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
permission := cases.Title(language.Und).String(verb)
|
||||
actions, exists := a.service.options.PermissionsToActions[permission]
|
||||
if !exists {
|
||||
log.New("resource-permissions-api").Warn(
|
||||
"Permission not found in PermissionsToActions map",
|
||||
"permission", permission,
|
||||
"resource", a.service.options.Resource,
|
||||
"availablePermissions", fmt.Sprintf("%v", getMapKeys(a.service.options.PermissionsToActions)),
|
||||
)
|
||||
actions = []string{}
|
||||
}
|
||||
|
||||
permDTO := resourcePermissionDTO{
|
||||
Permission: permission,
|
||||
Actions: actions,
|
||||
IsManaged: true,
|
||||
IsInherited: false,
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case iamv0.ResourcePermissionSpecPermissionKindUser, iamv0.ResourcePermissionSpecPermissionKindServiceAccount:
|
||||
userDetails, err := a.service.userService.GetByUID(context.Background(), &user.GetUserByUIDQuery{UID: name})
|
||||
if err == nil {
|
||||
permDTO.UserID = userDetails.ID
|
||||
permDTO.UserUID = userDetails.UID
|
||||
permDTO.UserLogin = userDetails.Login
|
||||
permDTO.UserAvatarUrl = dtos.GetGravatarUrl(a.cfg, userDetails.Email)
|
||||
permDTO.IsServiceAccount = userDetails.IsServiceAccount
|
||||
permDTO.RoleName = fmt.Sprintf("managed:users:%d:permissions", userDetails.ID)
|
||||
}
|
||||
case iamv0.ResourcePermissionSpecPermissionKindTeam:
|
||||
teamDetails, err := a.service.teamService.GetTeamByID(context.Background(), &team.GetTeamByIDQuery{
|
||||
UID: name,
|
||||
OrgID: orgID,
|
||||
})
|
||||
if err == nil {
|
||||
permDTO.Team = teamDetails.Name
|
||||
permDTO.TeamID = teamDetails.ID
|
||||
permDTO.TeamUID = teamDetails.UID
|
||||
permDTO.TeamAvatarUrl = dtos.GetGravatarUrlWithDefault(a.cfg, teamDetails.Email, teamDetails.Name)
|
||||
permDTO.RoleName = fmt.Sprintf("managed:teams:%d:permissions", teamDetails.ID)
|
||||
} else {
|
||||
permDTO.TeamUID = name
|
||||
permDTO.Team = name
|
||||
}
|
||||
case iamv0.ResourcePermissionSpecPermissionKindBasicRole:
|
||||
permDTO.BuiltInRole = name
|
||||
permDTO.RoleName = fmt.Sprintf("managed:builtins:%s:permissions", name)
|
||||
}
|
||||
|
||||
dto = append(dto, permDTO)
|
||||
}
|
||||
|
||||
return dto, nil
|
||||
}
|
||||
|
||||
func (a *api) getAPIGroup() string {
|
||||
if a.service.options.APIGroup != "" {
|
||||
return a.service.options.APIGroup
|
||||
}
|
||||
return fmt.Sprintf("%s.grafana.app", a.service.options.Resource)
|
||||
}
|
||||
|
||||
func getMapKeys(m map[string][]string) []string {
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func (a *api) buildResourcePermissionName(resourceID string) string {
|
||||
return fmt.Sprintf("%s-%s-%s", a.getAPIGroup(), a.service.options.Resource, resourceID)
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
|
||||
@@ -16,6 +17,9 @@ type Options struct {
|
||||
Resource string
|
||||
// ResourceAttribute is the attribute the scope should be based on (e.g. id or uid)
|
||||
ResourceAttribute string
|
||||
// APIGroup is the Kubernetes API group for the resource (e.g. "folder.grafana.app")
|
||||
// If not set, defaults to "{Resource}.grafana.app"
|
||||
APIGroup string
|
||||
// OnlyManaged will tell the service to return all permissions if set to false and only managed permissions if set to true
|
||||
OnlyManaged bool
|
||||
// ResourceTranslator is a translator function that will be called before each action, it can be used to translate a resource id to a different format.
|
||||
@@ -45,4 +49,6 @@ type Options struct {
|
||||
InheritedScopesSolver InheritedScopesSolver
|
||||
// LicenseMV if configured is applied to endpoints that can modify permissions
|
||||
LicenseMW web.Handler
|
||||
// RestConfigProvider if configured enables K8s API redirect for resource permissions
|
||||
RestConfigProvider apiserver.RestConfigProvider
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ func New(cfg *setting.Cfg,
|
||||
actionSetSvc: actionSetService,
|
||||
}
|
||||
|
||||
s.api = newApi(cfg, ac, router, s)
|
||||
s.api = newApi(cfg, ac, router, s, features, s.options.RestConfigProvider)
|
||||
|
||||
if err := s.declareFixedRoles(); err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user