Zanzana: Support subresources for users and service accounts (#102874)
* Zanzana: Support subresources for users and service accounts * rename relationsFolder * fix linter error
This commit is contained in:
@@ -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
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user