Skip to content

Commit dca2f1b

Browse files
committed
chore: add support to use ManagedIdentityCredential when clientID is configured
This commit add supports for ManagedIdentityCredential when AZURE_CLIENT_ID is configured Signed-off-by: Mitta Sai Chaithanya <mittas@microsoft.com>
1 parent f73a19a commit dca2f1b

4 files changed

Lines changed: 38 additions & 14 deletions

File tree

cpp/azure/client/client.cc

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <azure/storage/blobs.hpp>
1313
#include <azure/identity/default_azure_credential.hpp>
14+
#include <azure/identity/managed_identity_credential.hpp>
1415
#include <azure/storage/common/storage_credential.hpp>
1516
#include <azure/core/exception.hpp>
1617

@@ -34,6 +35,7 @@ AzureClient::AzureClient(const common::backend_api::ObjectClientConfig_t& config
3435
// ClientConfiguration reads environment variables
3536
_account_name = _client_config.account_name;
3637
_account_key = _client_config.account_key;
38+
_client_id = _client_config.client_id;
3739
#ifdef AZURITE_TESTING
3840
_connection_string = _client_config.connection_string;
3941
#endif
@@ -61,6 +63,10 @@ AzureClient::AzureClient(const common::backend_api::ObjectClientConfig_t& config
6163
_connection_string = std::string(value);
6264
}
6365
#endif
66+
else if (strcmp(key, "client_id") == 0)
67+
{
68+
_client_id = std::string(value);
69+
}
6470
else
6571
{
6672
LOG(WARNING) << "Unknown Azure parameter: " << key;
@@ -101,15 +107,28 @@ AzureClient::AzureClient(const common::backend_api::ObjectClientConfig_t& config
101107
_blob_service_client = std::make_shared<BlobServiceClient>(url, credential, options);
102108
LOG(DEBUG) << "Azure client initialized with StorageSharedKeyCredential for account: " << _account_name.value();
103109
} else {
104-
// Use DefaultAzureCredential (managed identity, Azure CLI, environment variables, etc.)
105-
// Reference: https://learn.microsoft.com/en-us/azure/developer/cpp/sdk/authentication
106110
std::string url = "https://" + _account_name.value() + ".blob.core.windows.net";
107-
// Share a single DefaultAzureCredential across all clients in the process to better
108-
// utilize token caching and reduce chances of overwhelming authentication sources
109-
// (e.g., IMDS) which can result in fatal throttling errors.
110-
static auto credential = std::make_shared<Azure::Identity::DefaultAzureCredential>();
111-
_blob_service_client = std::make_shared<BlobServiceClient>(url, credential, options);
112-
LOG(DEBUG) << "Azure client initialized with DefaultAzureCredential for account: " << _account_name.value();
111+
std::shared_ptr<Azure::Core::Credentials::TokenCredential> credential;
112+
113+
// Try DefaultAzureCredential first, fall back to ManagedIdentityCredential
114+
// with explicit client_id (AZURE_CLIENT_ID is injected by webhooks into the pod)
115+
try {
116+
LOG(DEBUG) << "Trying DefaultAzureCredential";
117+
static auto default_cred = std::make_shared<Azure::Identity::DefaultAzureCredential>();
118+
credential = default_cred;
119+
_blob_service_client = std::make_shared<BlobServiceClient>(url, credential, options);
120+
LOG(DEBUG) << "Azure client initialized with DefaultAzureCredential for account: " << _account_name.value();
121+
} catch (const std::exception& e) {
122+
LOG(WARNING) << "DefaultAzureCredential failed: " << e.what();
123+
if (_client_id.has_value()) {
124+
LOG(DEBUG) << "Falling back to ManagedIdentityCredential with client_id: " << _client_id.value();
125+
credential = std::make_shared<Azure::Identity::ManagedIdentityCredential>(_client_id.value());
126+
_blob_service_client = std::make_shared<BlobServiceClient>(url, credential, options);
127+
LOG(DEBUG) << "Azure client initialized with ManagedIdentityCredential for account: " << _account_name.value();
128+
} else {
129+
throw;
130+
}
131+
}
113132
}
114133
} else {
115134
#ifdef AZURITE_TESTING

cpp/azure/client/client.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct AzureClient : common::IClient
4747
// Azure credentials
4848
std::optional<std::string> _account_name;
4949
std::optional<std::string> _account_key;
50+
std::optional<std::string> _client_id;
5051
#ifdef AZURITE_TESTING
5152
std::optional<std::string> _connection_string;
5253
#endif

cpp/azure/client_configuration/client_configuration.cc

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,20 @@ ClientConfiguration::ClientConfiguration()
2929
}
3030

3131
// Account name configuration from environment variable
32-
// Authentication uses DefaultAzureCredential which supports:
33-
// - Environment variables (AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET)
34-
// - Managed Identity
35-
// - Azure CLI
36-
// - Visual Studio Code
37-
// Reference: https://learn.microsoft.com/en-us/azure/developer/cpp/sdk/authentication
3832
const auto acct_name = utils::getenv<std::string>("AZURE_STORAGE_ACCOUNT_NAME", "");
3933
if (!acct_name.empty()) {
4034
LOG(DEBUG) << "Azure Storage account name: " << acct_name;
4135
account_name = acct_name;
4236
}
4337

38+
// Client ID for user-assigned managed identity
39+
// When set, DefaultAzureCredential will target this specific managed identity
40+
const auto cid = utils::getenv<std::string>("AZURE_CLIENT_ID", "");
41+
if (!cid.empty()) {
42+
LOG(DEBUG) << "Using AZURE_CLIENT_ID for managed identity: " << cid;
43+
client_id = cid;
44+
}
45+
4446
unsigned nprocs = std::thread::hardware_concurrency();
4547
LOG(SPAM) << "Hardware concurrency detected: " << nprocs;
4648
unsigned default_max_concurrency = nprocs == 0 ? 8U : 1U;

cpp/azure/client_configuration/client_configuration.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ struct ClientConfiguration
1111
// Azure client configuration options
1212
std::optional<std::string> account_name;
1313
std::optional<std::string> account_key;
14+
// Client ID for user-assigned managed identity
15+
std::optional<std::string> client_id;
1416
#ifdef AZURITE_TESTING
1517
// Connection string is only available for Azurite/local testing
1618
std::optional<std::string> connection_string;

0 commit comments

Comments
 (0)