[v11.0.x] Alerting: Add two sets of provisioning actions for rules and notifications (#87572)

Alerting: Add two sets of provisioning actions for rules and notifications  (#87149)

(cherry picked from commit 356a29592b)

Co-authored-by: Yuri Tseretyan <yuriy.tseretyan@grafana.com>
This commit is contained in:
grafana-delivery-bot[bot]
2024-05-09 14:24:59 -04:00
committed by GitHub
co-authored by Yuri Tseretyan
parent 0bf33a4bf6
commit 0a2f239744
5 changed files with 63 additions and 11 deletions
+8 -3
View File
@@ -466,9 +466,14 @@ const (
ActionAlertingNotificationsExternalRead = "alert.notifications.external:read"
// Alerting provisioning actions
ActionAlertingProvisioningRead = "alert.provisioning:read"
ActionAlertingProvisioningReadSecrets = "alert.provisioning.secrets:read"
ActionAlertingProvisioningWrite = "alert.provisioning:write"
ActionAlertingProvisioningRead = "alert.provisioning:read"
ActionAlertingProvisioningReadSecrets = "alert.provisioning.secrets:read"
ActionAlertingProvisioningWrite = "alert.provisioning:write"
ActionAlertingRulesProvisioningRead = "alert.rules.provisioning:read"
ActionAlertingRulesProvisioningWrite = "alert.rules.provisioning:write"
ActionAlertingNotificationsProvisioningRead = "alert.notifications.provisioning:read"
ActionAlertingNotificationsProvisioningWrite = "alert.notifications.provisioning:write"
// ActionAlertingProvisioningSetStatus Gives access to set provisioning status to alerting resources. Cannot be used alone. Only in conjunction with other permissions.
ActionAlertingProvisioningSetStatus = "alert.provisioning.provenance:write"
+18
View File
@@ -179,6 +179,18 @@ var (
{
Action: accesscontrol.ActionAlertingProvisioningWrite, // organization scope
},
{
Action: accesscontrol.ActionAlertingRulesProvisioningRead, // organization scope
},
{
Action: accesscontrol.ActionAlertingRulesProvisioningWrite, // organization scope
},
{
Action: accesscontrol.ActionAlertingNotificationsProvisioningRead, // organization scope
},
{
Action: accesscontrol.ActionAlertingNotificationsProvisioningWrite, // organization scope
},
{
Action: dashboards.ActionFoldersRead,
Scope: dashboards.ScopeFoldersAll,
@@ -201,6 +213,12 @@ var (
{
Action: accesscontrol.ActionAlertingProvisioningRead, // organization scope
},
{
Action: accesscontrol.ActionAlertingRulesProvisioningRead, // organization scope
},
{
Action: accesscontrol.ActionAlertingNotificationsProvisioningRead, // organization scope
},
},
},
Grants: []string{string(org.RoleAdmin)},
+21 -5
View File
@@ -218,15 +218,17 @@ func (api *API) authorize(method, path string) web.Handler {
http.MethodGet + "/api/v1/provisioning/mute-timings/export",
http.MethodGet + "/api/v1/provisioning/mute-timings/{name}/export":
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingNotificationsRead), // organization scope
ac.EvalPermission(ac.ActionAlertingProvisioningRead), // organization scope
ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets), // organization scope
ac.EvalPermission(ac.ActionAlertingNotificationsRead), // organization scope
ac.EvalPermission(ac.ActionAlertingProvisioningRead), // organization scope
ac.EvalPermission(ac.ActionAlertingNotificationsProvisioningRead), // organization scope
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.ActionAlertingRulesProvisioningRead),
ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets),
ac.EvalAll( // scopes are enforced in the handler
ac.EvalPermission(ac.ActionAlertingRuleRead),
@@ -237,6 +239,7 @@ func (api *API) authorize(method, path string) web.Handler {
http.MethodGet + "/api/v1/provisioning/alert-rules/{UID}/export":
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningRead),
ac.EvalPermission(ac.ActionAlertingRulesProvisioningRead),
ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets),
ac.EvalAll(
ac.EvalPermission(ac.ActionAlertingRuleRead),
@@ -249,6 +252,7 @@ func (api *API) authorize(method, path string) web.Handler {
scope := dashboards.ScopeFoldersProvider.GetResourceScopeUID(ac.Parameter(":FolderUID"))
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningRead),
ac.EvalPermission(ac.ActionAlertingRulesProvisioningRead),
ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets),
ac.EvalAll(
ac.EvalPermission(ac.ActionAlertingRuleRead, scope),
@@ -264,6 +268,7 @@ func (api *API) authorize(method, path string) web.Handler {
http.MethodGet + "/api/v1/provisioning/mute-timings/{name}":
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningRead),
ac.EvalPermission(ac.ActionAlertingNotificationsProvisioningRead), // organization scope
ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets),
ac.EvalPermission(ac.ActionAlertingNotificationsRead),
)
@@ -272,6 +277,7 @@ func (api *API) authorize(method, path string) web.Handler {
case http.MethodPost + "/api/v1/provisioning/alert-rules":
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningWrite),
ac.EvalPermission(ac.ActionAlertingRulesProvisioningWrite),
ac.EvalAll(
ac.EvalPermission(ac.ActionAlertingRuleCreate), // more granular permissions are enforced by the handler via "authorizeRuleChanges"
ac.EvalPermission(ac.ActionAlertingProvisioningSetStatus),
@@ -280,6 +286,7 @@ func (api *API) authorize(method, path string) web.Handler {
case http.MethodPut + "/api/v1/provisioning/alert-rules/{UID}":
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningWrite),
ac.EvalPermission(ac.ActionAlertingRulesProvisioningWrite),
ac.EvalAll(
ac.EvalPermission(ac.ActionAlertingRuleUpdate), // more granular permissions are enforced by the handler via "authorizeRuleChanges"
ac.EvalPermission(ac.ActionAlertingProvisioningSetStatus),
@@ -288,6 +295,7 @@ func (api *API) authorize(method, path string) web.Handler {
case http.MethodDelete + "/api/v1/provisioning/alert-rules/{UID}":
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningWrite),
ac.EvalPermission(ac.ActionAlertingRulesProvisioningWrite),
ac.EvalAll(
ac.EvalPermission(ac.ActionAlertingRuleDelete), // more granular permissions are enforced by the handler via "authorizeRuleChanges"
ac.EvalPermission(ac.ActionAlertingProvisioningSetStatus),
@@ -297,6 +305,7 @@ func (api *API) authorize(method, path string) web.Handler {
scope := dashboards.ScopeFoldersProvider.GetResourceScopeUID(ac.Parameter(":FolderUID"))
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningWrite),
ac.EvalPermission(ac.ActionAlertingRulesProvisioningWrite),
ac.EvalAll(
ac.EvalPermission(ac.ActionAlertingRuleDelete, scope),
ac.EvalPermission(ac.ActionAlertingRuleRead, scope),
@@ -308,6 +317,7 @@ func (api *API) authorize(method, path string) web.Handler {
scope := dashboards.ScopeFoldersProvider.GetResourceScopeUID(ac.Parameter(":FolderUID"))
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningWrite),
ac.EvalPermission(ac.ActionAlertingRulesProvisioningWrite),
ac.EvalAll(
ac.EvalPermission(ac.ActionAlertingRuleRead, scope),
ac.EvalPermission(dashboards.ActionFoldersRead, scope),
@@ -331,7 +341,8 @@ func (api *API) authorize(method, path string) web.Handler {
http.MethodPut + "/api/v1/provisioning/mute-timings/{name}",
http.MethodDelete + "/api/v1/provisioning/mute-timings/{name}":
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningWrite), // organization scope,
ac.EvalPermission(ac.ActionAlertingProvisioningWrite), // organization scope,
ac.EvalPermission(ac.ActionAlertingNotificationsProvisioningWrite), // organization scope
ac.EvalAll(
ac.EvalPermission(ac.ActionAlertingNotificationsWrite),
ac.EvalPermission(ac.ActionAlertingProvisioningSetStatus),
@@ -339,7 +350,12 @@ func (api *API) authorize(method, path string) web.Handler {
)
case http.MethodGet + "/api/v1/notifications/time-intervals/{name}",
http.MethodGet + "/api/v1/notifications/time-intervals":
eval = ac.EvalAny(ac.EvalPermission(ac.ActionAlertingNotificationsRead), ac.EvalPermission(ac.ActionAlertingNotificationsTimeIntervalsRead), ac.EvalPermission(ac.ActionAlertingProvisioningRead))
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingNotificationsRead),
ac.EvalPermission(ac.ActionAlertingNotificationsTimeIntervalsRead),
ac.EvalPermission(ac.ActionAlertingProvisioningRead),
ac.EvalPermission(ac.ActionAlertingNotificationsProvisioningRead), // organization scope
)
}
if eval != nil {
@@ -64,6 +64,7 @@ func (p *provisioningRuleAccessControl) CanReadAllRules(ctx context.Context, use
return p.HasAccess(ctx, user, ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningRead),
ac.EvalPermission(ac.ActionAlertingProvisioningReadSecrets),
ac.EvalPermission(ac.ActionAlertingRulesProvisioningRead),
))
}
@@ -72,5 +73,8 @@ func (p *provisioningRuleAccessControl) CanReadAllRules(ctx context.Context, use
// 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))
return p.HasAccess(ctx, user, ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingProvisioningWrite),
ac.EvalPermission(ac.ActionAlertingRulesProvisioningWrite),
))
}
@@ -36,6 +36,7 @@ func TestCanReadAllRules(t *testing.T) {
require.Equal(t, accesscontrol.EvalAny(
accesscontrol.EvalPermission(accesscontrol.ActionAlertingProvisioningRead),
accesscontrol.EvalPermission(accesscontrol.ActionAlertingProvisioningReadSecrets),
accesscontrol.EvalPermission(accesscontrol.ActionAlertingRulesProvisioningRead),
).GoString(), rs.Calls[0].Arguments[2].(accesscontrol.Evaluator).GoString())
})
@@ -67,7 +68,11 @@ func TestCanWriteAllRules(t *testing.T) {
require.Len(t, rs.Calls, 1)
require.Equal(t, "HasAccess", rs.Calls[0].MethodName)
require.Equal(t, accesscontrol.EvalPermission(accesscontrol.ActionAlertingProvisioningWrite).GoString(), rs.Calls[0].Arguments[2].(accesscontrol.Evaluator).GoString())
require.Equal(t,
accesscontrol.EvalAny(
accesscontrol.EvalPermission(accesscontrol.ActionAlertingProvisioningWrite),
accesscontrol.EvalPermission(accesscontrol.ActionAlertingRulesProvisioningWrite),
).GoString(), rs.Calls[0].Arguments[2].(accesscontrol.Evaluator).GoString())
})
t.Run("should return error", func(t *testing.T) {
@@ -104,6 +109,7 @@ func TestAuthorizeAccessToRuleGroup(t *testing.T) {
assert.Equal(t, accesscontrol.EvalAny(
accesscontrol.EvalPermission(accesscontrol.ActionAlertingProvisioningRead),
accesscontrol.EvalPermission(accesscontrol.ActionAlertingProvisioningReadSecrets),
accesscontrol.EvalPermission(accesscontrol.ActionAlertingRulesProvisioningRead),
).GoString(), rs.Calls[0].Arguments[2].(accesscontrol.Evaluator).GoString())
assert.Equal(t, testUser, rs.Calls[0].Arguments[1])
})
@@ -176,7 +182,10 @@ func TestAuthorizeRuleChanges(t *testing.T) {
require.Len(t, rs.Calls, 1)
require.Equal(t, "HasAccess", rs.Calls[0].MethodName)
assert.Equal(t, accesscontrol.EvalPermission(accesscontrol.ActionAlertingProvisioningWrite).GoString(), rs.Calls[0].Arguments[2].(accesscontrol.Evaluator).GoString())
assert.Equal(t, accesscontrol.EvalAny(
accesscontrol.EvalPermission(accesscontrol.ActionAlertingProvisioningWrite),
accesscontrol.EvalPermission(accesscontrol.ActionAlertingRulesProvisioningWrite),
).GoString(), rs.Calls[0].Arguments[2].(accesscontrol.Evaluator).GoString())
assert.Equal(t, testUser, rs.Calls[0].Arguments[1])
})