diff --git a/conf/defaults.ini b/conf/defaults.ini index 18ece50c9ff..458e09ee92e 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -921,6 +921,10 @@ forward_settings_to_plugins = cloudwatch, grafana-athena-datasource, grafana-red # Default value is AzureCloud (i.e. public cloud) cloud = AzureCloud +# A customized list of Azure cloud settings and properties, used by data sources which need this information when run in non-standard azure environments +# When specified, this list will replace the default cloud list of AzureCloud, AzureChinaCloud, AzureUSGovernment and AzureGermanCloud +clouds_config = + # Specifies whether Grafana hosted in Azure service with Managed Identity configured (e.g. Azure Virtual Machines instance) # If enabled, the managed identity can be used for authentication of Grafana in Azure services # Disabled by default, needs to be explicitly enabled diff --git a/conf/sample.ini b/conf/sample.ini index f454728032a..0a2d21ecf44 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -839,6 +839,22 @@ # Default value is AzureCloud (i.e. public cloud) ;cloud = AzureCloud +# A customized list of Azure cloud settings and properties, used by data sources which need this information when run in non-standard azure environments +# When specified, this list will replace the default cloud list of AzureCloud, AzureChinaCloud, AzureUSGovernment and AzureGermanCloud +;clouds_config = `[ +; { +; "name":"CustomCloud1", +; "displayName":"Custom Cloud 1", +; "aadAuthority":"https://login.cloud1.contoso.com/", +; "properties":{ +; "azureDataExplorerSuffix": ".kusto.windows.cloud1.contoso.com", +; "logAnalytics": "https://api.loganalytics.cloud1.contoso.com", +; "portal": "https://portal.azure.cloud1.contoso.com", +; "prometheusResourceId": "https://prometheus.monitor.azure.cloud1.contoso.com", +; "resourceManager": "https://management.azure.cloud1.contoso.com" +; } +; }]` + # Specifies whether Grafana hosted in Azure service with Managed Identity configured (e.g. Azure Virtual Machines instance) # If enabled, the managed identity can be used for authentication of Grafana in Azure services # Disabled by default, needs to be explicitly enabled diff --git a/docs/sources/setup-grafana/configure-grafana/_index.md b/docs/sources/setup-grafana/configure-grafana/_index.md index 0cbd5fa157a..a3aa4700dd5 100644 --- a/docs/sources/setup-grafana/configure-grafana/_index.md +++ b/docs/sources/setup-grafana/configure-grafana/_index.md @@ -1175,6 +1175,28 @@ Azure cloud environment where Grafana is hosted: | US Government cloud | AzureUSGovernment | | Microsoft German national cloud ("Black Forest") | AzureGermanCloud | +### clouds_config + +The JSON config defines a list of Azure clouds and their associated properties when hosted in custom Azure environments. + +For example: + +```ini +clouds_config = `[ + { + "name":"CustomCloud1", + "displayName":"Custom Cloud 1", + "aadAuthority":"https://login.cloud1.contoso.com/", + "properties":{ + "azureDataExplorerSuffix": ".kusto.windows.cloud1.contoso.com", + "logAnalytics": "https://api.loganalytics.cloud1.contoso.com", + "portal": "https://portal.azure.cloud1.contoso.com", + "prometheusResourceId": "https://prometheus.monitor.azure.cloud1.contoso.com", + "resourceManager": "https://management.azure.cloud1.contoso.com" + } + }]` +``` + ### managed_identity_enabled Specifies whether Grafana hosted in Azure service with Managed Identity configured (e.g. Azure Virtual Machines instance). Disabled by default, needs to be explicitly enabled. diff --git a/go.mod b/go.mod index 7bf7e674e98..88b8cab6cf1 100644 --- a/go.mod +++ b/go.mod @@ -96,7 +96,7 @@ require ( github.com/grafana/gofpdf v0.0.0-20231002120153-857cc45be447 // @grafana/sharing-squad github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586 // @grafana/grafana-operator-experience-squad github.com/grafana/grafana-aws-sdk v0.25.1 // @grafana/aws-datasources - github.com/grafana/grafana-azure-sdk-go/v2 v2.0.3 // @grafana/partner-datasources + github.com/grafana/grafana-azure-sdk-go/v2 v2.0.4 // @grafana/partner-datasources github.com/grafana/grafana-google-sdk-go v0.1.0 // @grafana/partner-datasources github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 // @grafana/grafana-backend-group github.com/grafana/grafana-plugin-sdk-go v0.232.0 // @grafana/plugins-platform-backend diff --git a/go.sum b/go.sum index 68439dd071d..4a20acfed7f 100644 --- a/go.sum +++ b/go.sum @@ -2172,8 +2172,8 @@ github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586 h1:/of8Z8taCPft github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586/go.mod h1:PGk3RjYHpxMM8HFPhKKo+vve3DdlPUELZLSDEFehPuU= github.com/grafana/grafana-aws-sdk v0.25.1 h1:waJERJueqB1GldclAh5+tBcY9Ju9AOO9xYSJEnOAuf4= github.com/grafana/grafana-aws-sdk v0.25.1/go.mod h1:3zghFF6edrxn0d6k6X9HpGZXDH+VfA+MwD2Pc/9X0ec= -github.com/grafana/grafana-azure-sdk-go/v2 v2.0.3 h1:5qW9WVDpAxJx7db3Ir2BsHDetLhAFCwrAFlZjzCqTDE= -github.com/grafana/grafana-azure-sdk-go/v2 v2.0.3/go.mod h1:s8GLONgVh/svnSsO0Eo+OgXc/RZqozI5/0n+pNm3MEE= +github.com/grafana/grafana-azure-sdk-go/v2 v2.0.4 h1:z6amQ286IJSBctHf6c+ibJq/v0+TvmEjVkrdMNBd4uY= +github.com/grafana/grafana-azure-sdk-go/v2 v2.0.4/go.mod h1:aKlFPE36IDa8qccRg3KbgZX3MQ5xymS3RelT4j6kkVU= github.com/grafana/grafana-google-sdk-go v0.1.0 h1:LKGY8z2DSxKjYfr2flZsWgTRTZ6HGQbTqewE3JvRaNA= github.com/grafana/grafana-google-sdk-go v0.1.0/go.mod h1:Vo2TKWfDVmNTELBUM+3lkrZvFtBws0qSZdXhQxRdJrE= github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 h1:r+mU5bGMzcXCRVAuOrTn54S80qbfVkvTdUJZfSfTNbs= diff --git a/go.work.sum b/go.work.sum index 0f896655d0a..5bed99e647c 100644 --- a/go.work.sum +++ b/go.work.sum @@ -659,6 +659,7 @@ github.com/grafana/grafana-plugin-sdk-go v0.227.1-0.20240426134450-5fe9f7b9dfd4/ github.com/grafana/grafana-plugin-sdk-go v0.227.1-0.20240430073540-ce4d126ae8b8 h1:pyWJN79uW8QHZiQRasHGLCEkXSr3k6HCjdr0J2jZ3rU= github.com/grafana/grafana-plugin-sdk-go v0.227.1-0.20240430073540-ce4d126ae8b8/go.mod h1:u4K9vVN6eU86loO68977eTXGypC4brUCnk4sfDzutZU= github.com/grafana/grafana-plugin-sdk-go v0.228.0/go.mod h1:u4K9vVN6eU86loO68977eTXGypC4brUCnk4sfDzutZU= +github.com/grafana/grafana-plugin-sdk-go v0.230.0 h1:Y4IL+eT1jXqTCctlNzdCvxAozpBZ8xEsRGWjGAVRXxo= github.com/grafana/grafana-plugin-sdk-go v0.229.0/go.mod h1:6V6ikT4ryva8MrAp7Bdz5fTJx3/ztzKvpMJFfpzr4CI= github.com/grafana/grafana-plugin-sdk-go v0.230.0/go.mod h1:6V6ikT4ryva8MrAp7Bdz5fTJx3/ztzKvpMJFfpzr4CI= github.com/grafana/grafana-plugin-sdk-go v0.231.1-0.20240523124942-62dae9836284/go.mod h1:bNgmNmub1I7Mc8dzIncgNqHC5jTgSZPPHlZ3aG8HKJQ= diff --git a/pkg/services/pluginsintegration/pluginconfig/request.go b/pkg/services/pluginsintegration/pluginconfig/request.go index af2de223bda..c42e32c663d 100644 --- a/pkg/services/pluginsintegration/pluginconfig/request.go +++ b/pkg/services/pluginsintegration/pluginconfig/request.go @@ -95,6 +95,10 @@ func (s *RequestConfigProvider) PluginRequestConfig(ctx context.Context, pluginI m[azsettings.AzureCloud] = azureSettings.Cloud } + if len(azureSettings.CustomCloudListJSON) > 0 { + m[azsettings.AzureCustomCloudsConfig] = azureSettings.CustomCloudListJSON + } + if azureSettings.ManagedIdentityEnabled { m[azsettings.ManagedIdentityEnabled] = "true" diff --git a/pkg/services/pluginsintegration/pluginconfig/request_test.go b/pkg/services/pluginsintegration/pluginconfig/request_test.go index cec19e4a252..a6d57386457 100644 --- a/pkg/services/pluginsintegration/pluginconfig/request_test.go +++ b/pkg/services/pluginsintegration/pluginconfig/request_test.go @@ -335,6 +335,38 @@ func TestRequestConfigProvider_PluginRequestConfig_azure(t *testing.T) { }) }) + t.Run("azure settings include custom clouds when set", func(t *testing.T) { + cfg := setting.NewCfg() + cfg.Azure = azSettings + + customCloudJson := `[{"name":"CustomCloud1","displayName":"Custom Cloud 1","aadAuthority":"https://login.contoso.com/","properties":null}]` + err := azSettings.SetCustomClouds(customCloudJson) + require.NoError(t, err) + + // Sanity check to make sure SetCustomClouds call above also desirializes the JSON + require.Equal(t, len(azSettings.CustomCloudList), 1) + + pCfg, err := ProvidePluginInstanceConfig(cfg, setting.ProvideProvider(cfg), featuremgmt.WithFeatures()) + require.NoError(t, err) + + p := NewRequestConfigProvider(pCfg) + require.Subset(t, p.PluginRequestConfig(context.Background(), "grafana-azure-monitor-datasource", nil), map[string]string{ + "GFAZPL_AZURE_CLOUD": "AzureCloud", "GFAZPL_MANAGED_IDENTITY_ENABLED": "true", + "GFAZPL_MANAGED_IDENTITY_CLIENT_ID": "mock_managed_identity_client_id", + "GFAZPL_AZURE_CLOUDS_CONFIG": customCloudJson, + "GFAZPL_WORKLOAD_IDENTITY_ENABLED": "true", + "GFAZPL_WORKLOAD_IDENTITY_TENANT_ID": "mock_workload_identity_tenant_id", + "GFAZPL_WORKLOAD_IDENTITY_CLIENT_ID": "mock_workload_identity_client_id", + "GFAZPL_WORKLOAD_IDENTITY_TOKEN_FILE": "mock_workload_identity_token_file", + "GFAZPL_USER_IDENTITY_ENABLED": "true", + "GFAZPL_USER_IDENTITY_FALLBACK_SERVICE_CREDENTIALS_ENABLED": "true", + "GFAZPL_USER_IDENTITY_TOKEN_URL": "mock_user_identity_token_url", + "GFAZPL_USER_IDENTITY_CLIENT_ID": "mock_user_identity_client_id", + "GFAZPL_USER_IDENTITY_CLIENT_SECRET": "mock_user_identity_client_secret", + "GFAZPL_USER_IDENTITY_ASSERTION": "username", + }) + }) + t.Run("does not use the azure settings for a non-Azure plugin", func(t *testing.T) { cfg := setting.NewCfg() cfg.Azure = azSettings diff --git a/pkg/setting/setting_azure.go b/pkg/setting/setting_azure.go index e27a238cfbc..13ab1a575c6 100644 --- a/pkg/setting/setting_azure.go +++ b/pkg/setting/setting_azure.go @@ -72,6 +72,12 @@ func (cfg *Cfg) readAzureSettings() { azureSettings.UserIdentityFallbackCredentialsEnabled = azureSection.Key("user_identity_fallback_credentials_enabled").MustBool(true) } + if customCloudsJSON := azureSection.Key("clouds_config").MustString(""); customCloudsJSON != "" { + if err := azureSettings.SetCustomClouds(customCloudsJSON); err != nil { + cfg.Logger.Error("Failed to parse custom Azure cloud settings", "err", err.Error()) + } + } + azureSettings.ForwardSettingsPlugins = util.SplitString(azureSection.Key("forward_settings_to_plugins").String()) cfg.Azure = azureSettings