Alerting: Add access control to receiver status API (#94287)

This commit is contained in:
Yuri Tseretyan 2024-10-07 15:21:29 -04:00 committed by GitHub
parent cc40211f71
commit 4c1cb79069
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 28 additions and 2 deletions

View File

@ -110,6 +110,7 @@ func (api *API) RegisterAPIEndpoints(m *metrics.API) {
api.RuleStore,
ruleAuthzService,
),
receiverAuthz: accesscontrol.NewReceiverAccess[ReceiverStatus](api.AccessControl, false),
},
), m)
// Register endpoints for proxying to Prometheus-compatible backends.

View File

@ -12,12 +12,14 @@ import (
alertingNotify "github.com/grafana/alerting/notify"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/accesscontrol"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/featuremgmt"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/notifier"
"github.com/grafana/grafana/pkg/services/ngalert/notifier/legacy_storage"
"github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/util"
@ -28,6 +30,10 @@ const (
maxTestReceiversTimeout = 30 * time.Second
)
type receiversAuthz interface {
FilterRead(ctx context.Context, user identity.Requester, receivers ...ReceiverStatus) ([]ReceiverStatus, error)
}
type AlertmanagerSrv struct {
log log.Logger
ac accesscontrol.AccessControl
@ -35,6 +41,7 @@ type AlertmanagerSrv struct {
crypto notifier.Crypto
silenceSvc SilenceService
featureManager featuremgmt.FeatureToggles
receiverAuthz receiversAuthz
}
type UnknownReceiverError struct {
@ -237,7 +244,15 @@ func (srv AlertmanagerSrv) RouteGetReceivers(c *contextmodel.ReqContext) respons
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "failed to retrieve receivers")
}
return response.JSON(http.StatusOK, rcvs)
statuses := make([]ReceiverStatus, 0, len(rcvs))
for _, rcv := range rcvs { // TODO this is temporary so we can use authz filter logic.
statuses = append(statuses, ReceiverStatus(rcv))
}
statuses, err = srv.receiverAuthz.FilterRead(c.Req.Context(), c.SignedInUser, statuses...)
if err != nil {
response.ErrOrFallback(http.StatusInternalServerError, "failed to apply permissions to the receivers", err)
}
return response.JSON(http.StatusOK, statuses)
}
func (srv AlertmanagerSrv) RoutePostTestReceivers(c *contextmodel.ReqContext, body apimodels.TestReceiversConfigBodyParams) response.Response {
@ -368,3 +383,9 @@ func (srv AlertmanagerSrv) AlertmanagerFor(orgID int64) (notifier.Alertmanager,
srv.log.Error("Unable to obtain the org's Alertmanager", "error", err)
return nil, response.Error(http.StatusInternalServerError, "unable to obtain org's Alertmanager", err)
}
type ReceiverStatus apimodels.Receiver
func (rs ReceiverStatus) GetUID() string {
return legacy_storage.NameToUid(rs.Name)
}

View File

@ -210,7 +210,11 @@ func (api *API) authorize(method, path string) web.Handler {
case http.MethodPost + "/api/alertmanager/grafana/config/history/{id}/_activate":
eval = ac.EvalAny(ac.EvalPermission(ac.ActionAlertingNotificationsWrite))
case http.MethodGet + "/api/alertmanager/grafana/config/api/v1/receivers":
eval = ac.EvalPermission(ac.ActionAlertingNotificationsRead)
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingNotificationsRead),
ac.EvalPermission(ac.ActionAlertingReceiversRead),
ac.EvalPermission(ac.ActionAlertingReceiversReadSecrets),
)
case http.MethodPost + "/api/alertmanager/grafana/config/api/v1/receivers/test":
eval = ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingNotificationsWrite),