From 7bbff490a3bd72054c153940512b25d65b8bf514 Mon Sep 17 00:00:00 2001 From: Ogulcan Aydogan Date: Thu, 19 Mar 2026 10:49:17 +0000 Subject: [PATCH] discovery/azure: fix system managed identity when client_id is empty When using ManagedIdentity authentication with system-assigned identity, the client_id field is intentionally left empty. However, the current code unconditionally sets options.ID = azidentity.ClientID(cfg.ClientID), which passes an empty string instead of nil. The Azure SDK treats an empty ClientID as a request for a user-assigned identity with an empty client ID, rather than falling back to system-assigned identity. Fix by only setting options.ID when cfg.ClientID is non-empty, matching the pattern already used in storage/remote/azuread/azuread.go. Fixes #16634 Signed-off-by: Ogulcan Aydogan --- discovery/azure/azure.go | 5 ++++- discovery/azure/azure_test.go | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/discovery/azure/azure.go b/discovery/azure/azure.go index 834eaf1f29..0ac9a9af4e 100644 --- a/discovery/azure/azure.go +++ b/discovery/azure/azure.go @@ -298,7 +298,10 @@ func newCredential(cfg SDConfig, policyClientOptions policy.ClientOptions) (azco } credential = azcore.TokenCredential(workloadIdentityCredential) case authMethodManagedIdentity: - options := &azidentity.ManagedIdentityCredentialOptions{ClientOptions: policyClientOptions, ID: azidentity.ClientID(cfg.ClientID)} + options := &azidentity.ManagedIdentityCredentialOptions{ClientOptions: policyClientOptions} + if cfg.ClientID != "" { + options.ID = azidentity.ClientID(cfg.ClientID) + } managedIdentityCredential, err := azidentity.NewManagedIdentityCredential(options) if err != nil { return nil, err diff --git a/discovery/azure/azure_test.go b/discovery/azure/azure_test.go index 23c120ac6b..dd2eeb0a3f 100644 --- a/discovery/azure/azure_test.go +++ b/discovery/azure/azure_test.go @@ -24,6 +24,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" azfake "github.com/Azure/azure-sdk-for-go/sdk/azcore/fake" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" fake "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5/fake" @@ -490,6 +491,27 @@ func TestNewAzureResourceFromID(t *testing.T) { } } +func TestNewCredentialManagedIdentity(t *testing.T) { + // Test that system-assigned managed identity (empty ClientID) creates + // a valid credential. Previously, an empty ClientID was passed as + // azidentity.ClientID("") which is not nil and caused Azure SDK to + // look up a non-existent user-assigned identity instead of falling + // back to system-assigned identity. + cfg := SDConfig{ + AuthenticationMethod: authMethodManagedIdentity, + ClientID: "", + } + cred, err := newCredential(cfg, policy.ClientOptions{}) + require.NoError(t, err) + require.NotNil(t, cred) + + // Test that user-assigned managed identity (non-empty ClientID) also works. + cfg.ClientID = "00000000-0000-0000-0000-000000000000" + cred, err = newCredential(cfg, policy.ClientOptions{}) + require.NoError(t, err) + require.NotNil(t, cred) +} + func TestAzureRefresh(t *testing.T) { tests := []struct { scenario string