Zanzana: Support subresources for users and service accounts (#102874)

* Zanzana: Support subresources for users and service accounts

* rename relationsFolder

* fix linter error
pull/102907/head
Alexander Zobnin 4 months ago committed by GitHub
parent a4e8bd16de
commit 63a2ce7214
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 14
      pkg/services/authz/zanzana/common/info.go
  2. 12
      pkg/services/authz/zanzana/common/tuple.go
  3. 12
      pkg/services/authz/zanzana/schema/schema_core.fga
  4. 33
      pkg/services/authz/zanzana/schema/schema_subresource.fga
  5. 12
      pkg/services/authz/zanzana/server/server_check_test.go
  6. 18
      pkg/services/authz/zanzana/server/server_list_test.go
  7. 10
      pkg/services/authz/zanzana/server/server_test.go
  8. 2
      pkg/services/authz/zanzana/zanzana.go

@ -19,12 +19,22 @@ var typedResources = map[string]typeInfo{
folderalpha1.FolderResourceInfo.GroupResource().Group,
folderalpha1.FolderResourceInfo.GroupResource().Resource,
"",
): {Type: "folder", Relations: RelationsFolder},
): {Type: "folder", Relations: RelationsTyped},
FormatGroupResource(
iamalpha1.TeamResourceInfo.GroupResource().Group,
iamalpha1.TeamResourceInfo.GroupResource().Resource,
"",
): {Type: "team", Relations: RelationsFolder},
): {Type: "team", Relations: RelationsTyped},
FormatGroupResource(
iamalpha1.UserResourceInfo.GroupResource().Group,
iamalpha1.UserResourceInfo.GroupResource().Resource,
"",
): {Type: "user", Relations: RelationsTyped},
FormatGroupResource(
iamalpha1.ServiceAccountResourceInfo.GroupResource().Group,
iamalpha1.ServiceAccountResourceInfo.GroupResource().Resource,
"",
): {Type: "service-account", Relations: RelationsTyped},
}
func getTypeInfo(group, resource string) (typeInfo, bool) {

@ -92,8 +92,8 @@ var RelationsSubresource = []string{
RelationSubresourceSetPermissions,
}
// RelationsFolder are relations that can be added on type "folder".
var RelationsFolder = append(
// RelationsTyped are relations that can be added to typed resources (folders, teams, users, etc).
var RelationsTyped = append(
RelationsSubresource,
RelationGet,
RelationUpdate,
@ -160,10 +160,6 @@ func NewFolderIdent(name string) string {
return TypeFolderPrefix + name
}
func NewTeamIdent(name string) string {
return TypeTeamPrefix + name
}
func NewGroupResourceIdent(group, resource, subresource string) string {
return TypeGroupResoucePrefix + FormatGroupResource(group, resource, subresource)
}
@ -228,7 +224,7 @@ func NewFolderResourceTuple(subject, relation, group, resource, subresource, fol
}
}
func NewTeamResourceTuple(subject, relation, group, resource, subresource, name string) *openfgav1.TupleKey {
func NewTypedResourceTuple(subject, relation, typ, group, resource, subresource, name string) *openfgav1.TupleKey {
relation = SubresourceRelation(relation)
var condition *openfgav1.RelationshipCondition
if !isSubresourceRelationSet(relation) {
@ -247,7 +243,7 @@ func NewTeamResourceTuple(subject, relation, group, resource, subresource, name
return &openfgav1.TupleKey{
User: subject,
Relation: relation,
Object: NewTeamIdent(name),
Object: NewTypedIdent(typ, name),
Condition: condition,
}
}

@ -1,8 +1,16 @@
module core
type user
relations
define get: [user, service-account, team#member, role#assignee]
define update: [user, service-account, team#member, role#assignee]
define delete: [user, service-account, team#member, role#assignee]
type service-account
relations
define get: [user, service-account, team#member, role#assignee]
define update: [user, service-account, team#member, role#assignee]
define delete: [user, service-account, team#member, role#assignee]
type render
@ -12,6 +20,10 @@ type role
relations
define assignee: [user, service-account, anonymous, team#member, role#assignee]
define get: [user, service-account, team#member, role#assignee]
define update: [user, service-account, team#member, role#assignee]
define delete: [user, service-account, team#member, role#assignee]
type team
relations
define admin: [user, service-account]

@ -25,6 +25,39 @@ extend type team
define resource_update: [user with subresource_filter, service-account with subresource_filter, team#member with subresource_filter, role#assignee with subresource_filter] or resource_edit
define resource_delete: [user with subresource_filter, service-account with subresource_filter, team#member with subresource_filter, role#assignee with subresource_filter] or resource_edit
extend type user
relations
define resource_view: [user, service-account, team#member, role#assignee] or resource_edit
define resource_edit: [user, service-account, team#member, role#assignee] or resource_admin
define resource_admin: [user, service-account, team#member, role#assignee]
define resource_get: [user with subresource_filter, service-account with subresource_filter, team#member with subresource_filter, role#assignee with subresource_filter] or resource_view
define resource_create: [user with subresource_filter, service-account with subresource_filter, team#member with subresource_filter, role#assignee with subresource_filter] or resource_edit
define resource_update: [user with subresource_filter, service-account with subresource_filter, team#member with subresource_filter, role#assignee with subresource_filter] or resource_edit
define resource_delete: [user with subresource_filter, service-account with subresource_filter, team#member with subresource_filter, role#assignee with subresource_filter] or resource_edit
extend type service-account
relations
define resource_view: [user, service-account, team#member, role#assignee] or resource_edit
define resource_edit: [user, service-account, team#member, role#assignee] or resource_admin
define resource_admin: [user, service-account, team#member, role#assignee]
define resource_get: [user with subresource_filter, service-account with subresource_filter, team#member with subresource_filter, role#assignee with subresource_filter] or resource_view
define resource_create: [user with subresource_filter, service-account with subresource_filter, team#member with subresource_filter, role#assignee with subresource_filter] or resource_edit
define resource_update: [user with subresource_filter, service-account with subresource_filter, team#member with subresource_filter, role#assignee with subresource_filter] or resource_edit
define resource_delete: [user with subresource_filter, service-account with subresource_filter, team#member with subresource_filter, role#assignee with subresource_filter] or resource_edit
extend type role
relations
define resource_view: [user, service-account, team#member, role#assignee] or resource_edit
define resource_edit: [user, service-account, team#member, role#assignee] or resource_admin
define resource_admin: [user, service-account, team#member, role#assignee]
define resource_get: [user with subresource_filter, service-account with subresource_filter, team#member with subresource_filter, role#assignee with subresource_filter] or resource_view
define resource_create: [user with subresource_filter, service-account with subresource_filter, team#member with subresource_filter, role#assignee with subresource_filter] or resource_edit
define resource_update: [user with subresource_filter, service-account with subresource_filter, team#member with subresource_filter, role#assignee with subresource_filter] or resource_edit
define resource_delete: [user with subresource_filter, service-account with subresource_filter, team#member with subresource_filter, role#assignee with subresource_filter] or resource_edit
condition subresource_filter(subresource: string, subresources: list<string>) {
subresource in subresources
}

@ -172,4 +172,16 @@ func testCheck(t *testing.T, server *Server) {
require.NoError(t, err)
assert.True(t, res.GetAllowed())
})
t.Run("user:15 should be able to read user subresources for user 1", func(t *testing.T) {
res, err := server.Check(newContextWithNamespace(), newReq("user:15", utils.VerbGet, "iam.grafana.app", "users", statusSubresource, "", "1"))
require.NoError(t, err)
assert.True(t, res.GetAllowed())
})
t.Run("user:16 should be able to read serviceaccount subresources for serviceaccount 1", func(t *testing.T) {
res, err := server.Check(newContextWithNamespace(), newReq("user:16", utils.VerbGet, "iam.grafana.app", "serviceaccounts", statusSubresource, "", "1"))
require.NoError(t, err)
assert.True(t, res.GetAllowed())
})
}

@ -137,4 +137,22 @@ func testList(t *testing.T, server *Server) {
assert.Contains(t, res.GetItems(), "1")
})
t.Run("user:15 should be able to list all subresources for user 1", func(t *testing.T) {
res, err := server.List(newContextWithNamespace(), newList("user:15", userGroup, userResource, statusSubresource))
require.NoError(t, err)
assert.Len(t, res.GetItems(), 1)
assert.Len(t, res.GetFolders(), 0)
assert.Contains(t, res.GetItems(), "1")
})
t.Run("user:16 should be able to list all subresources for service-account 1", func(t *testing.T) {
res, err := server.List(newContextWithNamespace(), newList("user:16", serviceAccountGroup, serviceAccountResource, statusSubresource))
require.NoError(t, err)
assert.Len(t, res.GetItems(), 1)
assert.Len(t, res.GetFolders(), 0)
assert.Contains(t, res.GetItems(), "1")
})
}

@ -32,6 +32,12 @@ const (
teamGroup = "iam.grafana.app"
teamResource = "teams"
userGroup = "iam.grafana.app"
userResource = "users"
serviceAccountGroup = "iam.grafana.app"
serviceAccountResource = "serviceaccounts"
statusSubresource = "status"
)
@ -107,7 +113,9 @@ func setup(t *testing.T, testDB db.DB, cfg *setting.Cfg) *Server {
common.NewGroupResourceTuple("user:11", common.RelationGet, dashboardGroup, dashboardResource, statusSubresource),
common.NewFolderResourceTuple("user:12", common.RelationGet, dashboardGroup, dashboardResource, statusSubresource, "5"),
common.NewFolderResourceTuple("user:13", common.RelationGet, folderGroup, folderResource, statusSubresource, "5"),
common.NewTeamResourceTuple("user:14", common.RelationGet, teamGroup, teamResource, statusSubresource, "1"),
common.NewTypedResourceTuple("user:14", common.RelationGet, common.TypeTeam, teamGroup, teamResource, statusSubresource, "1"),
common.NewTypedResourceTuple("user:15", common.RelationGet, common.TypeUser, userGroup, userResource, statusSubresource, "1"),
common.NewTypedResourceTuple("user:16", common.RelationGet, common.TypeServiceAccount, serviceAccountGroup, serviceAccountResource, statusSubresource, "1"),
},
}
for _, w := range writes.TupleKeys {

@ -49,7 +49,7 @@ const (
)
var (
RelationsFolder = common.RelationsFolder
RelationsFolder = common.RelationsTyped
RelationsResouce = common.RelationsResource
RelationsSubresource = common.RelationsSubresource
)

Loading…
Cancel
Save