From c593b20465eb2b326091f1d97dd3a0d5330c397e Mon Sep 17 00:00:00 2001 From: Karl Persson <23356117+kalleep@users.noreply.github.com> Date: Fri, 10 Jan 2025 11:49:26 +0100 Subject: [PATCH] Zanana: Add custom verb for get_permissions and set_permissions. (#98616) * Add custom verb for get_permissions and update_permissions. Co-authored-by: Alexander Zobnin --- pkg/apimachinery/utils/verbs.go | 4 ++ pkg/services/accesscontrol/authorizer.go | 2 + pkg/services/authz/mappers/rbac_mapper.go | 70 ++++++++++--------- pkg/services/authz/zanzana/common/tuple.go | 33 ++++++--- .../authz/zanzana/schema/schema_core.fga | 9 ++- .../authz/zanzana/schema/schema_folder.fga | 3 + .../authz/zanzana/schema/schema_resource.fga | 9 +++ 7 files changed, 87 insertions(+), 43 deletions(-) diff --git a/pkg/apimachinery/utils/verbs.go b/pkg/apimachinery/utils/verbs.go index 7ab5086332f..2616f8f5e77 100644 --- a/pkg/apimachinery/utils/verbs.go +++ b/pkg/apimachinery/utils/verbs.go @@ -19,4 +19,8 @@ const ( VerbDelete = "delete" // VerbDelete is mapped from HTTP DELETE for collections VerbDeleteCollection = "deletecollection" + // VerbGetPermissions is used when fetching resource specific permissions + VerbGetPermissions = "get_permissions" + // VerbSetPermissions is used when setting resource specific permissions + VerbSetPermissions = "set_permissions" ) diff --git a/pkg/services/accesscontrol/authorizer.go b/pkg/services/accesscontrol/authorizer.go index cb14390e83a..007ba2c30b5 100644 --- a/pkg/services/accesscontrol/authorizer.go +++ b/pkg/services/accesscontrol/authorizer.go @@ -60,6 +60,8 @@ func NewLegacyAccessClient(ac AccessControl, opts ...ResourceAuthorizerOptions) utils.VerbPatch: fmt.Sprintf("%s:write", r), utils.VerbDelete: fmt.Sprintf("%s:delete", r), utils.VerbDeleteCollection: fmt.Sprintf("%s:delete", r), + utils.VerbGetPermissions: fmt.Sprintf("%s.permissions:read", r), + utils.VerbSetPermissions: fmt.Sprintf("%s.permissions:write", r), } } diff --git a/pkg/services/authz/mappers/rbac_mapper.go b/pkg/services/authz/mappers/rbac_mapper.go index fa9a1a1a4eb..86b97b95ef0 100644 --- a/pkg/services/authz/mappers/rbac_mapper.go +++ b/pkg/services/authz/mappers/rbac_mapper.go @@ -1,41 +1,52 @@ package mappers -type VerbToAction map[string]string // e.g. "get" -> "read" -type ResourceVerbToAction map[string]VerbToAction // e.g. "dashboards" -> VerbToAction -type GroupResourceVerbToAction map[string]ResourceVerbToAction // e.g. "dashboard.grafana.app" -> ResourceVerbToAction +import ( + "fmt" -type ResourceToAttribute map[string]string // e.g. "dashboards" -> "uid" -type GroupResourceToAttribute map[string]ResourceToAttribute // e.g. "dashboard.grafana.app" -> ResourceToAttribute + "github.com/grafana/grafana/pkg/apimachinery/utils" +) + +const defaultAttribute = "uid" + +type VerbMapping map[string]string // e.g. "get" -> "read" +type ResourceVerbMapping map[string]VerbMapping // e.g. "dashboards" -> VerbToAction +type GroupResourceVerbMapping map[string]ResourceVerbMapping // e.g. "dashboard.grafana.app" -> ResourceVerbToAction + +type ResourceAttributeMapping map[string]string // e.g. "dashboards" -> "uid" +type GroupResourceAttributeMapping map[string]ResourceAttributeMapping // e.g. "dashboard.grafana.app" -> ResourceToAttribute type K8sRbacMapper struct { - DefaultActions VerbToAction - DefaultAttribute string - Actions GroupResourceVerbToAction - Attributes GroupResourceToAttribute + GroupResourceVerbMapping GroupResourceVerbMapping + GroupResourceAttributeMapping GroupResourceAttributeMapping } func NewK8sRbacMapper() *K8sRbacMapper { + defaultMapping := func(r string) VerbMapping { + return map[string]string{ + utils.VerbGet: fmt.Sprintf("%s:read", r), + utils.VerbList: fmt.Sprintf("%s:read", r), + utils.VerbWatch: fmt.Sprintf("%s:read", r), + utils.VerbCreate: fmt.Sprintf("%s:create", r), + utils.VerbUpdate: fmt.Sprintf("%s:write", r), + utils.VerbPatch: fmt.Sprintf("%s:write", r), + utils.VerbDelete: fmt.Sprintf("%s:delete", r), + utils.VerbDeleteCollection: fmt.Sprintf("%s:delete", r), + utils.VerbGetPermissions: fmt.Sprintf("%s.permissions:read", r), + utils.VerbSetPermissions: fmt.Sprintf("%s.permissions:write", r), + } + } + return &K8sRbacMapper{ - DefaultActions: VerbToAction{ - "get": "read", - "list": "read", - "watch": "read", - "create": "create", - "update": "write", - "patch": "write", - "delete": "delete", - "deletecollection": "delete", - }, - DefaultAttribute: "uid", - Actions: GroupResourceVerbToAction{ - "dashboard.grafana.app": ResourceVerbToAction{"dashboards": VerbToAction{}}, - "folder.grafana.app": ResourceVerbToAction{"folders": VerbToAction{}}, + GroupResourceAttributeMapping: GroupResourceAttributeMapping{}, + GroupResourceVerbMapping: GroupResourceVerbMapping{ + "dashboard.grafana.app": ResourceVerbMapping{"dashboards": defaultMapping("dashboards")}, + "folder.grafana.app": ResourceVerbMapping{"folders": defaultMapping("folders")}, }, } } func (m *K8sRbacMapper) Action(group, resource, verb string) (string, bool) { - if resourceActions, ok := m.Actions[group]; ok { + if resourceActions, ok := m.GroupResourceVerbMapping[group]; ok { if actions, ok := resourceActions[resource]; ok { if action, ok := actions[verb]; ok { // If the action is explicitly set empty @@ -45,22 +56,17 @@ func (m *K8sRbacMapper) Action(group, resource, verb string) (string, bool) { } return action, true } - if defaultAction, ok := m.DefaultActions[verb]; ok { - return resource + ":" + defaultAction, true - } } } return "", false } func (m *K8sRbacMapper) Scope(group, resource, name string) (string, bool) { - if resourceAttributes, ok := m.Attributes[group]; ok { + if resourceAttributes, ok := m.GroupResourceAttributeMapping[group]; ok { if attribute, ok := resourceAttributes[resource]; ok { return resource + ":" + attribute + ":" + name, true } } - if m.DefaultAttribute != "" { - return resource + ":" + m.DefaultAttribute + ":" + name, true - } - return "", false + + return resource + ":" + defaultAttribute + ":" + name, true } diff --git a/pkg/services/authz/zanzana/common/tuple.go b/pkg/services/authz/zanzana/common/tuple.go index 3e15c9f97fa..cde3eac0fcb 100644 --- a/pkg/services/authz/zanzana/common/tuple.go +++ b/pkg/services/authz/zanzana/common/tuple.go @@ -43,14 +43,19 @@ const ( RelationCreate string = "create" RelationDelete string = "delete" + RelationGetPermissions string = "get_permissions" + RelationSetPermissions string = "set_permissions" + RelationFolderResourceSetView string = "resource_" + RelationSetView RelationFolderResourceSetEdit string = "resource_" + RelationSetEdit RelationFolderResourceSetAdmin string = "resource_" + RelationSetAdmin - RelationFolderResourceGet string = "resource_" + RelationGet - RelationFolderResourceUpdate string = "resource_" + RelationUpdate - RelationFolderResourceCreate string = "resource_" + RelationCreate - RelationFolderResourceDelete string = "resource_" + RelationDelete + RelationFolderResourceGet string = "resource_" + RelationGet + RelationFolderResourceUpdate string = "resource_" + RelationUpdate + RelationFolderResourceCreate string = "resource_" + RelationCreate + RelationFolderResourceDelete string = "resource_" + RelationDelete + RelationFolderResourceGetPermissions string = "resource_" + RelationGetPermissions + RelationFolderResourceSetPermissions string = "resource_" + RelationSetPermissions ) // RelationsGroupResource are relations that can be added on type "group_resource". @@ -59,6 +64,8 @@ var RelationsGroupResource = []string{ RelationUpdate, RelationCreate, RelationDelete, + RelationGetPermissions, + RelationSetPermissions, } // RelationsResource are relations that can be added on type "resource". @@ -66,6 +73,8 @@ var RelationsResource = []string{ RelationGet, RelationUpdate, RelationDelete, + RelationGetPermissions, + RelationSetPermissions, } // RelationsFolderResource are relations that can be added on type "folder" for child resources. @@ -74,6 +83,8 @@ var RelationsFolderResource = []string{ RelationFolderResourceUpdate, RelationFolderResourceCreate, RelationFolderResourceDelete, + RelationFolderResourceGetPermissions, + RelationFolderResourceSetPermissions, } // RelationsFolder are relations that can be added on type "folder". @@ -83,6 +94,8 @@ var RelationsFolder = append( RelationUpdate, RelationCreate, RelationDelete, + RelationGetPermissions, + RelationSetPermissions, ) // VerbMapping is mapping a k8s verb to a zanzana relation. @@ -95,14 +108,18 @@ var VerbMapping = map[string]string{ utils.VerbPatch: RelationUpdate, utils.VerbDelete: RelationDelete, utils.VerbDeleteCollection: RelationDelete, + utils.VerbGetPermissions: RelationGet, + utils.VerbSetPermissions: RelationDelete, } // RelationToVerbMapping is mapping a zanzana relation to k8s verb. var RelationToVerbMapping = map[string]string{ - RelationGet: utils.VerbGet, - RelationCreate: utils.VerbCreate, - RelationUpdate: utils.VerbUpdate, - RelationDelete: utils.VerbDelete, + RelationGet: utils.VerbGet, + RelationCreate: utils.VerbCreate, + RelationUpdate: utils.VerbUpdate, + RelationDelete: utils.VerbDelete, + RelationGetPermissions: utils.VerbGetPermissions, + RelationSetPermissions: utils.VerbSetPermissions, } func IsGroupResourceRelation(relation string) bool { diff --git a/pkg/services/authz/zanzana/schema/schema_core.fga b/pkg/services/authz/zanzana/schema/schema_core.fga index 80375ad2d4a..81a5bf49257 100644 --- a/pkg/services/authz/zanzana/schema/schema_core.fga +++ b/pkg/services/authz/zanzana/schema/schema_core.fga @@ -17,6 +17,9 @@ type team define admin: [user, service-account] define member: [user, service-account] or admin - define get: [role#assignee] or member - define update: [role#assignee] or admin - define delete: [role#assignee] or admin + define get: [user, service-account, team#member, role#assignee] or member + define update: [user, service-account, team#member, role#assignee] or admin + define delete: [user, service-account, team#member, role#assignee] or admin + + define get_permissions: [user, service-account, team#member, role#assignee] or admin + define set_permissions: [user, service-account, team#member, role#assignee] or admin diff --git a/pkg/services/authz/zanzana/schema/schema_folder.fga b/pkg/services/authz/zanzana/schema/schema_folder.fga index d3cbb26bb64..b9b0a842de9 100644 --- a/pkg/services/authz/zanzana/schema/schema_folder.fga +++ b/pkg/services/authz/zanzana/schema/schema_folder.fga @@ -13,3 +13,6 @@ type folder define create: [user, service-account, team#member, role#assignee] or edit or create from parent define update: [user, service-account, team#member, role#assignee] or edit or update from parent define delete: [user, service-account, team#member, role#assignee] or edit or delete from parent + + define get_permissions: [user, service-account, team#member, role#assignee] or admin or get_permissions from parent + define set_permissions: [user, service-account, team#member, role#assignee] or admin or set_permissions from parent diff --git a/pkg/services/authz/zanzana/schema/schema_resource.fga b/pkg/services/authz/zanzana/schema/schema_resource.fga index b97831d2163..b9893b2a997 100644 --- a/pkg/services/authz/zanzana/schema/schema_resource.fga +++ b/pkg/services/authz/zanzana/schema/schema_resource.fga @@ -11,6 +11,9 @@ extend type folder define resource_update: [user with folder_group_filter, service-account with folder_group_filter, team#member with folder_group_filter, role#assignee with folder_group_filter] or resource_edit or resource_update from parent define resource_delete: [user with folder_group_filter, service-account with folder_group_filter, team#member with folder_group_filter, role#assignee with folder_group_filter] or resource_edit or resource_delete from parent + define resource_get_permissions: [user with folder_group_filter, service-account with folder_group_filter, team#member with folder_group_filter, role#assignee with folder_group_filter] or resource_admin or resource_get_permissions from parent + define resource_set_permissions: [user with folder_group_filter, service-account with folder_group_filter, team#member with folder_group_filter, role#assignee with folder_group_filter] or resource_admin or resource_set_permissions from parent + type group_resource relations define view: [user, service-account, render, team#member, role#assignee] or edit @@ -22,6 +25,9 @@ type group_resource define update: [user, service-account, team#member, role#assignee] or edit define delete: [user, service-account, team#member, role#assignee] or edit + define get_permissions: [user, service-account, render, team#member, role#assignee] or admin + define set_permissions: [user, service-account, render, team#member, role#assignee] or admin + type resource relations define view: [user with group_filter, service-account with group_filter, team#member with group_filter, role#assignee with group_filter] or edit @@ -32,6 +38,9 @@ type resource define update: [user with group_filter, service-account with group_filter, team#member with group_filter, role#assignee with group_filter] or edit define delete: [user with group_filter, service-account with group_filter, team#member with group_filter, role#assignee with group_filter] or edit + define get_permissions: [user with group_filter, service-account with group_filter, team#member with group_filter, role#assignee with group_filter] or admin + define set_permissions: [user with group_filter, service-account with group_filter, team#member with group_filter, role#assignee with group_filter] or admin + condition group_filter(requested_group: string, group_resource: string) { requested_group == group_resource }