From cc33f0bd1067f2d08b36c4fa1f80b86311c831bc Mon Sep 17 00:00:00 2001 From: Sergey Kostrukov Date: Thu, 8 Feb 2024 16:47:09 -0600 Subject: [PATCH] Prometheus: Azure scopes from Grafana Azure SDK (#82023) * Prometheus: Azure scopes from Grafana Azure SDK * Refactor and add tests * Cosmetic fix * Cosmetic change 2 --- pkg/tsdb/prometheus/azureauth/azure.go | 35 +++++++++++------- pkg/tsdb/prometheus/azureauth/azure_test.go | 41 +++++++++++++++++---- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/pkg/tsdb/prometheus/azureauth/azure.go b/pkg/tsdb/prometheus/azureauth/azure.go index 5b0f9a98a64..93b8e5263e8 100644 --- a/pkg/tsdb/prometheus/azureauth/azure.go +++ b/pkg/tsdb/prometheus/azureauth/azure.go @@ -15,14 +15,6 @@ import ( "github.com/grafana/grafana/pkg/tsdb/prometheus/utils" ) -var ( - azurePrometheusScopes = map[string][]string{ - azsettings.AzurePublic: {"https://prometheus.monitor.azure.com/.default"}, - azsettings.AzureChina: {"https://prometheus.monitor.azure.cn/.default"}, - azsettings.AzureUSGovernment: {"https://prometheus.monitor.azure.us/.default"}, - } -) - func ConfigureAzureAuthentication(settings backend.DataSourceInstanceSettings, azureSettings *azsettings.AzureSettings, clientOpts *sdkhttpclient.Options) error { jsonData, err := utils.GetJsonData(settings) if err != nil { @@ -82,11 +74,28 @@ func getPrometheusScopes(settings *azsettings.AzureSettings, credentials azcrede return nil, err } - // Get scopes for the given cloud - if scopes, ok := azurePrometheusScopes[azureCloud]; !ok { - err := fmt.Errorf("the Azure cloud '%s' not supported by Prometheus datasource", azureCloud) + cloudSettings, err := settings.GetCloud(azureCloud) + if err != nil { return nil, err - } else { - return scopes, nil } + + // Get scopes for the given cloud + resourceIdS, ok := cloudSettings.Properties["prometheusResourceId"] + if !ok { + err := fmt.Errorf("the Azure cloud '%s' doesn't have configuration for Prometheus", azureCloud) + return nil, err + } + return audienceToScopes(resourceIdS) +} + +func audienceToScopes(audience string) ([]string, error) { + resourceId, err := url.Parse(audience) + if err != nil || resourceId.Scheme == "" || resourceId.Host == "" { + err = fmt.Errorf("endpoint resource ID (audience) '%s' invalid", audience) + return nil, err + } + + resourceId.Path = path.Join(resourceId.Path, ".default") + scopes := []string{resourceId.String()} + return scopes, nil } diff --git a/pkg/tsdb/prometheus/azureauth/azure_test.go b/pkg/tsdb/prometheus/azureauth/azure_test.go index bda541f8acb..3b046eb0f66 100644 --- a/pkg/tsdb/prometheus/azureauth/azure_test.go +++ b/pkg/tsdb/prometheus/azureauth/azure_test.go @@ -3,6 +3,7 @@ package azureauth import ( "testing" + "github.com/grafana/grafana-azure-sdk-go/azcredentials" "github.com/grafana/grafana-azure-sdk-go/azsettings" "github.com/grafana/grafana-plugin-sdk-go/backend" sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" @@ -11,7 +12,7 @@ import ( ) func TestConfigureAzureAuthentication(t *testing.T) { - cfgAzure := &azsettings.AzureSettings{} + azureSettings := &azsettings.AzureSettings{} t.Run("should set Azure middleware when JsonData contains valid credentials", func(t *testing.T) { settings := backend.DataSourceInstanceSettings{ @@ -25,7 +26,7 @@ func TestConfigureAzureAuthentication(t *testing.T) { var opts = &sdkhttpclient.Options{CustomOptions: map[string]any{}} - err := ConfigureAzureAuthentication(settings, cfgAzure, opts) + err := ConfigureAzureAuthentication(settings, azureSettings, opts) require.NoError(t, err) require.NotNil(t, opts.Middlewares) @@ -39,7 +40,7 @@ func TestConfigureAzureAuthentication(t *testing.T) { var opts = &sdkhttpclient.Options{CustomOptions: map[string]any{}} - err := ConfigureAzureAuthentication(settings, cfgAzure, opts) + err := ConfigureAzureAuthentication(settings, azureSettings, opts) require.NoError(t, err) assert.NotContains(t, opts.CustomOptions, "_azureCredentials") @@ -54,7 +55,7 @@ func TestConfigureAzureAuthentication(t *testing.T) { } var opts = &sdkhttpclient.Options{CustomOptions: map[string]any{}} - err := ConfigureAzureAuthentication(settings, cfgAzure, opts) + err := ConfigureAzureAuthentication(settings, azureSettings, opts) assert.Error(t, err) }) @@ -70,7 +71,7 @@ func TestConfigureAzureAuthentication(t *testing.T) { } var opts = &sdkhttpclient.Options{CustomOptions: map[string]any{}} - err := ConfigureAzureAuthentication(settings, cfgAzure, opts) + err := ConfigureAzureAuthentication(settings, azureSettings, opts) require.NoError(t, err) require.NotNil(t, opts.Middlewares) @@ -86,7 +87,7 @@ func TestConfigureAzureAuthentication(t *testing.T) { } var opts = &sdkhttpclient.Options{CustomOptions: map[string]any{}} - err := ConfigureAzureAuthentication(settings, cfgAzure, opts) + err := ConfigureAzureAuthentication(settings, azureSettings, opts) require.NoError(t, err) if opts.Middlewares != nil { @@ -107,7 +108,33 @@ func TestConfigureAzureAuthentication(t *testing.T) { var opts = &sdkhttpclient.Options{CustomOptions: map[string]any{}} - err := ConfigureAzureAuthentication(settings, cfgAzure, opts) + err := ConfigureAzureAuthentication(settings, azureSettings, opts) assert.Error(t, err) }) } + +func TestGetPrometheusScopes(t *testing.T) { + azureSettings := &azsettings.AzureSettings{ + Cloud: azsettings.AzureUSGovernment, + } + + t.Run("should return scopes for cloud from settings with MSI credentials", func(t *testing.T) { + credentials := &azcredentials.AzureManagedIdentityCredentials{} + scopes, err := getPrometheusScopes(azureSettings, credentials) + require.NoError(t, err) + + assert.NotNil(t, scopes) + assert.Len(t, scopes, 1) + assert.Equal(t, "https://prometheus.monitor.azure.us/.default", scopes[0]) + }) + + t.Run("should return scopes for cloud from client secret credentials", func(t *testing.T) { + credentials := &azcredentials.AzureClientSecretCredentials{AzureCloud: azsettings.AzureChina} + scopes, err := getPrometheusScopes(azureSettings, credentials) + require.NoError(t, err) + + assert.NotNil(t, scopes) + assert.Len(t, scopes, 1) + assert.Equal(t, "https://prometheus.monitor.azure.cn/.default", scopes[0]) + }) +}