mirror of
https://github.com/grafana/grafana.git
synced 2024-11-28 19:54:10 -06:00
Alerting: Receiver resource permissions service (#93552)
This commit is contained in:
parent
7398fe3fcb
commit
1ede1e32b8
@ -107,9 +107,9 @@ func convertToK8sResource(
|
||||
|
||||
var permissionMapper = map[ngmodels.ReceiverPermission]string{
|
||||
ngmodels.ReceiverPermissionReadSecret: "canReadSecrets",
|
||||
//ngmodels.ReceiverPermissionAdmin: "canAdmin", // TODO: Add when resource permissions are implemented.
|
||||
ngmodels.ReceiverPermissionWrite: "canWrite",
|
||||
ngmodels.ReceiverPermissionDelete: "canDelete",
|
||||
ngmodels.ReceiverPermissionAdmin: "canAdmin",
|
||||
ngmodels.ReceiverPermissionWrite: "canWrite",
|
||||
ngmodels.ReceiverPermissionDelete: "canDelete",
|
||||
}
|
||||
|
||||
func convertToDomainModel(receiver *model.Receiver) (*ngmodels.Receiver, map[string][]string, error) {
|
||||
|
@ -315,6 +315,8 @@ var wireBasicSet = wire.NewSet(
|
||||
wire.Bind(new(accesscontrol.FolderPermissionsService), new(*ossaccesscontrol.FolderPermissionsService)),
|
||||
ossaccesscontrol.ProvideDashboardPermissions,
|
||||
wire.Bind(new(accesscontrol.DashboardPermissionsService), new(*ossaccesscontrol.DashboardPermissionsService)),
|
||||
ossaccesscontrol.ProvideReceiverPermissionsService,
|
||||
wire.Bind(new(accesscontrol.ReceiverPermissionsService), new(*ossaccesscontrol.ReceiverPermissionsService)),
|
||||
starimpl.ProvideService,
|
||||
playlistimpl.ProvideService,
|
||||
apikeyimpl.ProvideService,
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/grafana/authlib/claims"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/registry"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
@ -148,6 +149,10 @@ type ServiceAccountPermissionsService interface {
|
||||
PermissionsService
|
||||
}
|
||||
|
||||
type ReceiverPermissionsService interface {
|
||||
PermissionsService
|
||||
}
|
||||
|
||||
type PermissionsService interface {
|
||||
// GetPermissions returns all permissions for given resourceID
|
||||
GetPermissions(ctx context.Context, user identity.Requester, resourceID string) ([]ResourcePermission, error)
|
||||
|
@ -444,12 +444,14 @@ const (
|
||||
ActionAlertingNotificationsTimeIntervalsDelete = "alert.notifications.time-intervals:delete"
|
||||
|
||||
// Alerting receiver actions
|
||||
ActionAlertingReceiversList = "alert.notifications.receivers:list"
|
||||
ActionAlertingReceiversRead = "alert.notifications.receivers:read"
|
||||
ActionAlertingReceiversReadSecrets = "alert.notifications.receivers.secrets:read"
|
||||
ActionAlertingReceiversCreate = "alert.notifications.receivers:create"
|
||||
ActionAlertingReceiversUpdate = "alert.notifications.receivers:write"
|
||||
ActionAlertingReceiversDelete = "alert.notifications.receivers:delete"
|
||||
ActionAlertingReceiversList = "alert.notifications.receivers:list"
|
||||
ActionAlertingReceiversRead = "alert.notifications.receivers:read"
|
||||
ActionAlertingReceiversReadSecrets = "alert.notifications.receivers.secrets:read"
|
||||
ActionAlertingReceiversCreate = "alert.notifications.receivers:create"
|
||||
ActionAlertingReceiversUpdate = "alert.notifications.receivers:write"
|
||||
ActionAlertingReceiversDelete = "alert.notifications.receivers:delete"
|
||||
ActionAlertingReceiversPermissionsRead = "receivers.permissions:read"
|
||||
ActionAlertingReceiversPermissionsWrite = "receivers.permissions:write"
|
||||
|
||||
// External alerting rule actions. We can only narrow it down to writes or reads, as we don't control the atomicity in the external system.
|
||||
ActionAlertingRuleExternalWrite = "alert.rules.external:write"
|
||||
|
60
pkg/services/accesscontrol/ossaccesscontrol/receivers.go
Normal file
60
pkg/services/accesscontrol/ossaccesscontrol/receivers.go
Normal file
@ -0,0 +1,60 @@
|
||||
package ossaccesscontrol
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/licensing"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert"
|
||||
alertingac "github.com/grafana/grafana/pkg/services/ngalert/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/team"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
var ReceiversViewActions = []string{accesscontrol.ActionAlertingReceiversRead}
|
||||
var ReceiversEditActions = append(ReceiversViewActions, []string{accesscontrol.ActionAlertingReceiversUpdate, accesscontrol.ActionAlertingReceiversDelete}...)
|
||||
var ReceiversAdminActions = append(ReceiversEditActions, []string{accesscontrol.ActionAlertingReceiversReadSecrets, accesscontrol.ActionAlertingReceiversPermissionsRead, accesscontrol.ActionAlertingReceiversPermissionsWrite}...)
|
||||
|
||||
func ProvideReceiverPermissionsService(
|
||||
cfg *setting.Cfg, features featuremgmt.FeatureToggles, router routing.RouteRegister, sql db.DB, ac accesscontrol.AccessControl,
|
||||
license licensing.Licensing, service accesscontrol.Service,
|
||||
teamService team.Service, userService user.Service, actionSetService resourcepermissions.ActionSetService,
|
||||
) (*ReceiverPermissionsService, error) {
|
||||
if !features.IsEnabledGlobally(featuremgmt.FlagAlertingApiServer) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
options := resourcepermissions.Options{
|
||||
Resource: "receivers",
|
||||
ResourceAttribute: "uid",
|
||||
Assignments: resourcepermissions.Assignments{
|
||||
Users: true,
|
||||
Teams: true,
|
||||
BuiltInRoles: true,
|
||||
ServiceAccounts: true,
|
||||
},
|
||||
PermissionsToActions: map[string][]string{
|
||||
string(alertingac.ReceiverPermissionView): append([]string{}, ReceiversViewActions...),
|
||||
string(alertingac.ReceiverPermissionEdit): append([]string{}, ReceiversEditActions...),
|
||||
string(alertingac.ReceiverPermissionAdmin): append([]string{}, ReceiversAdminActions...),
|
||||
},
|
||||
ReaderRoleName: "Alerting receiver permission reader",
|
||||
WriterRoleName: "Alerting receiver permission writer",
|
||||
RoleGroup: ngalert.AlertRolesGroup,
|
||||
}
|
||||
|
||||
srv, err := resourcepermissions.New(cfg, options, features, router, license, ac, service, sql, teamService, userService, actionSetService)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ReceiverPermissionsService{Service: srv}, nil
|
||||
}
|
||||
|
||||
var _ accesscontrol.ReceiverPermissionsService = new(ReceiverPermissionsService)
|
||||
|
||||
type ReceiverPermissionsService struct {
|
||||
*resourcepermissions.Service
|
||||
}
|
@ -4,6 +4,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
ac "github.com/grafana/grafana/pkg/services/ngalert/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
)
|
||||
@ -115,13 +116,50 @@ var (
|
||||
},
|
||||
}
|
||||
|
||||
receiversReaderRole = accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: accesscontrol.FixedRolePrefix + "alerting.receivers:reader",
|
||||
DisplayName: "Contact Point Reader",
|
||||
Description: "Read all contact points in Grafana",
|
||||
Group: AlertRolesGroup,
|
||||
Permissions: []accesscontrol.Permission{
|
||||
{Action: accesscontrol.ActionAlertingReceiversRead, Scope: ac.ScopeReceiversAll},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
receiversCreatorRole = accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: accesscontrol.FixedRolePrefix + "alerting.receivers:creator",
|
||||
DisplayName: "Contact Point Creator",
|
||||
Description: "Create new contact points in Grafana",
|
||||
Group: AlertRolesGroup,
|
||||
Permissions: []accesscontrol.Permission{
|
||||
{Action: accesscontrol.ActionAlertingReceiversCreate},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
receiversWriterRole = accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: accesscontrol.FixedRolePrefix + "alerting.receivers:writer",
|
||||
DisplayName: "Contact Point Writer",
|
||||
Description: "Create, update, and delete all contact points in Grafana",
|
||||
Group: AlertRolesGroup,
|
||||
Permissions: accesscontrol.ConcatPermissions(receiversReaderRole.Role.Permissions, receiversCreatorRole.Role.Permissions, []accesscontrol.Permission{
|
||||
{Action: accesscontrol.ActionAlertingReceiversUpdate, Scope: ac.ScopeReceiversAll},
|
||||
{Action: accesscontrol.ActionAlertingReceiversDelete, Scope: ac.ScopeReceiversAll},
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
notificationsReaderRole = accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: accesscontrol.FixedRolePrefix + "alerting.notifications:reader",
|
||||
DisplayName: "Notifications Reader",
|
||||
Description: "Read notification policies and contact points in Grafana and external providers",
|
||||
Group: AlertRolesGroup,
|
||||
Permissions: []accesscontrol.Permission{
|
||||
Permissions: accesscontrol.ConcatPermissions(receiversReaderRole.Role.Permissions, []accesscontrol.Permission{
|
||||
{
|
||||
Action: accesscontrol.ActionAlertingNotificationsRead,
|
||||
},
|
||||
@ -132,11 +170,7 @@ var (
|
||||
{
|
||||
Action: accesscontrol.ActionAlertingNotificationsTimeIntervalsRead,
|
||||
},
|
||||
{
|
||||
Action: accesscontrol.ActionAlertingReceiversRead,
|
||||
Scope: ac.ScopeReceiversAll,
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
@ -146,7 +180,7 @@ var (
|
||||
DisplayName: "Notifications Writer",
|
||||
Description: "Add, update, and delete contact points and notification policies in Grafana and external providers",
|
||||
Group: AlertRolesGroup,
|
||||
Permissions: accesscontrol.ConcatPermissions(notificationsReaderRole.Role.Permissions, []accesscontrol.Permission{
|
||||
Permissions: accesscontrol.ConcatPermissions(notificationsReaderRole.Role.Permissions, receiversWriterRole.Role.Permissions, []accesscontrol.Permission{
|
||||
{
|
||||
Action: accesscontrol.ActionAlertingNotificationsWrite,
|
||||
},
|
||||
@ -154,18 +188,6 @@ var (
|
||||
Action: accesscontrol.ActionAlertingNotificationsExternalWrite,
|
||||
Scope: datasources.ScopeAll,
|
||||
},
|
||||
{
|
||||
Action: accesscontrol.ActionAlertingReceiversCreate,
|
||||
Scope: ac.ScopeReceiversAll,
|
||||
},
|
||||
{
|
||||
Action: accesscontrol.ActionAlertingReceiversUpdate,
|
||||
Scope: ac.ScopeReceiversAll,
|
||||
},
|
||||
{
|
||||
Action: accesscontrol.ActionAlertingReceiversDelete,
|
||||
Scope: ac.ScopeReceiversAll,
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
@ -184,12 +206,27 @@ var (
|
||||
alertingWriterRole = accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: accesscontrol.FixedRolePrefix + "alerting:writer",
|
||||
DisplayName: "Full access",
|
||||
Description: "Add,update and delete alert rules, instances, silences, contact points, and notification policies in Grafana and all external providers",
|
||||
DisplayName: "Full write access",
|
||||
Description: "Add, update and delete alert rules, instances, silences, contact points, and notification policies in Grafana and all external providers",
|
||||
Group: AlertRolesGroup,
|
||||
Permissions: accesscontrol.ConcatPermissions(rulesWriterRole.Role.Permissions, instancesWriterRole.Role.Permissions, notificationsWriterRole.Role.Permissions),
|
||||
},
|
||||
Grants: []string{string(org.RoleEditor), string(org.RoleAdmin)},
|
||||
Grants: []string{string(org.RoleEditor)},
|
||||
}
|
||||
|
||||
alertingAdminRole = accesscontrol.RoleRegistration{
|
||||
Role: accesscontrol.RoleDTO{
|
||||
Name: accesscontrol.FixedRolePrefix + "alerting:admin",
|
||||
DisplayName: "Full admin access",
|
||||
Description: "Full write access in Grafana and all external providers, including their permissions and secrets",
|
||||
Group: AlertRolesGroup,
|
||||
Permissions: accesscontrol.ConcatPermissions(alertingWriterRole.Role.Permissions, []accesscontrol.Permission{
|
||||
{Action: accesscontrol.ActionAlertingReceiversPermissionsRead, Scope: ac.ScopeReceiversAll},
|
||||
{Action: accesscontrol.ActionAlertingReceiversPermissionsWrite, Scope: ac.ScopeReceiversAll},
|
||||
{Action: accesscontrol.ActionAlertingReceiversReadSecrets, Scope: ac.ScopeReceiversAll},
|
||||
}),
|
||||
},
|
||||
Grants: []string{string(org.RoleAdmin)},
|
||||
}
|
||||
|
||||
alertingProvisionerRole = accesscontrol.RoleRegistration{
|
||||
@ -266,11 +303,17 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func DeclareFixedRoles(service accesscontrol.Service) error {
|
||||
return service.DeclareFixedRoles(
|
||||
func DeclareFixedRoles(service accesscontrol.Service, features featuremgmt.FeatureToggles) error {
|
||||
fixedRoles := []accesscontrol.RoleRegistration{
|
||||
rulesReaderRole, rulesWriterRole,
|
||||
instancesReaderRole, instancesWriterRole,
|
||||
notificationsReaderRole, notificationsWriterRole,
|
||||
alertingReaderRole, alertingWriterRole, alertingProvisionerRole, alertingProvisioningReaderWithSecretsRole, alertingProvisioningStatus,
|
||||
)
|
||||
alertingReaderRole, alertingWriterRole, alertingAdminRole, alertingProvisionerRole, alertingProvisioningReaderWithSecretsRole, alertingProvisioningStatus,
|
||||
}
|
||||
|
||||
if features.IsEnabledGlobally(featuremgmt.FlagAlertingApiServer) {
|
||||
fixedRoles = append(fixedRoles, receiversReaderRole, receiversCreatorRole, receiversWriterRole)
|
||||
}
|
||||
|
||||
return service.DeclareFixedRoles(fixedRoles...)
|
||||
}
|
||||
|
@ -17,6 +17,15 @@ var (
|
||||
ScopeReceiversAll = ScopeReceiversProvider.GetResourceAllScope()
|
||||
)
|
||||
|
||||
// ReceiverPermission is a type for representing a receiver permission.
|
||||
type ReceiverPermission string
|
||||
|
||||
const (
|
||||
ReceiverPermissionView ReceiverPermission = "View"
|
||||
ReceiverPermissionEdit ReceiverPermission = "Edit"
|
||||
ReceiverPermissionAdmin ReceiverPermission = "Admin"
|
||||
)
|
||||
|
||||
var (
|
||||
// Asserts pre-conditions for read access to redacted receivers. If this evaluates to false, the user cannot read any redacted receivers.
|
||||
readRedactedReceiversPreConditionsEval = ac.EvalAny(
|
||||
@ -125,6 +134,28 @@ var (
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversDelete, ScopeReceiversProvider.GetResourceScopeUID(uid)),
|
||||
)
|
||||
}
|
||||
|
||||
// Admin
|
||||
|
||||
// Asserts pre-conditions for resource permissions access to receivers. If this evaluates to false, the user cannot modify permissions for any receivers.
|
||||
permissionsReceiversPreConditionsEval = ac.EvalAll(
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversPermissionsRead), // Action for receivers. UID scope.
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversPermissionsWrite), // Action for receivers. UID scope.
|
||||
)
|
||||
|
||||
// Asserts resource permissions access to all receivers.
|
||||
permissionsAllReceiversEval = ac.EvalAll(
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversPermissionsRead, ScopeReceiversAll),
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversPermissionsWrite, ScopeReceiversAll),
|
||||
)
|
||||
|
||||
// Asserts resource permissions access to a specific receiver.
|
||||
permissionsReceiverEval = func(uid string) ac.Evaluator {
|
||||
return ac.EvalAll(
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversPermissionsRead, ScopeReceiversProvider.GetResourceScopeUID(uid)),
|
||||
ac.EvalPermission(ac.ActionAlertingReceiversPermissionsWrite, ScopeReceiversProvider.GetResourceScopeUID(uid)),
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
type ReceiverAccess[T models.Identified] struct {
|
||||
@ -133,6 +164,7 @@ type ReceiverAccess[T models.Identified] struct {
|
||||
create actionAccess[T]
|
||||
update actionAccess[T]
|
||||
delete actionAccess[T]
|
||||
permissions actionAccess[T]
|
||||
}
|
||||
|
||||
// NewReceiverAccess creates a new ReceiverAccess service. If includeProvisioningActions is true, the service will include
|
||||
@ -199,6 +231,18 @@ func NewReceiverAccess[T models.Identified](a ac.AccessControl, includeProvision
|
||||
},
|
||||
authorizeAll: deleteAllReceiversEval,
|
||||
},
|
||||
permissions: actionAccess[T]{
|
||||
genericService: genericService{
|
||||
ac: a,
|
||||
},
|
||||
resource: "receiver",
|
||||
action: "admin", // Essentially read+write receiver resource permissions.
|
||||
authorizeSome: permissionsReceiversPreConditionsEval,
|
||||
authorizeOne: func(receiver models.Identified) ac.Evaluator {
|
||||
return permissionsReceiverEval(receiver.GetUID())
|
||||
},
|
||||
authorizeAll: permissionsAllReceiversEval,
|
||||
},
|
||||
}
|
||||
|
||||
// If this service is meant for the provisioning API, we include the provisioning actions as possible permissions.
|
||||
@ -219,9 +263,10 @@ func NewReceiverAccess[T models.Identified](a ac.AccessControl, includeProvision
|
||||
})
|
||||
}
|
||||
|
||||
// Write and delete permissions should require read permissions.
|
||||
// Write, delete, and permissions management should require read permissions.
|
||||
extendAccessControl(&rcvAccess.update, ac.EvalAll, rcvAccess.read)
|
||||
extendAccessControl(&rcvAccess.delete, ac.EvalAll, rcvAccess.read)
|
||||
extendAccessControl(&rcvAccess.permissions, ac.EvalAll, rcvAccess.read)
|
||||
|
||||
return rcvAccess
|
||||
}
|
||||
@ -335,12 +380,11 @@ func (s ReceiverAccess[T]) Access(ctx context.Context, user identity.Requester,
|
||||
basePerms.Set(models.ReceiverPermissionReadSecret, true) // Has access to all receivers.
|
||||
}
|
||||
|
||||
// TODO: Add when resource permissions are implemented.
|
||||
//if err := s.permissions.AuthorizePreConditions(ctx, user); err != nil {
|
||||
// basePerms.Set(models.ReceiverPermissionAdmin, false) // Doesn't match the preconditions.
|
||||
//} else if err := s.permissions.AuthorizeAll(ctx, user); err == nil {
|
||||
// basePerms.Set(models.ReceiverPermissionAdmin, true) // Has access to all receivers.
|
||||
//}
|
||||
if err := s.permissions.AuthorizePreConditions(ctx, user); err != nil {
|
||||
basePerms.Set(models.ReceiverPermissionAdmin, false) // Doesn't match the preconditions.
|
||||
} else if err := s.permissions.AuthorizeAll(ctx, user); err == nil {
|
||||
basePerms.Set(models.ReceiverPermissionAdmin, true) // Has access to all receivers.
|
||||
}
|
||||
|
||||
if err := s.update.AuthorizePreConditions(ctx, user); err != nil {
|
||||
basePerms.Set(models.ReceiverPermissionWrite, false) // Doesn't match the preconditions.
|
||||
@ -371,11 +415,10 @@ func (s ReceiverAccess[T]) Access(ctx context.Context, user identity.Requester,
|
||||
permSet.Set(models.ReceiverPermissionReadSecret, err == nil)
|
||||
}
|
||||
|
||||
// TODO: Add when resource permissions are implemented.
|
||||
//if _, ok := permSet.Has(models.ReceiverPermissionAdmin); !ok {
|
||||
// err := s.permissions.authorize(ctx, user, rcv)
|
||||
// permSet.Set(models.ReceiverPermissionAdmin, err == nil)
|
||||
//}
|
||||
if _, ok := permSet.Has(models.ReceiverPermissionAdmin); !ok {
|
||||
err := s.permissions.authorize(ctx, user, rcv)
|
||||
permSet.Set(models.ReceiverPermissionAdmin, err == nil)
|
||||
}
|
||||
|
||||
if _, ok := permSet.Has(models.ReceiverPermissionWrite); !ok {
|
||||
err := s.update.authorize(ctx, user, rcv)
|
||||
|
@ -238,6 +238,65 @@ func TestReceiverAccess(t *testing.T) {
|
||||
recv3.UID: permissions(),
|
||||
},
|
||||
},
|
||||
// Receiver admin.
|
||||
{
|
||||
name: "receiver read permissions alone can't admin",
|
||||
user: newViewUser(ac.Permission{Action: ac.ActionAlertingReceiversPermissionsRead, Scope: ScopeReceiversAll}),
|
||||
expected: map[string]models.ReceiverPermissionSet{
|
||||
recv1.UID: permissions(),
|
||||
recv2.UID: permissions(),
|
||||
recv3.UID: permissions(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "receiver write permissions alone can't admin",
|
||||
user: newViewUser(ac.Permission{Action: ac.ActionAlertingReceiversPermissionsWrite, Scope: ScopeReceiversAll}),
|
||||
expected: map[string]models.ReceiverPermissionSet{
|
||||
recv1.UID: permissions(),
|
||||
recv2.UID: permissions(),
|
||||
recv3.UID: permissions(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "global receiver read + write permissions can admin",
|
||||
user: newViewUser(
|
||||
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsRead, Scope: ScopeReceiversAll},
|
||||
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsWrite, Scope: ScopeReceiversAll},
|
||||
),
|
||||
expected: map[string]models.ReceiverPermissionSet{
|
||||
recv1.UID: permissions(models.ReceiverPermissionAdmin),
|
||||
recv2.UID: permissions(models.ReceiverPermissionAdmin),
|
||||
recv3.UID: permissions(models.ReceiverPermissionAdmin),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "per-receiver read + write permissions should have per-receiver admin",
|
||||
user: newViewUser(
|
||||
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsRead, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
||||
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsWrite, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
||||
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsRead, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
||||
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsWrite, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
||||
),
|
||||
expected: map[string]models.ReceiverPermissionSet{
|
||||
recv1.UID: permissions(models.ReceiverPermissionAdmin),
|
||||
recv2.UID: permissions(),
|
||||
recv3.UID: permissions(models.ReceiverPermissionAdmin),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "per-receiver admin should require read",
|
||||
user: newEmptyUser(
|
||||
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsRead, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
||||
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsWrite, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
||||
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsRead, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
||||
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsWrite, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
||||
),
|
||||
expected: map[string]models.ReceiverPermissionSet{
|
||||
recv1.UID: permissions(),
|
||||
recv2.UID: permissions(),
|
||||
recv3.UID: permissions(),
|
||||
},
|
||||
},
|
||||
// Mixed permissions.
|
||||
{
|
||||
name: "legacy provisioning secret read, receiver write",
|
||||
|
@ -10,16 +10,16 @@ type ReceiverPermission string
|
||||
|
||||
const (
|
||||
ReceiverPermissionReadSecret ReceiverPermission = "secrets"
|
||||
//ReceiverPermissionAdmin ReceiverPermission = "admin" // TODO: Add when resource permissions are implemented.
|
||||
ReceiverPermissionWrite ReceiverPermission = "write"
|
||||
ReceiverPermissionDelete ReceiverPermission = "delete"
|
||||
ReceiverPermissionAdmin ReceiverPermission = "admin"
|
||||
ReceiverPermissionWrite ReceiverPermission = "write"
|
||||
ReceiverPermissionDelete ReceiverPermission = "delete"
|
||||
)
|
||||
|
||||
// ReceiverPermissions returns all possible silence permissions.
|
||||
func ReceiverPermissions() []ReceiverPermission {
|
||||
return []ReceiverPermission{
|
||||
ReceiverPermissionReadSecret,
|
||||
//ReceiverPermissionAdmin, // TODO: Add when resource permissions are implemented.
|
||||
ReceiverPermissionAdmin,
|
||||
ReceiverPermissionWrite,
|
||||
ReceiverPermissionDelete,
|
||||
}
|
||||
|
@ -489,7 +489,7 @@ func (ng *AlertNG) init() error {
|
||||
return key.LogContext(), true
|
||||
})
|
||||
|
||||
return DeclareFixedRoles(ng.accesscontrolService)
|
||||
return DeclareFixedRoles(ng.accesscontrolService, ng.FeatureToggles)
|
||||
}
|
||||
|
||||
func subscribeToFolderChanges(logger log.Logger, bus bus.Bus, dbStore api.RuleStore) {
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
notificationsv0alpha1 "github.com/grafana/grafana/pkg/generated/clientset/versioned/typed/alerting_notifications/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
@ -142,6 +143,7 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
canCreate bool
|
||||
canDelete bool
|
||||
canReadSecrets bool
|
||||
canAdmin bool
|
||||
}
|
||||
// region users
|
||||
unauthorized := helper.CreateUser("unauthorized", "Org1", org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{})
|
||||
@ -185,6 +187,12 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
},
|
||||
},
|
||||
})
|
||||
adminLikeUser := helper.CreateUser("adminLikeUser", apis.Org1, org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{
|
||||
createWildcardPermission(append(
|
||||
[]string{accesscontrol.ActionAlertingReceiversCreate},
|
||||
ossaccesscontrol.ReceiversAdminActions...,
|
||||
)...),
|
||||
})
|
||||
|
||||
// endregion
|
||||
|
||||
@ -197,11 +205,13 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
canDelete: false,
|
||||
},
|
||||
{
|
||||
user: org1.Admin,
|
||||
canRead: true,
|
||||
canUpdate: true,
|
||||
canCreate: true,
|
||||
canDelete: true,
|
||||
user: org1.Admin,
|
||||
canRead: true,
|
||||
canCreate: true,
|
||||
canUpdate: true,
|
||||
canDelete: true,
|
||||
canAdmin: true,
|
||||
canReadSecrets: true,
|
||||
},
|
||||
{
|
||||
user: org1.Editor,
|
||||
@ -249,6 +259,15 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
canUpdate: true,
|
||||
canDelete: true,
|
||||
},
|
||||
{
|
||||
user: adminLikeUser,
|
||||
canRead: true,
|
||||
canCreate: true,
|
||||
canUpdate: true,
|
||||
canDelete: true,
|
||||
canAdmin: true,
|
||||
canReadSecrets: true,
|
||||
},
|
||||
}
|
||||
|
||||
admin := org1.Admin
|
||||
@ -315,6 +334,9 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
if tc.canReadSecrets {
|
||||
expectedWithMetadata.SetAccessControl("canReadSecrets")
|
||||
}
|
||||
if tc.canAdmin {
|
||||
expectedWithMetadata.SetAccessControl("canAdmin")
|
||||
}
|
||||
t.Run("should be able to list receivers", func(t *testing.T) {
|
||||
list, err := client.List(ctx, v1.ListOptions{})
|
||||
require.NoError(t, err)
|
||||
@ -1027,6 +1049,8 @@ func TestIntegrationCRUD(t *testing.T) {
|
||||
// Set expected metadata
|
||||
receiver.SetAccessControl("canWrite")
|
||||
receiver.SetAccessControl("canDelete")
|
||||
receiver.SetAccessControl("canReadSecrets")
|
||||
receiver.SetAccessControl("canAdmin")
|
||||
receiver.SetInUse(0, nil)
|
||||
|
||||
// Use export endpoint because it's the only way to get decrypted secrets fast.
|
||||
|
Loading…
Reference in New Issue
Block a user