From 80611b381c1e4a2ab8036ecbb62a70940e6617f3 Mon Sep 17 00:00:00 2001 From: Santiago Date: Mon, 30 Sep 2024 13:28:30 -0300 Subject: [PATCH] Alerting: Decrypt secure settings when testing receivers in the remote Alertmanager (#93864) * Alerting: Decrypt secure settings when testing receivers in the remote Alertmanager * go work sync * make update-workspace * point to latest main in grafana/alerting * unit test * import definitions only once --- go.mod | 2 +- go.sum | 4 +- go.work.sum | 2 + .../api/tooling/definitions/alertmanager.go | 17 ++---- pkg/services/ngalert/remote/alertmanager.go | 11 +++- .../ngalert/remote/alertmanager_test.go | 59 +++++++++++++++++++ 6 files changed, 78 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index 4496998f90f..1d8d0652273 100644 --- a/go.mod +++ b/go.mod @@ -73,7 +73,7 @@ require ( github.com/googleapis/gax-go/v2 v2.13.0 // @grafana/grafana-backend-group github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group github.com/gorilla/websocket v1.5.0 // @grafana/grafana-app-platform-squad - github.com/grafana/alerting v0.0.0-20240926144415-27f4e81b4b6b // @grafana/alerting-backend + github.com/grafana/alerting v0.0.0-20240927162124-918609743768 // @grafana/alerting-backend github.com/grafana/authlib v0.0.0-20240919120951-58259833c564 // @grafana/identity-access-team github.com/grafana/authlib/claims v0.0.0-20240827210201-19d5347dd8dd // @grafana/identity-access-team github.com/grafana/codejen v0.0.3 // @grafana/dataviz-squad diff --git a/go.sum b/go.sum index 92daabd7e00..4bbb15008f0 100644 --- a/go.sum +++ b/go.sum @@ -2256,8 +2256,8 @@ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grafana/alerting v0.0.0-20240926144415-27f4e81b4b6b h1:UO4mv94pG1kzKCgBKh20TXdACBCAK2vYjV3Q2MlcpEQ= -github.com/grafana/alerting v0.0.0-20240926144415-27f4e81b4b6b/go.mod h1:GMLi6d09Xqo96fCVUjNk//rcjP5NKEdjOzfWIffD5r4= +github.com/grafana/alerting v0.0.0-20240927162124-918609743768 h1:rZoJB3Myo+aKrTIAfn2E4MfgGime/KbH5sxm/67ppSM= +github.com/grafana/alerting v0.0.0-20240927162124-918609743768/go.mod h1:GMLi6d09Xqo96fCVUjNk//rcjP5NKEdjOzfWIffD5r4= github.com/grafana/authlib v0.0.0-20240919120951-58259833c564 h1:zYF/RBulpvMqPYR3gbzJZ8t/j/Eymn5FNidSYkueNCA= github.com/grafana/authlib v0.0.0-20240919120951-58259833c564/go.mod h1:PFzXbCrn0GIpN4KwT6NP1l5Z1CPLfmKHnYx8rZzQcyY= github.com/grafana/authlib/claims v0.0.0-20240827210201-19d5347dd8dd h1:sIlR7n38/MnZvX2qxDEszywXdI5soCwQ78aTDSARvus= diff --git a/go.work.sum b/go.work.sum index e993d1985f4..9fd96d0bd66 100644 --- a/go.work.sum +++ b/go.work.sum @@ -565,6 +565,8 @@ github.com/grafana/alerting v0.0.0-20240830172655-aa466962ea18 h1:3cQ+d+fkNL2Eqp github.com/grafana/alerting v0.0.0-20240830172655-aa466962ea18/go.mod h1:GMLi6d09Xqo96fCVUjNk//rcjP5NKEdjOzfWIffD5r4= github.com/grafana/alerting v0.0.0-20240917171353-6c25eb6eff10 h1:oDbLKM34O+JUF9EQFS+9aYhdYoeNfUpXqNjFCLIxwF4= github.com/grafana/alerting v0.0.0-20240917171353-6c25eb6eff10/go.mod h1:GMLi6d09Xqo96fCVUjNk//rcjP5NKEdjOzfWIffD5r4= +github.com/grafana/alerting v0.0.0-20240926233713-446ddd356f8d h1:HOK6RWTuVldWFtNbWHxPlTa2shZ+WsNJsxoRJhX56Zg= +github.com/grafana/alerting v0.0.0-20240926233713-446ddd356f8d/go.mod h1:GMLi6d09Xqo96fCVUjNk//rcjP5NKEdjOzfWIffD5r4= github.com/grafana/gomemcache v0.0.0-20240229205252-cd6a66d6fb56/go.mod h1:PGk3RjYHpxMM8HFPhKKo+vve3DdlPUELZLSDEFehPuU= github.com/grafana/pyroscope-go/godeltaprof v0.1.6/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE= github.com/grafana/thema v0.0.0-20230511182720-3146087fcc26 h1:HX927q4X1n451pnGb8U0wq74i8PCzuxVjzv7TyD10kc= diff --git a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go index 044d74c3ba4..304a4edcae9 100644 --- a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go +++ b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go @@ -2,7 +2,6 @@ package definitions import ( "context" - "encoding/base64" "encoding/json" "fmt" "time" @@ -680,19 +679,11 @@ func (c *PostableUserConfig) Decrypt(decryptFn func(payload []byte) ([]byte, err // Iterate through receivers and decrypt secure settings. for _, rcv := range newCfg.AlertmanagerConfig.Receivers { for _, gmr := range rcv.PostableGrafanaReceivers.GrafanaManagedReceivers { - for k, v := range gmr.SecureSettings { - decoded, err := base64.StdEncoding.DecodeString(v) - if err != nil { - return PostableUserConfig{}, fmt.Errorf("failed to decode value for key '%s': %w", k, err) - } - - decrypted, err := decryptFn(decoded) - if err != nil { - return PostableUserConfig{}, fmt.Errorf("failed to decrypt value for key '%s': %w", k, err) - } - - gmr.SecureSettings[k] = string(decrypted) + decrypted, err := gmr.DecryptSecureSettings(decryptFn) + if err != nil { + return PostableUserConfig{}, err } + gmr.SecureSettings = decrypted } } return *newCfg, nil diff --git a/pkg/services/ngalert/remote/alertmanager.go b/pkg/services/ngalert/remote/alertmanager.go index 48350b02ff1..36c6e631b67 100644 --- a/pkg/services/ngalert/remote/alertmanager.go +++ b/pkg/services/ngalert/remote/alertmanager.go @@ -527,17 +527,26 @@ func (am *Alertmanager) GetReceivers(ctx context.Context) ([]apimodels.Receiver, } func (am *Alertmanager) TestReceivers(ctx context.Context, c apimodels.TestReceiversConfigBodyParams) (*alertingNotify.TestReceiversResult, int, error) { + fn := func(payload []byte) ([]byte, error) { + return am.decrypt(ctx, payload) + } + receivers := make([]*alertingNotify.APIReceiver, 0, len(c.Receivers)) for _, r := range c.Receivers { integrations := make([]*alertingNotify.GrafanaIntegrationConfig, 0, len(r.GrafanaManagedReceivers)) for _, gr := range r.PostableGrafanaReceivers.GrafanaManagedReceivers { + decrypted, err := gr.DecryptSecureSettings(fn) + if err != nil { + return nil, 0, err + } + integrations = append(integrations, &alertingNotify.GrafanaIntegrationConfig{ UID: gr.UID, Name: gr.Name, Type: gr.Type, DisableResolveMessage: gr.DisableResolveMessage, Settings: json.RawMessage(gr.Settings), - SecureSettings: gr.SecureSettings, + SecureSettings: decrypted, }) } receivers = append(receivers, &alertingNotify.APIReceiver{ diff --git a/pkg/services/ngalert/remote/alertmanager_test.go b/pkg/services/ngalert/remote/alertmanager_test.go index 5d6b9644e34..5e95752ea0e 100644 --- a/pkg/services/ngalert/remote/alertmanager_test.go +++ b/pkg/services/ngalert/remote/alertmanager_test.go @@ -335,6 +335,65 @@ func TestCompareAndSendConfiguration(t *testing.T) { } } +func Test_TestReceiversDecryptsSecureSettings(t *testing.T) { + const testKey = "test-key" + const testValue = "test-value" + decryptFn := func(_ context.Context, payload []byte) ([]byte, error) { + if string(payload) == testValue { + return []byte(testValue), nil + } + return nil, errTest + } + + var got apimodels.TestReceiversConfigBodyParams + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "application/json") + require.NoError(t, json.NewDecoder(r.Body).Decode(&got)) + require.NoError(t, r.Body.Close()) + _, err := w.Write([]byte(`{"status": "success"}`)) + require.NoError(t, err) + })) + + fstore := notifier.NewFileStore(1, ngfakes.NewFakeKVStore(t)) + m := metrics.NewRemoteAlertmanagerMetrics(prometheus.NewRegistry()) + cfg := AlertmanagerConfig{ + OrgID: 1, + TenantID: "test", + URL: server.URL, + DefaultConfig: defaultGrafanaConfig, + } + + am, err := NewAlertmanager(cfg, + fstore, + decryptFn, + NoopAutogenFn, + m, + tracing.InitializeTracerForTest(), + ) + + require.NoError(t, err) + params := apimodels.TestReceiversConfigBodyParams{ + Alert: &apimodels.TestReceiversConfigAlertParams{}, + Receivers: []*definition.PostableApiReceiver{ + { + PostableGrafanaReceivers: apimodels.PostableGrafanaReceivers{ + GrafanaManagedReceivers: []*apimodels.PostableGrafanaReceiver{ + { + SecureSettings: map[string]string{ + testKey: base64.StdEncoding.EncodeToString([]byte(testValue)), + }, + }, + }, + }, + }, + }, + } + + _, _, err = am.TestReceivers(context.Background(), params) + require.NoError(t, err) + require.Equal(t, map[string]string{testKey: testValue}, got.Receivers[0].PostableGrafanaReceivers.GrafanaManagedReceivers[0].SecureSettings) +} + func Test_isDefaultConfiguration(t *testing.T) { parsedDefaultConfig, _ := notifier.Load([]byte(defaultGrafanaConfig)) parsedTestConfig, _ := notifier.Load([]byte(testGrafanaConfig))