Alerting: Protected fields for Contact points (#115442)

* Alerting: Protect sensitive fields of contact points from
 unauthorized modification

- Introduce a new permission alert.notifications.receivers.protected:write. The permission is granted to contact point administrators.
- Introduce field Protected to NotifierOption
- Introduce DiffReport for models.Integrations with focus on Settings. The diff report is extended with methods that return all keys that are different between two settings.
- Add new annotation 'grafana.com/access/CanModifyProtected' to Receiver model
- Update receiver service to enforce the permission and return status 403 if unauthorized user modifies protected field
- Update receiver testing API to enforce permission and return status 403 if unauthorized user modifies protected field.
- Update UI to disable protected fields if user cannot modify them
This commit is contained in:
Yuri Tseretyan
2025-12-16 15:56:02 -05:00
committed by GitHub
parent 30fb1c032a
commit f2c30cbbd1
37 changed files with 1482 additions and 114 deletions
+9 -1
View File
@@ -10,8 +10,10 @@ import (
"time"
alertingNotify "github.com/grafana/alerting/notify"
"github.com/grafana/alerting/receivers/schema"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/apimachinery/errutil"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/accesscontrol"
@@ -32,6 +34,7 @@ const (
type receiversAuthz interface {
FilterRead(ctx context.Context, user identity.Requester, receivers ...ReceiverStatus) ([]ReceiverStatus, error)
AuthorizeUpdateProtected(context.Context, identity.Requester, ReceiverStatus) error
}
type AlertmanagerSrv struct {
@@ -210,11 +213,16 @@ func (srv AlertmanagerSrv) RouteGetReceivers(c *contextmodel.ReqContext) respons
}
func (srv AlertmanagerSrv) RoutePostTestReceivers(c *contextmodel.ReqContext, body apimodels.TestReceiversConfigBodyParams) response.Response {
if err := srv.crypto.ProcessSecureSettings(c.Req.Context(), c.GetOrgID(), body.Receivers); err != nil {
if err := srv.crypto.ProcessSecureSettings(c.Req.Context(), c.GetOrgID(), body.Receivers, func(receiverName string, paths []schema.IntegrationFieldPath) error {
return srv.receiverAuthz.AuthorizeUpdateProtected(c.Req.Context(), c.SignedInUser, ReceiverStatus{Name: receiverName})
}); err != nil {
var unknownReceiverError UnknownReceiverError
if errors.As(err, &unknownReceiverError) {
return ErrResp(http.StatusBadRequest, err, "")
}
if errors.As(err, &errutil.Error{}) {
return response.Err(err)
}
return ErrResp(http.StatusInternalServerError, err, "failed to post process Alertmanager configuration")
}