K8s: Dashboards: Add fine grained access control checks to /apis (#104347)
--------- Co-authored-by: Ieva <ieva.vasiljeva@grafana.com> Co-authored-by: Gabriel MABILLE <gabriel.mabille@grafana.com> Co-authored-by: Marco de Abreu <marco.deabreu@grafana.com> Co-authored-by: Georges Chaudy <chaudyg@gmail.com>
This commit is contained in:
co-authored by
Ieva
Gabriel MABILLE
Marco de Abreu
Georges Chaudy
parent
410c5ebfb7
commit
b887e8aa05
@@ -18,6 +18,7 @@ import (
|
||||
authzv1 "github.com/grafana/authlib/authz/proto/v1"
|
||||
"github.com/grafana/authlib/cache"
|
||||
"github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
@@ -553,10 +554,14 @@ func (s *Service) checkPermission(ctx context.Context, scopeMap map[string]bool,
|
||||
ctxLogger := s.logger.FromContext(ctx)
|
||||
|
||||
// Only check action if the request doesn't specify scope
|
||||
if req.Name == "" {
|
||||
if req.Name == "" && req.Verb != utils.VerbCreate {
|
||||
return len(scopeMap) > 0, nil
|
||||
}
|
||||
|
||||
if req.Verb == utils.VerbCreate && req.ParentFolder == "" {
|
||||
req.ParentFolder = accesscontrol.GeneralFolderUID
|
||||
}
|
||||
|
||||
// Wildcard grant, no further checks needed
|
||||
if scopeMap["*"] {
|
||||
return true, nil
|
||||
@@ -568,7 +573,7 @@ func (s *Service) checkPermission(ctx context.Context, scopeMap map[string]bool,
|
||||
return false, status.Error(codes.NotFound, "unsupported resource")
|
||||
}
|
||||
|
||||
if scopeMap[t.scope(req.Name)] {
|
||||
if req.Name != "" && scopeMap[t.scope(req.Name)] {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/grafana/authlib/cache"
|
||||
"github.com/grafana/authlib/types"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam/legacy"
|
||||
@@ -127,19 +128,39 @@ func TestService_checkPermission(t *testing.T) {
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "should return true if no resource is specified",
|
||||
name: "should check general folder scope for root level resource creation",
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: "folders:create",
|
||||
Action: "dashboards:create",
|
||||
Scope: "folders:uid:general",
|
||||
Kind: "folders",
|
||||
Attribute: "uid",
|
||||
Identifier: "general",
|
||||
},
|
||||
},
|
||||
check: CheckRequest{
|
||||
Action: "folders:create",
|
||||
Group: "folder.grafana.app",
|
||||
Resource: "folders",
|
||||
Action: "dashboards:create",
|
||||
Group: "dashboard.grafana.app",
|
||||
Resource: "dashboards",
|
||||
Verb: utils.VerbCreate,
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "should fail if user doesn't have general folder scope for root level resource creation",
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: "dashboards:create",
|
||||
},
|
||||
},
|
||||
check: CheckRequest{
|
||||
Action: "dashboards:create",
|
||||
Group: "dashboard.grafana.app",
|
||||
Resource: "dashboards",
|
||||
Verb: utils.VerbCreate,
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "should return false if user has no permissions on resource",
|
||||
permissions: []accesscontrol.Permission{},
|
||||
@@ -174,6 +195,72 @@ func TestService_checkPermission(t *testing.T) {
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "should allow creating a nested resource",
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: "dashboards:create",
|
||||
Scope: "folders:uid:parent",
|
||||
Kind: "folders",
|
||||
Attribute: "uid",
|
||||
Identifier: "parent",
|
||||
},
|
||||
},
|
||||
folders: []store.Folder{{UID: "parent"}},
|
||||
check: CheckRequest{
|
||||
Action: "dashboards:create",
|
||||
Group: "dashboard.grafana.app",
|
||||
Resource: "dashboards",
|
||||
Name: "",
|
||||
ParentFolder: "parent",
|
||||
Verb: utils.VerbCreate,
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "should deny creating a nested resource",
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: "dashboards:create",
|
||||
Scope: "folders:uid:parent",
|
||||
Kind: "folders",
|
||||
Attribute: "uid",
|
||||
Identifier: "parent",
|
||||
},
|
||||
},
|
||||
folders: []store.Folder{{UID: "parent"}},
|
||||
check: CheckRequest{
|
||||
Action: "dashboards:create",
|
||||
Group: "dashboard.grafana.app",
|
||||
Resource: "dashboards",
|
||||
Name: "",
|
||||
ParentFolder: "other_parent",
|
||||
Verb: utils.VerbCreate,
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "should allow if it's an any check",
|
||||
permissions: []accesscontrol.Permission{
|
||||
{
|
||||
Action: "dashboards:read",
|
||||
Scope: "folders:uid:parent",
|
||||
Kind: "folders",
|
||||
Attribute: "uid",
|
||||
Identifier: "parent",
|
||||
},
|
||||
},
|
||||
folders: []store.Folder{{UID: "parent"}},
|
||||
check: CheckRequest{
|
||||
Action: "dashboards:read",
|
||||
Group: "dashboard.grafana.app",
|
||||
Resource: "dashboards",
|
||||
Name: "",
|
||||
ParentFolder: "",
|
||||
Verb: utils.VerbList,
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
||||
Reference in New Issue
Block a user