From 5dc1415d6ed78fe7d987e0663ccd8ab7844e2f0f Mon Sep 17 00:00:00 2001 From: Andrei Dorin Oprea Date: Wed, 16 Oct 2024 17:51:48 +0300 Subject: [PATCH] [exporter/azuredataexplorerexporter] add azure default auth --- .chloggen/add_azure_default_auth.yaml | 27 +++++++++++++++++++ exporter/azuredataexplorerexporter/README.md | 13 ++++++--- .../azuredataexplorerexporter/adx_exporter.go | 2 ++ .../adx_exporter_test.go | 12 +++++++++ exporter/azuredataexplorerexporter/config.go | 21 ++++++++++++--- .../azuredataexplorerexporter/config_test.go | 14 +++++++++- .../testdata/config.yaml | 7 ++++- 7 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 .chloggen/add_azure_default_auth.yaml diff --git a/.chloggen/add_azure_default_auth.yaml b/.chloggen/add_azure_default_auth.yaml new file mode 100644 index 000000000000..d9f279fc7991 --- /dev/null +++ b/.chloggen/add_azure_default_auth.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: azuredataexplorerexporter + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add new configuration option `use_default_auth` to enable default authentication for Azure Data Explorer. This option allows users to leverage workload identity for authentication. + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [33667] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [user] diff --git a/exporter/azuredataexplorerexporter/README.md b/exporter/azuredataexplorerexporter/README.md index b0024e90d34a..0f2afaa745ed 100644 --- a/exporter/azuredataexplorerexporter/README.md +++ b/exporter/azuredataexplorerexporter/README.md @@ -22,9 +22,16 @@ This exporter sends metrics, logs and trace data to The following settings are required: - `cluster_uri` (no default): The cluster name of the provisioned ADX cluster to ingest the data. -- `application_id` (no default): The client id to connect to the cluster and ingest data. -- `application_key` (no default): The cluster secret corresponding to the client id. -- `tenant_id` (no default): The tenant id where the application_id is referenced from. + +One authentication method is required: +- Service principal: + - `application_id` (no default): The client id to connect to the cluster and ingest data. + - `application_key` (no default): The cluster secret corresponding to the client id. + - `tenant_id` (no default): The tenant id where the application_id is referenced from. +- Managed identity: + - `managed_identity_id` (no default): The managed identity id to authenticate with. Set to "system" for system-assigned managed identity. Set the MI client Id (GUID) for user-assigned managed identity. +- Default authentication: + - `use_default_auth` (no default): Set to true to use the Azure [default authentication](https://learn.microsoft.com/en-us/azure/developer/go/azure-sdk-authentication?tabs=bash#2-authenticate-with-azure). This is an optional setting and is set to false by default. The following settings can be optionally configured and have default values: > Note that the database tables are expected to be created upfront before the exporter is in operation , the definition of these are in the section [Database and Table definition scripts](#database-and-table-definition-scripts) diff --git a/exporter/azuredataexplorerexporter/adx_exporter.go b/exporter/azuredataexplorerexporter/adx_exporter.go index b7e66e13b9fb..77e16e851aa7 100644 --- a/exporter/azuredataexplorerexporter/adx_exporter.go +++ b/exporter/azuredataexplorerexporter/adx_exporter.go @@ -218,6 +218,8 @@ func createKcsb(config *Config, version string) *kusto.ConnectionStringBuilder { isSystemManagedIdentity := strings.EqualFold(strings.TrimSpace(config.ManagedIdentityID), "SYSTEM") // If the user has managed identity done, use it. For System managed identity use the MI as system switch { + case config.UseDefaultAuth: + kcsb = kusto.NewConnectionStringBuilder(config.ClusterURI).WithDefaultAzureCredential() case !isManagedIdentity: kcsb = kusto.NewConnectionStringBuilder(config.ClusterURI).WithAadAppKey(config.ApplicationID, string(config.ApplicationKey), config.TenantID) case isManagedIdentity && isSystemManagedIdentity: diff --git a/exporter/azuredataexplorerexporter/adx_exporter_test.go b/exporter/azuredataexplorerexporter/adx_exporter_test.go index 186a8839e700..6c02cdb4f6f7 100644 --- a/exporter/azuredataexplorerexporter/adx_exporter_test.go +++ b/exporter/azuredataexplorerexporter/adx_exporter_test.go @@ -178,6 +178,7 @@ func TestCreateKcsb(t *testing.T) { name string // name of the test config Config // config for the test isMsi bool // is MSI enabled + isDefaultAuth bool // is default authentication enabled applicationID string // application id managedIdentityID string // managed identity id }{ @@ -216,6 +217,15 @@ func TestCreateKcsb(t *testing.T) { managedIdentityID: "636d798f-b005-41c9-9809-81a5e5a12b2e", applicationID: "", }, + { + name: "workload identity", + config: Config{ + ClusterURI: "https://CLUSTER.kusto.windows.net", + Database: "tests", + UseDefaultAuth: true, + }, + isDefaultAuth: true, + }, } for i := range tests { tt := tests[i] @@ -229,6 +239,8 @@ func TestCreateKcsb(t *testing.T) { wantManagedID := tt.managedIdentityID assert.Equal(t, wantManagedID, gotKcsb.ManagedServiceIdentity) assert.Equal(t, "https://CLUSTER.kusto.windows.net", gotKcsb.DataSource) + wantIsDefault := tt.isDefaultAuth + assert.Equal(t, wantIsDefault, gotKcsb.DefaultAuth) }) } } diff --git a/exporter/azuredataexplorerexporter/config.go b/exporter/azuredataexplorerexporter/config.go index 082add3ac618..50650c34fbbb 100644 --- a/exporter/azuredataexplorerexporter/config.go +++ b/exporter/azuredataexplorerexporter/config.go @@ -24,6 +24,7 @@ type Config struct { ApplicationKey configopaque.String `mapstructure:"application_key"` TenantID string `mapstructure:"tenant_id"` ManagedIdentityID string `mapstructure:"managed_identity_id"` + UseDefaultAuth bool `mapstructure:"use_default_auth"` Database string `mapstructure:"db_name"` MetricTable string `mapstructure:"metrics_table_name"` LogTable string `mapstructure:"logs_table_name"` @@ -46,9 +47,23 @@ func (adxCfg *Config) Validate() error { if isClusterURIEmpty { return errors.New(`clusterURI config is mandatory`) } - // Parameters for AD App Auth or Managed Identity Auth are mandatory - if isAppAuthEmpty && isManagedAuthEmpty { - return errors.New(`either ["application_id" , "application_key" , "tenant_id"] or ["managed_identity_id"] are needed for auth`) + // Parameters for AD App Auth or Managed Identity Auth or Default Auth are mandatory + authMethods := 0 + + if !isAppAuthEmpty { + authMethods++ + } + + if !isManagedAuthEmpty { + authMethods++ + } + + if adxCfg.UseDefaultAuth { + authMethods++ + } + + if authMethods != 1 { + return errors.New(`either ["application_id" , "application_key" , "tenant_id"] or ["managed_identity_id"] or ["use_default_auth"] must be provided for auth`) } if !(adxCfg.IngestionType == managedIngestType || adxCfg.IngestionType == queuedIngestTest || isEmpty(adxCfg.IngestionType)) { diff --git a/exporter/azuredataexplorerexporter/config_test.go b/exporter/azuredataexplorerexporter/config_test.go index 03882a8145f0..df2d211abb94 100644 --- a/exporter/azuredataexplorerexporter/config_test.go +++ b/exporter/azuredataexplorerexporter/config_test.go @@ -45,7 +45,7 @@ func TestLoadConfig(t *testing.T) { }, { id: component.NewIDWithName(metadata.Type, "2"), - errorMessage: `either ["application_id" , "application_key" , "tenant_id"] or ["managed_identity_id"] are needed for auth`, + errorMessage: `either ["application_id" , "application_key" , "tenant_id"] or ["managed_identity_id"] or ["use_default_auth"] must be provided for auth`, }, { id: component.NewIDWithName(metadata.Type, "3"), @@ -111,6 +111,18 @@ func TestLoadConfig(t *testing.T) { }, }, }, + { + id: component.NewIDWithName(metadata.Type, "9"), + expected: &Config{ + ClusterURI: "https://CLUSTER.kusto.windows.net", + Database: "oteldb", + MetricTable: "OTELMetrics", + LogTable: "OTELLogs", + TraceTable: "OTELTraces", + UseDefaultAuth: true, + IngestionType: queuedIngestTest, + }, + }, } for _, tt := range tests { diff --git a/exporter/azuredataexplorerexporter/testdata/config.yaml b/exporter/azuredataexplorerexporter/testdata/config.yaml index 0fdf9fbe0a13..dcd754709e7a 100644 --- a/exporter/azuredataexplorerexporter/testdata/config.yaml +++ b/exporter/azuredataexplorerexporter/testdata/config.yaml @@ -145,4 +145,9 @@ azuredataexplorer/8: enabled: true initial_interval: 10s max_interval: 60s - max_elapsed_time: 10m \ No newline at end of file + max_elapsed_time: 10m +azuredataexplorer/9: + # Kusto cluster uri + cluster_uri: "https://CLUSTER.kusto.windows.net" + # weather to use the default azure auth + use_default_auth: true