Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions internal/api/authorization/k8s/k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ func (k *k8sImpl) GetPermissions(ctx echo.Context) (map[string][]*v1Role.Permiss
// against any of the projects we check after this point
allNamespacePermittedActions := map[v1Role.Scope][]v1Role.Action{}
allNamespacePermissions := []*v1Role.Permission{}
for _, scope := range scopesToCheck {
for _, scope := range globalScopesToCheck {
permittedActions := k.getPermittedActions(ctx, v1.WildcardProject, kubernetesUser, scope, []v1Role.Action{})
if len(permittedActions) > 0 {
allNamespacePermittedActions[scope] = permittedActions
Expand All @@ -300,7 +300,7 @@ func (k *k8sImpl) GetPermissions(ctx echo.Context) (map[string][]*v1Role.Permiss
}

for _, namespace := range namespaces {
namespacePermissions := k.getNamespacePermissions(ctx, namespace, kubernetesUser, scopesToCheck, allNamespacePermittedActions)
namespacePermissions := k.getNamespacePermissions(ctx, namespace, kubernetesUser, projectScopesToCheck, allNamespacePermittedActions)
if len(namespacePermissions) > 0 {
userPermissions[namespace] = namespacePermissions
}
Expand Down Expand Up @@ -374,6 +374,12 @@ func (k *k8sImpl) checkSpecificPermision(ctx echo.Context, namespace string, use
k8sScope := getK8sScope(scope)
apiGroup := getK8sAPIGroup(k8sScope)
apiVersion := getK8sAPIVersion(k8sScope)

// To align with Perses RBAC any Global resource is not namespaced
if slices.Contains(globalScopes, scope) {
namespace = v1.WildcardProject
}

attributes := authorizer.AttributesRecord{
User: user,
Verb: string(getK8sAction(action)),
Expand All @@ -398,7 +404,7 @@ func (k *k8sImpl) hasPermissionForNamespace(ctx echo.Context, namespace string,
// Rather than checking if the user has access to the namespace, we check if the user has access
// to read any of the perses scopes within the namespace, since namespaces which the user has access to
// but cannot view perses scopes are irrelevant
for _, scope := range scopesToCheck {
for _, scope := range projectScopesToCheck {
authorized, _ := k.checkSpecificPermision(ctx, namespace, user, scope, v1Role.ReadAction)
if authorized == authorizer.DecisionAllow {
// We can return early if the user can access any of the scopes
Expand Down
55 changes: 46 additions & 9 deletions internal/api/authorization/k8s/k8s_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,19 +201,25 @@
spec := sar.Spec
if spec.User == "admin" {
sar.Status.Allowed = true
// User0 has access to read in project0 only
} else if spec.User == "user0" && spec.ResourceAttributes.Verb == "get" && spec.ResourceAttributes.Namespace == "project0" {
// User0 has access to read in project0 only and GlobalDatasource in in all projects
} else if spec.User == "user0" && spec.ResourceAttributes.Verb == "get" && spec.ResourceAttributes.Namespace == "project0" && spec.ResourceAttributes.Resource != string(k8sGlobalDatasourceScope) {

Check failure on line 205 in internal/api/authorization/k8s/k8s_test.go

View workflow job for this annotation

GitHub Actions / lint

string `get` has 3 occurrences, but such constant `k8sReadAction` already exists (goconst)
sar.Status.Allowed = true
} else if spec.User == "user0" && spec.ResourceAttributes.Verb == "get" && spec.ResourceAttributes.Resource == string(k8sGlobalDatasourceScope) {
sar.Status.Allowed = true
} else if spec.User == "user0" {
sar.Status.Allowed = false
sar.Status.Reason = fmt.Sprintf("Mock RBAC: user0 cannot '%s' in namespace '%s", createAction.GetVerb(), createAction.GetNamespace())
} else if spec.User == "user1" {
sar.Status.Allowed = false
sar.Status.Reason = fmt.Sprintf("Mock RBAC: user1 cannot '%s'", createAction.GetVerb())
} else if spec.User == "user2" && spec.ResourceAttributes.Verb == "get" {
} else if spec.User == "user2" && spec.ResourceAttributes.Verb == "get" && spec.ResourceAttributes.Resource != string(k8sGlobalDatasourceScope) {

Check failure on line 215 in internal/api/authorization/k8s/k8s_test.go

View workflow job for this annotation

GitHub Actions / lint

string `user2` has 3 occurrences, make it a constant (goconst)
sar.Status.Allowed = true
} else if spec.User == "user2" && spec.ResourceAttributes.Verb == "create" && spec.ResourceAttributes.Namespace == "project0" {
sar.Status.Allowed = true
// user2 has incorrectly set up GlobalDatasource access to a single namespace. This should not be reflected
// in any perses permissions
} else if spec.User == "user2" && spec.ResourceAttributes.Verb == "read" && spec.ResourceAttributes.Namespace == "project0" && spec.ResourceAttributes.Resource == string(k8sGlobalDatasourceScope) {
sar.Status.Allowed = true
} else {
sar.Status.Allowed = false
sar.Status.Reason = "Mock RBAC: User does not exist"
Expand Down Expand Up @@ -263,6 +269,30 @@
reqScope: "Dashboard",
expectedResult: true,
},
{
title: "user0 has read globaldatasource perm in project0",
user: "user0",
reqAction: "read",
reqProject: "project0",
reqScope: "GlobalDatasource",
expectedResult: true,
},
{
title: "user0 has read globaldatasource perm in project1",
user: "user0",
reqAction: "read",
reqProject: "project2",
reqScope: "GlobalDatasource",
expectedResult: true,
},
{
title: "user0 has read globaldatasource perm in wildcard project",
user: "user0",
reqAction: "read",
reqProject: "*",
reqScope: "GlobalDatasource",
expectedResult: true,
},
{
title: "admin has create dashboard perm in project0",
user: "admin",
Expand Down Expand Up @@ -327,6 +357,14 @@
reqScope: "Dashboard",
expectedResult: false,
},
{
title: "user2 doesn't have read globaldatasource perm in project0 due to invalid configuration",
user: "user2",
reqAction: "read",
reqProject: "project0",
reqScope: "GlobalDatasource",
expectedResult: false,
},
}
for i := range testSuites {
test := testSuites[i]
Expand Down Expand Up @@ -402,17 +440,18 @@
title: "admin has full permissions to all projects",
user: "admin",
expectedResult: map[string][]*v1Role.Permission{"*": {
&v1Role.Permission{Actions: []v1Role.Action{"*"}, Scopes: []v1Role.Scope{"Dashboard"}},
&v1Role.Permission{Actions: []v1Role.Action{"*"}, Scopes: []v1Role.Scope{"GlobalDatasource"}},
&v1Role.Permission{Actions: []v1Role.Action{"*"}, Scopes: []v1Role.Scope{"Dashboard"}},
&v1Role.Permission{Actions: []v1Role.Action{"*"}, Scopes: []v1Role.Scope{"Datasource"}},
}},
},
{
title: "user0 has readonly permissions in project0",
title: "user0 has readonly permissions in project0 and GlobalDatasource in all namespaces",
user: "user0",
expectedResult: map[string][]*v1Role.Permission{"project0": {
&v1Role.Permission{Actions: []v1Role.Action{"read"}, Scopes: []v1Role.Scope{"Dashboard"}},
expectedResult: map[string][]*v1Role.Permission{"*": {
&v1Role.Permission{Actions: []v1Role.Action{"read"}, Scopes: []v1Role.Scope{"GlobalDatasource"}},
}, "project0": {
&v1Role.Permission{Actions: []v1Role.Action{"read"}, Scopes: []v1Role.Scope{"Dashboard"}},
&v1Role.Permission{Actions: []v1Role.Action{"read"}, Scopes: []v1Role.Scope{"Datasource"}},
}},
},
Expand All @@ -421,11 +460,9 @@
user: "user2",
expectedResult: map[string][]*v1Role.Permission{"*": {
&v1Role.Permission{Actions: []v1Role.Action{"read"}, Scopes: []v1Role.Scope{"Dashboard"}},
&v1Role.Permission{Actions: []v1Role.Action{"read"}, Scopes: []v1Role.Scope{"GlobalDatasource"}},
&v1Role.Permission{Actions: []v1Role.Action{"read"}, Scopes: []v1Role.Scope{"Datasource"}},
}, "project0": {
&v1Role.Permission{Actions: []v1Role.Action{"create"}, Scopes: []v1Role.Scope{"Dashboard"}},
&v1Role.Permission{Actions: []v1Role.Action{"create"}, Scopes: []v1Role.Scope{"GlobalDatasource"}},
&v1Role.Permission{Actions: []v1Role.Action{"create"}, Scopes: []v1Role.Scope{"Datasource"}},
}},
},
Expand Down
14 changes: 12 additions & 2 deletions internal/api/authorization/k8s/translation.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,22 @@ const (
k8sProjectScope k8sScope = "namespaces"
)

var scopesToCheck = []v1Role.Scope{
v1Role.DashboardScope,
var globalScopesToCheck = []v1Role.Scope{
v1Role.GlobalDatasourceScope,
v1Role.DashboardScope,
v1Role.DatasourceScope,
}

var projectScopesToCheck = []v1Role.Scope{
v1Role.DashboardScope,
v1Role.DatasourceScope,
}

// All resources which are global scoped
var globalScopes = []v1Role.Scope{
v1Role.GlobalDatasourceScope,
}

func getK8sAction(action v1Role.Action) k8sAction {
switch action {
case v1Role.ReadAction:
Expand Down
Loading