This is an automated email from the ASF dual-hosted git repository.
kou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new f0a6f49016 GH-39344: [C++][FS][Azure] Support azure cli auth (#41976)
f0a6f49016 is described below
commit f0a6f490161e50411242cd026d7adf9303f5f109
Author: Thomas Newton <[email protected]>
AuthorDate: Mon Jun 10 07:40:58 2024 +0100
GH-39344: [C++][FS][Azure] Support azure cli auth (#41976)
### 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]>
---
cpp/src/arrow/filesystem/azurefs.cc | 14 ++++++++++++++
cpp/src/arrow/filesystem/azurefs.h | 11 +++++++----
cpp/src/arrow/filesystem/azurefs_test.cc | 17 +++++++++++++++++
3 files changed, 38 insertions(+), 4 deletions(-)
diff --git a/cpp/src/arrow/filesystem/azurefs.cc
b/cpp/src/arrow/filesystem/azurefs.cc
index f367bbdd3e..809aef32b3 100644
--- a/cpp/src/arrow/filesystem/azurefs.cc
+++ b/cpp/src/arrow/filesystem/azurefs.cc
@@ -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") {
@@ -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;
@@ -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:
@@ -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>();
@@ -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),
@@ -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>(
diff --git a/cpp/src/arrow/filesystem/azurefs.h
b/cpp/src/arrow/filesystem/azurefs.h
index 5d100bbcb4..93d6ec2f94 100644
--- a/cpp/src/arrow/filesystem/azurefs.h
+++ b/cpp/src/arrow/filesystem/azurefs.h
@@ -119,6 +119,7 @@ struct ARROW_EXPORT AzureOptions {
kStorageSharedKey,
kClientSecret,
kManagedIdentity,
+ kCLI,
kWorkloadIdentity,
kEnvironment,
} credential_kind_ = CredentialKind::kDefault;
@@ -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
@@ -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();
diff --git a/cpp/src/arrow/filesystem/azurefs_test.cc
b/cpp/src/arrow/filesystem/azurefs_test.cc
index 6075cbf0c0..05ff3e551c 100644
--- a/cpp/src/arrow/filesystem/azurefs_test.cc
+++ b/cpp/src/arrow/filesystem/azurefs_test.cc
@@ -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";
@@ -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,
@@ -733,6 +749,7 @@ TEST_F(TestAzureOptions, FromUriCredentialClientSecret) {
TEST_F(TestAzureOptions, FromUriCredentialManagedIdentity) {
TestFromUriCredentialManagedIdentity();
}
+TEST_F(TestAzureOptions, FromUriCredentialCLI) { TestFromUriCredentialCLI(); }
TEST_F(TestAzureOptions, FromUriCredentialWorkloadIdentity) {
TestFromUriCredentialWorkloadIdentity();
}