diff --git a/plugins/inputs/azure_monitor/README.md b/plugins/inputs/azure_monitor/README.md index f9581c9751ab0..2e152eada88f6 100644 --- a/plugins/inputs/azure_monitor/README.md +++ b/plugins/inputs/azure_monitor/README.md @@ -58,6 +58,14 @@ plugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details. [CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins +## Secret-store support + +This plugin supports secrets from secret-stores for the `client_secret` option. +See the [secret-store documentation][SECRETSTORE] for more details on how +to use them. + +[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets + ## Configuration ```toml @sample.conf @@ -74,6 +82,7 @@ plugin ordering. See [CONFIGURATION.md][CONFIGURATION.md] for more details. # - Managed Identity # - Azure CLI auth # - Developer Azure CLI auth + # Supports referencing values from secret stores using @{:} syntax client_secret = "<>" # can be found under Azure Active Directory->Properties tenant_id = "<>" diff --git a/plugins/inputs/azure_monitor/azure_monitor.go b/plugins/inputs/azure_monitor/azure_monitor.go index 900df9b3d23f5..07ab463032044 100644 --- a/plugins/inputs/azure_monitor/azure_monitor.go +++ b/plugins/inputs/azure_monitor/azure_monitor.go @@ -3,6 +3,7 @@ package azure_monitor import ( _ "embed" + "errors" "fmt" "sync" @@ -12,13 +13,14 @@ import ( receiver "github.com/logzio/azure-monitor-metrics-receiver" "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/config" "github.com/influxdata/telegraf/plugins/inputs" ) type AzureMonitor struct { SubscriptionID string `toml:"subscription_id"` ClientID string `toml:"client_id"` - ClientSecret string `toml:"client_secret"` + ClientSecret config.Secret `toml:"client_secret"` TenantID string `toml:"tenant_id"` CloudOption string `toml:"cloud_option,omitempty"` ResourceTargets []*resourceTarget `toml:"resource_target"` @@ -63,6 +65,10 @@ func (*AzureMonitor) SampleConfig() string { } func (am *AzureMonitor) Init() error { + if am.SubscriptionID == "" { + return errors.New("subscription_id is required") + } + var clientOptions azcore.ClientOptions switch am.CloudOption { case "AzureChina": @@ -75,8 +81,24 @@ func (am *AzureMonitor) Init() error { return fmt.Errorf("unknown cloud option: %s", am.CloudOption) } + var clientSecret string + if !am.ClientSecret.Empty() { + if am.ClientID == "" { + return errors.New("client_id is required when client_secret is set") + } + if am.TenantID == "" { + return errors.New("tenant_id is required when client_secret is set") + } + secret, err := am.ClientSecret.Get() + if err != nil { + return fmt.Errorf("getting client secret failed: %w", err) + } + clientSecret = secret.String() + secret.Destroy() + } + var err error - am.azureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions) + am.azureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, clientSecret, am.TenantID, clientOptions) if err != nil { return err } diff --git a/plugins/inputs/azure_monitor/azure_monitor_test.go b/plugins/inputs/azure_monitor/azure_monitor_test.go index f8b5648988c4e..02ec31792f320 100644 --- a/plugins/inputs/azure_monitor/azure_monitor_test.go +++ b/plugins/inputs/azure_monitor/azure_monitor_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/Azure/azure-sdk-for-go/sdk/azcore" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources" "github.com/influxdata/toml" @@ -116,23 +115,23 @@ func (*mockAzureMetricDefinitionsClient) List( return armmonitor.MetricDefinitionsClientListResponse{}, err } - if resourceID == "/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1" { + switch resourceID { + case "/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1": return armmonitor.MetricDefinitionsClientListResponse{ MetricDefinitionCollection: armmonitor.MetricDefinitionCollection{ Value: metricDefinitions[0], }, }, nil - } - - if resourceID == "/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2" { + case "/subscriptions/subscriptionID/resourceGroups/resourceGroup1/providers/Microsoft.Test/type2/resource2", + "/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type2/resource4", + "/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type2/resource5", + "/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type2/resource6": return armmonitor.MetricDefinitionsClientListResponse{ MetricDefinitionCollection: armmonitor.MetricDefinitionCollection{ Value: metricDefinitions[1], }, }, nil - } - - if resourceID == "/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3" { + case "/subscriptions/subscriptionID/resourceGroups/resourceGroup2/providers/Microsoft.Test/type1/resource3": return armmonitor.MetricDefinitionsClientListResponse{ MetricDefinitionCollection: armmonitor.MetricDefinitionCollection{ Value: metricDefinitions[2], @@ -611,6 +610,36 @@ func TestInit_NoSubscriptionID(t *testing.T) { require.Error(t, am.Init()) } +func TestInit_NoClientID(t *testing.T) { + file, err := os.ReadFile("testdata/toml/init_no_client_id.toml") + require.NoError(t, err) + require.NotNil(t, file) + require.NotEmpty(t, file) + + var am *AzureMonitor + require.NoError(t, toml.Unmarshal(file, &am)) + + am.Log = testutil.Logger{} + am.azureManager = &mockAzureClientsManager{} + + require.Error(t, am.Init()) +} + +func TestInit_NoTenantID(t *testing.T) { + file, err := os.ReadFile("testdata/toml/init_no_tenant_id.toml") + require.NoError(t, err) + require.NotNil(t, file) + require.NotEmpty(t, file) + + var am *AzureMonitor + require.NoError(t, toml.Unmarshal(file, &am)) + + am.Log = testutil.Logger{} + am.azureManager = &mockAzureClientsManager{} + + require.Error(t, am.Init()) +} + func TestInit_NoTargets(t *testing.T) { file, err := os.ReadFile("testdata/toml/init_no_targets.toml") require.NoError(t, err) @@ -906,25 +935,8 @@ func TestGather_Success(t *testing.T) { am.Log = testutil.Logger{} am.azureManager = &mockAzureClientsManager{} - resourceTargets := make([]*receiver.ResourceTarget, 0, len(am.ResourceTargets)) - for _, target := range am.ResourceTargets { - resourceTargets = append(resourceTargets, receiver.NewResourceTarget(target.ResourceID, target.Metrics, target.Aggregations)) - } - var clientOptions = azcore.ClientOptions{Cloud: cloud.AzurePublic} - - var azureClients *receiver.AzureClients - azureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions) - require.NoError(t, err) - require.NotNil(t, azureClients) - - am.receiver, err = receiver.NewAzureMonitorMetricsReceiver( - am.SubscriptionID, - receiver.NewTargets(resourceTargets, nil, nil), - azureClients, - ) - require.NoError(t, err) - require.NotNil(t, am.receiver) + require.NoError(t, am.Init()) expectedResource1Metric1Name := "azure_monitor_microsoft_test_type1_metric1" expectedResource1Metric1MetricFields := make(map[string]interface{}) @@ -993,25 +1005,7 @@ func TestGather_China_Success(t *testing.T) { am.Log = testutil.Logger{} am.azureManager = &mockAzureClientsManager{} - resourceTargets := make([]*receiver.ResourceTarget, 0, len(am.ResourceTargets)) - for _, target := range am.ResourceTargets { - resourceTargets = append(resourceTargets, receiver.NewResourceTarget(target.ResourceID, target.Metrics, target.Aggregations)) - } - - var clientOptions = azcore.ClientOptions{Cloud: cloud.AzureChina} - - var azureClients *receiver.AzureClients - azureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions) - require.NoError(t, err) - require.NotNil(t, azureClients) - - am.receiver, err = receiver.NewAzureMonitorMetricsReceiver( - am.SubscriptionID, - receiver.NewTargets(resourceTargets, nil, nil), - azureClients, - ) - require.NoError(t, err) - require.NotNil(t, am.receiver) + require.NoError(t, am.Init()) } func TestGather_Government_Success(t *testing.T) { @@ -1026,25 +1020,7 @@ func TestGather_Government_Success(t *testing.T) { am.Log = testutil.Logger{} am.azureManager = &mockAzureClientsManager{} - resourceTargets := make([]*receiver.ResourceTarget, 0, len(am.ResourceTargets)) - for _, target := range am.ResourceTargets { - resourceTargets = append(resourceTargets, receiver.NewResourceTarget(target.ResourceID, target.Metrics, target.Aggregations)) - } - - var clientOptions = azcore.ClientOptions{Cloud: cloud.AzureGovernment} - - var azureClients *receiver.AzureClients - azureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions) - require.NoError(t, err) - require.NotNil(t, azureClients) - - am.receiver, err = receiver.NewAzureMonitorMetricsReceiver( - am.SubscriptionID, - receiver.NewTargets(resourceTargets, nil, nil), - azureClients, - ) - require.NoError(t, err) - require.NotNil(t, am.receiver) + require.NoError(t, am.Init()) } func TestGather_Public_Success(t *testing.T) { @@ -1059,23 +1035,5 @@ func TestGather_Public_Success(t *testing.T) { am.Log = testutil.Logger{} am.azureManager = &mockAzureClientsManager{} - resourceTargets := make([]*receiver.ResourceTarget, 0, len(am.ResourceTargets)) - for _, target := range am.ResourceTargets { - resourceTargets = append(resourceTargets, receiver.NewResourceTarget(target.ResourceID, target.Metrics, target.Aggregations)) - } - - var clientOptions = azcore.ClientOptions{Cloud: cloud.AzurePublic} - - var azureClients *receiver.AzureClients - azureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions) - require.NoError(t, err) - require.NotNil(t, azureClients) - - am.receiver, err = receiver.NewAzureMonitorMetricsReceiver( - am.SubscriptionID, - receiver.NewTargets(resourceTargets, nil, nil), - azureClients, - ) - require.NoError(t, err) - require.NotNil(t, am.receiver) + require.NoError(t, am.Init()) } diff --git a/plugins/inputs/azure_monitor/sample.conf b/plugins/inputs/azure_monitor/sample.conf index 9eb28b1edbaca..90e51f60cebf9 100644 --- a/plugins/inputs/azure_monitor/sample.conf +++ b/plugins/inputs/azure_monitor/sample.conf @@ -11,6 +11,7 @@ # - Managed Identity # - Azure CLI auth # - Developer Azure CLI auth + # Supports referencing values from secret stores using @{:} syntax client_secret = "<>" # can be found under Azure Active Directory->Properties tenant_id = "<>"