Shared Azure middleware between Azure Monitor and Prometheus datasources (#46002)

* Scopes in Azure middleware

* Enable Azure middleware without feature flag

* Use common Azure middleware in Azure Monitor

* Apply feature flag to JsonData configuration of Azure auth

* Enforce feature flag in Prometheus datasource

* Prometheus provider tests

* Datasource service tests

* Fix http client provider tests

* Pass sdkhttpclient.Options by reference

* Add middleware to httpclient.Options

* Remove dependency on Grafana settings

* Unit-tests updated

* Fix ds_proxy_test

* Fix service_test
This commit is contained in:
Sergey Kostrukov
2022-04-01 13:26:49 +02:00
committed by GitHub
parent 16db1ad46d
commit 656ade9884
39 changed files with 728 additions and 433 deletions
@@ -5,6 +5,8 @@ import (
"crypto/tls"
"fmt"
"net/http"
"net/url"
"path"
"strconv"
"strings"
"sync"
@@ -23,12 +25,14 @@ import (
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/azhttpclient"
)
type Service struct {
Bus bus.Bus
SQLStore *sqlstore.SQLStore
SecretsService secrets.Service
cfg *setting.Cfg
features featuremgmt.FeatureToggles
permissionsService accesscontrol.PermissionsService
@@ -57,7 +61,7 @@ type cachedDecryptedJSON struct {
}
func ProvideService(
bus bus.Bus, store *sqlstore.SQLStore, secretsService secrets.Service, features featuremgmt.FeatureToggles,
bus bus.Bus, store *sqlstore.SQLStore, secretsService secrets.Service, cfg *setting.Cfg, features featuremgmt.FeatureToggles,
ac accesscontrol.AccessControl, permissionsServices accesscontrol.PermissionsServices,
) *Service {
s := &Service{
@@ -70,6 +74,7 @@ func ProvideService(
dsDecryptionCache: secureJSONDecryptionCache{
cache: make(map[int64]cachedDecryptedJSON),
},
cfg: cfg,
features: features,
permissionsService: permissionsServices.GetDataSourceService(),
}
@@ -233,7 +238,7 @@ func (s *Service) GetHTTPTransport(ds *models.DataSource, provider httpclient.Pr
return nil, err
}
opts.Middlewares = customMiddlewares
opts.Middlewares = append(opts.Middlewares, customMiddlewares...)
rt, err := provider.GetTransport(*opts)
if err != nil {
@@ -337,7 +342,8 @@ func (s *Service) httpClientOptions(ds *models.DataSource) (*sdkhttpclient.Optio
}
}
if ds.JsonData != nil {
// Azure authentication
if ds.JsonData != nil && s.features.IsEnabled(featuremgmt.FlagHttpclientproviderAzureAuth) {
credentials, err := azcredentials.FromDatasourceData(ds.JsonData.MustMap(), s.DecryptedValues(ds))
if err != nil {
err = fmt.Errorf("invalid Azure credentials: %s", err)
@@ -345,7 +351,22 @@ func (s *Service) httpClientOptions(ds *models.DataSource) (*sdkhttpclient.Optio
}
if credentials != nil {
opts.CustomOptions["_azureCredentials"] = credentials
resourceIdStr := ds.JsonData.Get("azureEndpointResourceId").MustString()
if resourceIdStr == "" {
err := fmt.Errorf("endpoint resource ID (audience) not provided")
return nil, err
}
resourceId, err := url.Parse(resourceIdStr)
if err != nil || resourceId.Scheme == "" || resourceId.Host == "" {
err := fmt.Errorf("endpoint resource ID (audience) '%s' invalid", resourceIdStr)
return nil, err
}
resourceId.Path = path.Join(resourceId.Path, ".default")
scopes := []string{resourceId.String()}
azhttpclient.AddAzureAuthentication(opts, s.cfg.Azure, credentials, scopes)
}
}