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>
This commit is contained in:
Yuri Tseretyan
2024-03-22 15:37:10 -04:00
committed by GitHub
co-authored by Alexander Weaver
parent 0b4830ccfd
commit b9abb8cabb
21 changed files with 2039 additions and 108 deletions
+80 -14
View File
@@ -223,19 +223,90 @@ func (api *API) authorize(method, path string) web.Handler {
ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets), // organization scope
)
case http.MethodGet + "/api/v1/provisioning/alert-rules",
http.MethodGet + "/api/v1/provisioning/alert-rules/export":
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningRead),
ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets),
ac.EvalAll( // scopes are enforced in the handler
ac.EvalPermission(ac.ActionAlertingRuleRead),
ac.EvalPermission(dashboards.ActionFoldersRead),
),
)
case http.MethodGet + "/api/v1/provisioning/alert-rules/{UID}",
http.MethodGet + "/api/v1/provisioning/alert-rules/{UID}/export":
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningRead),
ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets),
ac.EvalAll(
ac.EvalPermission(ac.ActionAlertingRuleRead),
ac.EvalPermission(dashboards.ActionFoldersRead),
),
)
case http.MethodGet + "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}",
http.MethodGet + "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}/export":
scope := dashboards.ScopeFoldersProvider.GetResourceScopeUID(ac.Parameter(":FolderUID"))
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningRead),
ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets),
ac.EvalAll(
ac.EvalPermission(ac.ActionAlertingRuleRead, scope),
ac.EvalPermission(dashboards.ActionFoldersRead, scope),
),
)
case http.MethodGet + "/api/v1/provisioning/policies",
http.MethodGet + "/api/v1/provisioning/contact-points",
http.MethodGet + "/api/v1/provisioning/templates",
http.MethodGet + "/api/v1/provisioning/templates/{name}",
http.MethodGet + "/api/v1/provisioning/mute-timings",
http.MethodGet + "/api/v1/provisioning/mute-timings/{name}",
http.MethodGet + "/api/v1/provisioning/alert-rules",
http.MethodGet + "/api/v1/provisioning/alert-rules/{UID}",
http.MethodGet + "/api/v1/provisioning/alert-rules/export",
http.MethodGet + "/api/v1/provisioning/alert-rules/{UID}/export",
http.MethodGet + "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}",
http.MethodGet + "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}/export":
eval = ac.EvalAny(ac.EvalPermission(ac.ActionAlertingProvisioningRead), ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets)) // organization scope
http.MethodGet + "/api/v1/provisioning/mute-timings/{name}":
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningRead),
ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets),
)
// Grafana-only Provisioning Write Paths
case http.MethodPost + "/api/v1/provisioning/alert-rules":
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningWrite),
ac.EvalPermission(ac.ActionAlertingRuleCreate), // more granular permissions are enforced by the handler via "authorizeRuleChanges"
)
case http.MethodPut + "/api/v1/provisioning/alert-rules/{UID}":
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningWrite),
ac.EvalPermission(ac.ActionAlertingRuleUpdate), // more granular permissions are enforced by the handler via "authorizeRuleChanges"
)
case http.MethodDelete + "/api/v1/provisioning/alert-rules/{UID}":
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningWrite),
ac.EvalPermission(ac.ActionAlertingRuleDelete), // more granular permissions are enforced by the handler via "authorizeRuleChanges"
)
case http.MethodDelete + "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}":
scope := dashboards.ScopeFoldersProvider.GetResourceScopeUID(ac.Parameter(":FolderUID"))
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningWrite),
ac.EvalAll(
ac.EvalPermission(ac.ActionAlertingRuleDelete, scope),
ac.EvalPermission(ac.ActionAlertingRuleRead, scope),
ac.EvalPermission(dashboards.ActionFoldersRead, scope),
),
)
case http.MethodPut + "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}":
scope := dashboards.ScopeFoldersProvider.GetResourceScopeUID(ac.Parameter(":FolderUID"))
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningWrite),
ac.EvalAll(
ac.EvalPermission(ac.ActionAlertingRuleRead, scope),
ac.EvalPermission(dashboards.ActionFoldersRead, scope),
ac.EvalAny( // the exact permissions will be checked after the operations are determined
ac.EvalPermission(ac.ActionAlertingRuleUpdate, scope),
ac.EvalPermission(ac.ActionAlertingRuleCreate, scope),
ac.EvalPermission(ac.ActionAlertingRuleDelete, scope),
),
),
)
case http.MethodPut + "/api/v1/provisioning/policies",
http.MethodDelete + "/api/v1/provisioning/policies",
@@ -246,12 +317,7 @@ func (api *API) authorize(method, path string) web.Handler {
http.MethodDelete + "/api/v1/provisioning/templates/{name}",
http.MethodPost + "/api/v1/provisioning/mute-timings",
http.MethodPut + "/api/v1/provisioning/mute-timings/{name}",
http.MethodDelete + "/api/v1/provisioning/mute-timings/{name}",
http.MethodPost + "/api/v1/provisioning/alert-rules",
http.MethodPut + "/api/v1/provisioning/alert-rules/{UID}",
http.MethodDelete + "/api/v1/provisioning/alert-rules/{UID}",
http.MethodPut + "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}",
http.MethodDelete + "/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}":
http.MethodDelete + "/api/v1/provisioning/mute-timings/{name}":
eval = ac.EvalPermission(ac.ActionAlertingProvisioningWrite) // organization scope
case http.MethodGet + "/api/v1/notifications/time-intervals/{name}",
http.MethodGet + "/api/v1/notifications/time-intervals":