diff --git a/pkg/services/ngalert/provisioning/compat.go b/pkg/services/ngalert/provisioning/compat.go index edd9a23bc15..621ce88b4f5 100644 --- a/pkg/services/ngalert/provisioning/compat.go +++ b/pkg/services/ngalert/provisioning/compat.go @@ -3,7 +3,9 @@ package provisioning import ( alertingNotify "github.com/grafana/alerting/notify" + "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" + "github.com/grafana/grafana/pkg/services/ngalert/models" ) func EmbeddedContactPointToGrafanaIntegrationConfig(e definitions.EmbeddedContactPoint) (alertingNotify.GrafanaIntegrationConfig, error) { @@ -20,3 +22,26 @@ func EmbeddedContactPointToGrafanaIntegrationConfig(e definitions.EmbeddedContac SecureSettings: nil, }, nil } + +func PostableGrafanaReceiverToEmbeddedContactPoint(contactPoint *definitions.PostableGrafanaReceiver, provenance models.Provenance, decryptValue func(string) string) (definitions.EmbeddedContactPoint, error) { + simpleJson, err := simplejson.NewJson(contactPoint.Settings) + if err != nil { + return definitions.EmbeddedContactPoint{}, err + } + embeddedContactPoint := definitions.EmbeddedContactPoint{ + UID: contactPoint.UID, + Type: contactPoint.Type, + Name: contactPoint.Name, + DisableResolveMessage: contactPoint.DisableResolveMessage, + Settings: simpleJson, + Provenance: string(provenance), + } + for k, v := range contactPoint.SecureSettings { + decryptedValue := decryptValue(v) + if decryptedValue == "" { + continue + } + embeddedContactPoint.Settings.Set(k, decryptedValue) + } + return embeddedContactPoint, nil +} diff --git a/pkg/services/ngalert/provisioning/contactpoints.go b/pkg/services/ngalert/provisioning/contactpoints.go index 010b530e565..d20415fc634 100644 --- a/pkg/services/ngalert/provisioning/contactpoints.go +++ b/pkg/services/ngalert/provisioning/contactpoints.go @@ -12,7 +12,6 @@ import ( alertingNotify "github.com/grafana/alerting/notify" "github.com/prometheus/alertmanager/config" - "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/accesscontrol" apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" @@ -77,42 +76,21 @@ func (ecp *ContactPointService) GetContactPoints(ctx context.Context, q ContactP if err != nil { return nil, err } - contactPoints := []apimodels.EmbeddedContactPoint{} + var contactPoints []apimodels.EmbeddedContactPoint + for _, contactPoint := range revision.cfg.GetGrafanaReceiverMap() { if q.Name != "" && contactPoint.Name != q.Name { continue } - simpleJson, err := simplejson.NewJson(contactPoint.Settings) + embeddedContactPoint, err := PostableGrafanaReceiverToEmbeddedContactPoint( + contactPoint, + provenances[contactPoint.UID], + ecp.decryptValueOrRedacted(q.Decrypt, contactPoint.UID), + ) if err != nil { return nil, err } - embeddedContactPoint := apimodels.EmbeddedContactPoint{ - UID: contactPoint.UID, - Type: contactPoint.Type, - Name: contactPoint.Name, - DisableResolveMessage: contactPoint.DisableResolveMessage, - Settings: simpleJson, - } - if val, exists := provenances[embeddedContactPoint.UID]; exists && val != "" { - embeddedContactPoint.Provenance = string(val) - } - for k, v := range contactPoint.SecureSettings { - decryptedValue, err := ecp.decryptValue(v) - if err != nil { - ecp.log.Warn("Decrypting value failed", "error", err.Error()) - continue - } - if decryptedValue == "" { - continue - } - if q.Decrypt { - embeddedContactPoint.Settings.Set(k, decryptedValue) - } else { - embeddedContactPoint.Settings.Set(k, apimodels.RedactedValue) - } - } - contactPoints = append(contactPoints, embeddedContactPoint) } sort.SliceStable(contactPoints, func(i, j int) bool { @@ -138,28 +116,14 @@ func (ecp *ContactPointService) getContactPointDecrypted(ctx context.Context, or if receiver.UID != uid { continue } - simpleJson, err := simplejson.NewJson(receiver.Settings) + embeddedContactPoint, err := PostableGrafanaReceiverToEmbeddedContactPoint( + receiver, + models.ProvenanceNone, + ecp.decryptValueOrRedacted(true, receiver.UID), + ) if err != nil { return apimodels.EmbeddedContactPoint{}, err } - embeddedContactPoint := apimodels.EmbeddedContactPoint{ - UID: receiver.UID, - Type: receiver.Type, - Name: receiver.Name, - DisableResolveMessage: receiver.DisableResolveMessage, - Settings: simpleJson, - } - for k, v := range receiver.SecureSettings { - decryptedValue, err := ecp.decryptValue(v) - if err != nil { - ecp.log.Warn("Decrypting value failed", "error", err.Error()) - continue - } - if decryptedValue == "" { - continue - } - embeddedContactPoint.Settings.Set(k, decryptedValue) - } return embeddedContactPoint, nil } return apimodels.EmbeddedContactPoint{}, fmt.Errorf("%w: contact point with uid '%s' not found", ErrNotFound, uid) @@ -428,18 +392,27 @@ func isContactPointInUse(name string, routes []*apimodels.Route) bool { return false } -func (ecp *ContactPointService) decryptValue(value string) (string, error) { - decodeValue, err := base64.StdEncoding.DecodeString(value) - if err != nil { - return "", err +// decryptValueOrRedacted returns a function that decodes a string from Base64 and then decrypts using secrets.Service. +// If argument 'decrypt' is false, then returns definitions.RedactedValue regardless of the decrypted value. +// Otherwise, it returns the decoded and decrypted value. The function returns empty string in the case of errors, which are logged +func (ecp *ContactPointService) decryptValueOrRedacted(decrypt bool, integrationUID string) func(v string) string { + return func(value string) string { + decodeValue, err := base64.StdEncoding.DecodeString(value) + if err != nil { + ecp.log.Warn("Failed to decode secret value from Base64", "error", err.Error(), "integrationUid", integrationUID) + return "" + } + decryptedValue, err := ecp.encryptionService.Decrypt(context.Background(), decodeValue) + if err != nil { + ecp.log.Warn("Failed to decrypt secret value", "error", err.Error(), "integrationUid", integrationUID) + return "" + } + if decrypt { + return string(decryptedValue) + } else { + return apimodels.RedactedValue + } } - - decryptedValue, err := ecp.encryptionService.Decrypt(context.Background(), decodeValue) - if err != nil { - return "", err - } - - return string(decryptedValue), nil } func (ecp *ContactPointService) encryptValue(value string) (string, error) {