From 4c15266a77117a5dabc549f4754cec7de9273bc3 Mon Sep 17 00:00:00 2001 From: Santiago Date: Thu, 17 Oct 2024 22:38:13 +0200 Subject: [PATCH] Alerting: Add X-Remote-Alertmanager header to the remote AM client (#94913) --- .../ngalert/remote/alertmanager_test.go | 17 ++++++++++++++--- .../remote/client/mimir_auth_round_tripper.go | 8 ++++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/pkg/services/ngalert/remote/alertmanager_test.go b/pkg/services/ngalert/remote/alertmanager_test.go index 5e95752ea0e..b8cb77ef422 100644 --- a/pkg/services/ngalert/remote/alertmanager_test.go +++ b/pkg/services/ngalert/remote/alertmanager_test.go @@ -125,8 +125,11 @@ func TestNewAlertmanager(t *testing.T) { } func TestApplyConfig(t *testing.T) { + const tenantID = "test" // errorHandler returns an error response for the readiness check and state sync. errorHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, tenantID, r.Header.Get(client.MimirTenantHeader)) + require.Equal(t, "true", r.Header.Get(client.RemoteAlertmanagerHeader)) w.Header().Add("content-type", "application/json") w.WriteHeader(http.StatusInternalServerError) require.NoError(t, json.NewEncoder(w).Encode(map[string]string{"status": "error"})) @@ -135,6 +138,8 @@ func TestApplyConfig(t *testing.T) { var configSent client.UserGrafanaConfig var lastConfigSync, lastStateSync time.Time okHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, tenantID, r.Header.Get(client.MimirTenantHeader)) + require.Equal(t, "true", r.Header.Get(client.RemoteAlertmanagerHeader)) if r.Method == http.MethodPost { if strings.Contains(r.URL.Path, "/config") { require.NoError(t, json.NewDecoder(r.Body).Decode(&configSent)) @@ -166,7 +171,7 @@ func TestApplyConfig(t *testing.T) { server := httptest.NewServer(errorHandler) cfg := AlertmanagerConfig{ OrgID: 1, - TenantID: "test", + TenantID: tenantID, URL: server.URL, DefaultConfig: defaultGrafanaConfig, PromoteConfig: true, @@ -228,6 +233,7 @@ func TestApplyConfig(t *testing.T) { } func TestCompareAndSendConfiguration(t *testing.T) { + const tenantID = "test" cfgWithSecret, err := notifier.Load([]byte(testGrafanaConfigWithSecret)) require.NoError(t, err) testValue := []byte("test") @@ -240,6 +246,8 @@ func TestCompareAndSendConfiguration(t *testing.T) { var got string server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, tenantID, r.Header.Get(client.MimirTenantHeader)) + require.Equal(t, "true", r.Header.Get(client.RemoteAlertmanagerHeader)) w.Header().Add("content-type", "application/json") b, err := io.ReadAll(r.Body) @@ -255,7 +263,7 @@ func TestCompareAndSendConfiguration(t *testing.T) { m := metrics.NewRemoteAlertmanagerMetrics(prometheus.NewRegistry()) cfg := AlertmanagerConfig{ OrgID: 1, - TenantID: "test", + TenantID: tenantID, URL: server.URL, DefaultConfig: defaultGrafanaConfig, } @@ -336,6 +344,7 @@ func TestCompareAndSendConfiguration(t *testing.T) { } func Test_TestReceiversDecryptsSecureSettings(t *testing.T) { + const tenantID = "test" const testKey = "test-key" const testValue = "test-value" decryptFn := func(_ context.Context, payload []byte) ([]byte, error) { @@ -347,6 +356,8 @@ func Test_TestReceiversDecryptsSecureSettings(t *testing.T) { var got apimodels.TestReceiversConfigBodyParams server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, tenantID, r.Header.Get(client.MimirTenantHeader)) + require.Equal(t, "true", r.Header.Get(client.RemoteAlertmanagerHeader)) w.Header().Add("Content-Type", "application/json") require.NoError(t, json.NewDecoder(r.Body).Decode(&got)) require.NoError(t, r.Body.Close()) @@ -358,7 +369,7 @@ func Test_TestReceiversDecryptsSecureSettings(t *testing.T) { m := metrics.NewRemoteAlertmanagerMetrics(prometheus.NewRegistry()) cfg := AlertmanagerConfig{ OrgID: 1, - TenantID: "test", + TenantID: tenantID, URL: server.URL, DefaultConfig: defaultGrafanaConfig, } diff --git a/pkg/services/ngalert/remote/client/mimir_auth_round_tripper.go b/pkg/services/ngalert/remote/client/mimir_auth_round_tripper.go index 821eabd58ee..3a9ff94f4a6 100644 --- a/pkg/services/ngalert/remote/client/mimir_auth_round_tripper.go +++ b/pkg/services/ngalert/remote/client/mimir_auth_round_tripper.go @@ -4,7 +4,10 @@ import ( "net/http" ) -const mimirTenantHeader = "X-Scope-OrgID" +const ( + MimirTenantHeader = "X-Scope-OrgID" + RemoteAlertmanagerHeader = "X-Remote-Alertmanager" +) type MimirAuthRoundTripper struct { TenantID string @@ -16,8 +19,9 @@ type MimirAuthRoundTripper struct { // It adds an `X-Scope-OrgID` header with the TenantID if only provided with a tenantID or sets HTTP Basic Authentication if both // a tenantID and a password are provided. func (r *MimirAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + req.Header.Set(RemoteAlertmanagerHeader, "true") if r.TenantID != "" && r.Password == "" { - req.Header.Set(mimirTenantHeader, r.TenantID) + req.Header.Set(MimirTenantHeader, r.TenantID) } if r.TenantID != "" && r.Password != "" {