Skip to content

Commit

Permalink
GH-39344: [C++][FS][Azure] Support azure cli auth (#41976)
Browse files Browse the repository at this point in the history
### Rationale for this change
Maybe be useful to support explicit environment credential (currently environment credential can be used as part of the Azure default credential flow).

### What changes are included in this PR?
Create `ConfigureCLICredential`. Add it to FromUri

### Are these changes tested?
There are new unittests but no integration tests that we can actually authenticate successfully. We are relying on the Azure C++ SDK to abstracting that away.

### Are there any user-facing changes?
Explicit CLI auth is now supported

* GitHub Issue: #39344

Authored-by: Thomas Newton <[email protected]>
Signed-off-by: Sutou Kouhei <[email protected]>
  • Loading branch information
Tom-Newton authored Jun 10, 2024
1 parent 95db23e commit f0a6f49
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 4 deletions.
14 changes: 14 additions & 0 deletions cpp/src/arrow/filesystem/azurefs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ Status AzureOptions::ExtractFromUriQuery(const Uri& uri) {
credential_kind = CredentialKind::kDefault;
} else if (kv.second == "anonymous") {
credential_kind = CredentialKind::kAnonymous;
} else if (kv.second == "cli") {
credential_kind = CredentialKind::kCLI;
} else if (kv.second == "workload_identity") {
credential_kind = CredentialKind::kWorkloadIdentity;
} else if (kv.second == "environment") {
Expand Down Expand Up @@ -170,6 +172,9 @@ Status AzureOptions::ExtractFromUriQuery(const Uri& uri) {
case CredentialKind::kAnonymous:
RETURN_NOT_OK(ConfigureAnonymousCredential());
break;
case CredentialKind::kCLI:
RETURN_NOT_OK(ConfigureCLICredential());
break;
case CredentialKind::kWorkloadIdentity:
RETURN_NOT_OK(ConfigureWorkloadIdentityCredential());
break;
Expand Down Expand Up @@ -255,6 +260,7 @@ bool AzureOptions::Equals(const AzureOptions& other) const {
return storage_shared_key_credential_->AccountName ==
other.storage_shared_key_credential_->AccountName;
case CredentialKind::kClientSecret:
case CredentialKind::kCLI:
case CredentialKind::kManagedIdentity:
case CredentialKind::kWorkloadIdentity:
case CredentialKind::kEnvironment:
Expand Down Expand Up @@ -337,6 +343,12 @@ Status AzureOptions::ConfigureManagedIdentityCredential(const std::string& clien
return Status::OK();
}

Status AzureOptions::ConfigureCLICredential() {
credential_kind_ = CredentialKind::kCLI;
token_credential_ = std::make_shared<Azure::Identity::AzureCliCredential>();
return Status::OK();
}

Status AzureOptions::ConfigureWorkloadIdentityCredential() {
credential_kind_ = CredentialKind::kWorkloadIdentity;
token_credential_ = std::make_shared<Azure::Identity::WorkloadIdentityCredential>();
Expand Down Expand Up @@ -364,6 +376,7 @@ Result<std::unique_ptr<Blobs::BlobServiceClient>> AzureOptions::MakeBlobServiceC
[[fallthrough]];
case CredentialKind::kClientSecret:
case CredentialKind::kManagedIdentity:
case CredentialKind::kCLI:
case CredentialKind::kWorkloadIdentity:
case CredentialKind::kEnvironment:
return std::make_unique<Blobs::BlobServiceClient>(AccountBlobUrl(account_name),
Expand Down Expand Up @@ -391,6 +404,7 @@ AzureOptions::MakeDataLakeServiceClient() const {
[[fallthrough]];
case CredentialKind::kClientSecret:
case CredentialKind::kManagedIdentity:
case CredentialKind::kCLI:
case CredentialKind::kWorkloadIdentity:
case CredentialKind::kEnvironment:
return std::make_unique<DataLake::DataLakeServiceClient>(
Expand Down
11 changes: 7 additions & 4 deletions cpp/src/arrow/filesystem/azurefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ struct ARROW_EXPORT AzureOptions {
kStorageSharedKey,
kClientSecret,
kManagedIdentity,
kCLI,
kWorkloadIdentity,
kEnvironment,
} credential_kind_ = CredentialKind::kDefault;
Expand Down Expand Up @@ -160,14 +161,15 @@ struct ARROW_EXPORT AzureOptions {
/// * blob_storage_authority: Set AzureOptions::blob_storage_authority
/// * dfs_storage_authority: Set AzureOptions::dfs_storage_authority
/// * enable_tls: If it's "false" or "0", HTTP not HTTPS is used.
/// * credential_kind: One of "default", "anonymous",
/// "workload_identity" or "environment". If "default" is specified, it's
/// * credential_kind: One of "default", "anonymous", "workload_identity",
/// "environment" or "cli". If "default" is specified, it's
/// just ignored. If "anonymous" is specified,
/// AzureOptions::ConfigureAnonymousCredential() is called. If
/// "workload_identity" is specified,
/// AzureOptions::ConfigureWorkloadIdentityCredential() is called, If
/// AzureOptions::ConfigureWorkloadIdentityCredential() is called. If
/// "environment" is specified,
/// AzureOptions::ConfigureEnvironmentCredential() is called.
/// AzureOptions::ConfigureEnvironmentCredential() is called. If "cli" is
/// specified, AzureOptions::ConfigureCLICredential() is called.
/// * tenant_id: You must specify "client_id" and "client_secret"
/// too. AzureOptions::ConfigureClientSecretCredential() is called.
/// * client_id: If you don't specify "tenant_id" and
Expand All @@ -190,6 +192,7 @@ struct ARROW_EXPORT AzureOptions {
const std::string& client_id,
const std::string& client_secret);
Status ConfigureManagedIdentityCredential(const std::string& client_id = std::string());
Status ConfigureCLICredential();
Status ConfigureWorkloadIdentityCredential();
Status ConfigureEnvironmentCredential();

Expand Down
17 changes: 17 additions & 0 deletions cpp/src/arrow/filesystem/azurefs_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,13 @@ TEST(AzureFileSystem, InitializeWithManagedIdentityCredential) {
EXPECT_OK_AND_ASSIGN(fs, AzureFileSystem::Make(options));
}

TEST(AzureFileSystem, InitializeWithCLICredential) {
AzureOptions options;
options.account_name = "dummy-account-name";
ARROW_EXPECT_OK(options.ConfigureCLICredential());
EXPECT_OK_AND_ASSIGN(auto fs, AzureFileSystem::Make(options));
}

TEST(AzureFileSystem, InitializeWithWorkloadIdentityCredential) {
AzureOptions options;
options.account_name = "dummy-account-name";
Expand Down Expand Up @@ -667,6 +674,15 @@ class TestAzureOptions : public ::testing::Test {
ASSERT_EQ(options.credential_kind_, AzureOptions::CredentialKind::kManagedIdentity);
}

void TestFromUriCredentialCLI() {
ASSERT_OK_AND_ASSIGN(
auto options,
AzureOptions::FromUri("abfs://account.blob.core.windows.net/container/dir/blob?"
"credential_kind=cli",
nullptr));
ASSERT_EQ(options.credential_kind_, AzureOptions::CredentialKind::kCLI);
}

void TestFromUriCredentialWorkloadIdentity() {
ASSERT_OK_AND_ASSIGN(
auto options,
Expand Down Expand Up @@ -733,6 +749,7 @@ TEST_F(TestAzureOptions, FromUriCredentialClientSecret) {
TEST_F(TestAzureOptions, FromUriCredentialManagedIdentity) {
TestFromUriCredentialManagedIdentity();
}
TEST_F(TestAzureOptions, FromUriCredentialCLI) { TestFromUriCredentialCLI(); }
TEST_F(TestAzureOptions, FromUriCredentialWorkloadIdentity) {
TestFromUriCredentialWorkloadIdentity();
}
Expand Down

0 comments on commit f0a6f49

Please sign in to comment.