Zanzana: Handle renderer service authorization requests (#97201)

* Zanzana: Handle renderer service authorization requests

* only add context if render service is authorizing

* use group and resource from API definitions

* check prefix instead of full identity

* fix AddRenderContext

* remove unused type
pull/97629/head
Alexander Zobnin 7 months ago committed by GitHub
parent 4f1307edb1
commit cd7772204e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 20
      pkg/services/authz/zanzana/common/tuple.go
  2. 14
      pkg/services/authz/zanzana/schema/schema_core.fga
  3. 11
      pkg/services/authz/zanzana/server/server_check.go
  4. 1
      pkg/services/authz/zanzana/zanzana.go

@ -6,12 +6,14 @@ import (
openfgav1 "github.com/openfga/api/proto/openfga/v1" openfgav1 "github.com/openfga/api/proto/openfga/v1"
"google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/structpb"
dashboardalpha1 "github.com/grafana/grafana/pkg/apis/dashboard/v0alpha1"
authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1"
) )
const ( const (
TypeUser string = "user" TypeUser string = "user"
TypeServiceAccount string = "service-account" TypeServiceAccount string = "service-account"
TypeRenderService string = "render"
TypeTeam string = "team" TypeTeam string = "team"
TypeRole string = "role" TypeRole string = "role"
TypeFolder string = "folder" TypeFolder string = "folder"
@ -245,3 +247,21 @@ func ToOpenFGATuples(tuples []*authzextv1.Tuple) []*openfgav1.Tuple {
} }
return result return result
} }
func AddRenderContext(req *openfgav1.CheckRequest) {
if req.ContextualTuples == nil {
req.ContextualTuples = &openfgav1.ContextualTupleKeys{}
}
if req.ContextualTuples.TupleKeys == nil {
req.ContextualTuples.TupleKeys = make([]*openfgav1.TupleKey, 0)
}
req.ContextualTuples.TupleKeys = append(req.ContextualTuples.TupleKeys, &openfgav1.TupleKey{
User: req.TupleKey.User,
Relation: "view",
Object: NewNamespaceResourceIdent(
dashboardalpha1.DashboardResourceInfo.GroupResource().Group,
dashboardalpha1.DashboardResourceInfo.GroupResource().Resource,
),
})
}

@ -1,22 +1,24 @@
module core module core
type user
type service-account
type render
type namespace type namespace
relations relations
define view: [user, service-account, team#member, role#assignee] or edit define view: [user, service-account, render, team#member, role#assignee] or edit
define edit: [user, service-account, team#member, role#assignee] or admin define edit: [user, service-account, team#member, role#assignee] or admin
define admin: [user, service-account, team#member, role#assignee] define admin: [user, service-account, team#member, role#assignee]
define read: [user, service-account, team#member, role#assignee] or view define read: [user, service-account, render, team#member, role#assignee] or view
define create: [user, service-account, team#member, role#assignee] or edit define create: [user, service-account, team#member, role#assignee] or edit
define write: [user, service-account, team#member, role#assignee] or edit define write: [user, service-account, team#member, role#assignee] or edit
define delete: [user, service-account, team#member, role#assignee] or edit define delete: [user, service-account, team#member, role#assignee] or edit
define permissions_read: [user, service-account, team#member, role#assignee] or admin define permissions_read: [user, service-account, team#member, role#assignee] or admin
define permissions_write: [user, service-account, team#member, role#assignee] or admin define permissions_write: [user, service-account, team#member, role#assignee] or admin
type user
type service-account
type role type role
relations relations
define assignee: [user, service-account, team#member, role#assignee] define assignee: [user, service-account, team#member, role#assignee]

@ -2,6 +2,8 @@ package server
import ( import (
"context" "context"
"fmt"
"strings"
authzv1 "github.com/grafana/authlib/authz/proto/v1" authzv1 "github.com/grafana/authlib/authz/proto/v1"
openfgav1 "github.com/openfga/api/proto/openfga/v1" openfgav1 "github.com/openfga/api/proto/openfga/v1"
@ -40,7 +42,7 @@ func (s *Server) Check(ctx context.Context, r *authzv1.CheckRequest) (*authzv1.C
// checkTyped performes check on the root "namespace". If subject has access through the namespace they have access to // checkTyped performes check on the root "namespace". If subject has access through the namespace they have access to
// every resource for that "GroupResource". // every resource for that "GroupResource".
func (s *Server) checkNamespace(ctx context.Context, subject, relation, group, resource string, store *storeInfo) (*authzv1.CheckResponse, error) { func (s *Server) checkNamespace(ctx context.Context, subject, relation, group, resource string, store *storeInfo) (*authzv1.CheckResponse, error) {
res, err := s.openfga.Check(ctx, &openfgav1.CheckRequest{ req := &openfgav1.CheckRequest{
StoreId: store.ID, StoreId: store.ID,
AuthorizationModelId: store.ModelID, AuthorizationModelId: store.ModelID,
TupleKey: &openfgav1.CheckRequestTupleKey{ TupleKey: &openfgav1.CheckRequestTupleKey{
@ -48,7 +50,12 @@ func (s *Server) checkNamespace(ctx context.Context, subject, relation, group, r
Relation: relation, Relation: relation,
Object: common.NewNamespaceResourceIdent(group, resource), Object: common.NewNamespaceResourceIdent(group, resource),
}, },
}) }
if strings.HasPrefix(subject, fmt.Sprintf("%s:", common.TypeRenderService)) {
common.AddRenderContext(req)
}
res, err := s.openfga.Check(ctx, req)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -13,6 +13,7 @@ import (
const ( const (
TypeUser = common.TypeUser TypeUser = common.TypeUser
TypeServiceAccount = common.TypeServiceAccount TypeServiceAccount = common.TypeServiceAccount
TypeRenderService = common.TypeRenderService
TypeTeam = common.TypeTeam TypeTeam = common.TypeTeam
TypeRole = common.TypeRole TypeRole = common.TypeRole
TypeFolder = common.TypeFolder TypeFolder = common.TypeFolder

Loading…
Cancel
Save