grafana/pkg/services/ngalert/provisioning/accesscontrol.go
Yuri Tseretyan b9abb8cabb
Alerting: Update provisioning API to support regular permissions (#77007)
* allow users with regular actions access provisioning API paths
* update methods that read rules
skip new authorization logic if user CanReadAllRules to avoid performance impact on file-provisioning
update all methods to accept identity.Requester that contains all permissions and is required by access control.

* create deltas for single rul e 

* update modify methods
skip new authorization logic if user CanWriteAllRules to avoid performance impact on file-provisioning
update all methods to accept identity.Requester that contains all permissions and is required by access control.

* implement RuleAccessControlService in provisioning

* update file provisioning user to have all permissions to bypass authz

* update provisioning API to return errutil errors correctly

---------

Co-authored-by: Alexander Weaver <weaver.alex.d@gmail.com>
2024-03-22 15:37:10 -04:00

77 lines
3.3 KiB
Go

package provisioning
import (
"context"
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/store"
)
type RuleAccessControlService interface {
HasAccess(ctx context.Context, user identity.Requester, evaluator ac.Evaluator) (bool, error)
AuthorizeAccessToRuleGroup(ctx context.Context, user identity.Requester, rules models.RulesGroup) error
AuthorizeRuleChanges(ctx context.Context, user identity.Requester, change *store.GroupDelta) error
}
func newRuleAccessControlService(ac RuleAccessControlService) *provisioningRuleAccessControl {
return &provisioningRuleAccessControl{
RuleAccessControlService: ac,
}
}
type provisioningRuleAccessControl struct {
RuleAccessControlService
}
var _ ruleAccessControlService = &provisioningRuleAccessControl{}
// AuthorizeRuleGroupRead authorizes the read access to a group of rules for a user.
// It first checks if the user has permission to read all rules. If yes, it bypasses the authorization.
// If not, it calls the RuleAccessControlService to authorize access to the rule group.
// It returns an error if the authorization fails or if there is an error during permission check.
func (p *provisioningRuleAccessControl) AuthorizeRuleGroupRead(ctx context.Context, user identity.Requester, rules models.RulesGroup) error {
can, err := p.CanReadAllRules(ctx, user)
if err != nil {
return err
}
if !can {
return p.RuleAccessControlService.AuthorizeAccessToRuleGroup(ctx, user, rules)
}
return nil
}
// AuthorizeRuleGroupWrite authorizes the write access to a group of rules for a user.
// It first checks if the user has permission to write all rules. If yes, it bypasses the authorization.
// If not, it calls the RuleAccessControlService to authorize the rule changes.
// It returns an error if the authorization fails or if there is an error during permission check.
func (p *provisioningRuleAccessControl) AuthorizeRuleGroupWrite(ctx context.Context, user identity.Requester, change *store.GroupDelta) error {
can, err := p.CanWriteAllRules(ctx, user)
if err != nil {
return err
}
if !can {
return p.RuleAccessControlService.AuthorizeRuleChanges(ctx, user, change)
}
return nil
}
// CanReadAllRules checks if the user has permission to read all rules.
// It evaluates if the user has either "alert.provisioning:read" or "alert.provisioning.secrets:read" permissions.
// It returns true if the user has the required permissions, otherwise it returns false.
func (p *provisioningRuleAccessControl) CanReadAllRules(ctx context.Context, user identity.Requester) (bool, error) {
return p.HasAccess(ctx, user, ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningRead),
ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets),
))
}
// CanWriteAllRules is a method that checks if a user has permission to write all rules.
// It calls the HasAccess method with the provided action "alert.provisioning:write".
// It returns true if the user has permission, false otherwise.
// It returns an error if there is a problem checking the permission.
func (p *provisioningRuleAccessControl) CanWriteAllRules(ctx context.Context, user identity.Requester) (bool, error) {
return p.HasAccess(ctx, user, ac.EvalPermission(ac.ActionAlertingProvisioningWrite))
}