This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.0 by this push:
     new add05a81297 branch-4.0: [fix](be) Default to the Default chain when S3 
role_arn is set without provider_type #60822 (#60965)
add05a81297 is described below

commit add05a8129713d200f66ec44e90e11035c2083a0
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Tue Mar 3 17:47:24 2026 +0800

    branch-4.0: [fix](be) Default to the Default chain when S3 role_arn is set 
without provider_type #60822 (#60965)
    
    Cherry-picked from #60822
    
    Co-authored-by: Calvin Kirs <[email protected]>
---
 be/src/util/s3_util.cpp               |   3 +-
 be/test/io/s3_client_factory_test.cpp | 243 +++++++++++++++++++++++++++++++++-
 2 files changed, 244 insertions(+), 2 deletions(-)

diff --git a/be/src/util/s3_util.cpp b/be/src/util/s3_util.cpp
index 7dacf3afb4f..9f6f9ccdaf3 100644
--- a/be/src/util/s3_util.cpp
+++ b/be/src/util/s3_util.cpp
@@ -563,7 +563,8 @@ Status S3ClientFactory::convert_properties_to_s3_conf(
     }
 
     if (auto it = properties.find(S3_ROLE_ARN); it != properties.end()) {
-        s3_conf->client_conf.cred_provider_type = 
CredProviderType::InstanceProfile;
+        // Keep provider type as Default unless explicitly configured by
+        // AWS_CREDENTIALS_PROVIDER_TYPE, consistent with FE behavior.
         s3_conf->client_conf.role_arn = it->second;
     }
 
diff --git a/be/test/io/s3_client_factory_test.cpp 
b/be/test/io/s3_client_factory_test.cpp
index 30df26ce64d..792d815cbca 100644
--- a/be/test/io/s3_client_factory_test.cpp
+++ b/be/test/io/s3_client_factory_test.cpp
@@ -16,10 +16,15 @@
 // under the License.
 
 #include <aws/core/auth/AWSCredentialsProviderChain.h>
+#include <aws/core/auth/STSCredentialsProvider.h>
 #include <aws/identity-management/auth/STSAssumeRoleCredentialsProvider.h>
 #include <gtest/gtest.h>
 
+#include <cstdlib>
+#include <vector>
+
 #include "cpp/custom_aws_credentials_provider_chain.h"
+#include "util/s3_uri.h"
 #include "util/s3_util.h"
 
 namespace doris {
@@ -43,6 +48,9 @@ TEST_F(S3ClientFactoryTest, AwsCredentialsProvider) {
     role_conf2.role_arn = "role_arn";
     role_conf2.external_id = "external_id";
 
+    S3ClientConf web_identity_conf;
+    web_identity_conf.cred_provider_type = CredProviderType::WebIdentity;
+
     config::aws_credentials_provider_version = "v2";
     {
         auto provider_v2 = 
factory.get_aws_credentials_provider(anonymous_conf);
@@ -72,6 +80,14 @@ TEST_F(S3ClientFactoryTest, AwsCredentialsProvider) {
         ASSERT_NE(custom_chain_v2, nullptr);
     }
 
+    {
+        auto provider_v2 = 
factory.get_aws_credentials_provider(web_identity_conf);
+        auto web_identity_v2 =
+                
std::dynamic_pointer_cast<Aws::Auth::STSAssumeRoleWebIdentityCredentialsProvider>(
+                        provider_v2);
+        ASSERT_NE(web_identity_v2, nullptr);
+    }
+
     config::aws_credentials_provider_version = "v1";
     {
         auto provider_v1 = 
factory.get_aws_credentials_provider(anonymous_conf);
@@ -105,4 +121,229 @@ TEST_F(S3ClientFactoryTest, AwsCredentialsProvider) {
     config::aws_credentials_provider_version = "v2";
 }
 
-} // namespace doris
\ No newline at end of file
+TEST_F(S3ClientFactoryTest, ConvertPropertiesToS3ConfRoleArnProviderType) {
+    std::map<std::string, std::string> properties {
+            {"AWS_ENDPOINT", "s3.us-west-2.amazonaws.com"},
+            {"AWS_REGION", "us-west-2"},
+            {"AWS_ROLE_ARN", "arn:aws:iam::123456789012:role/test-role"},
+    };
+
+    S3URI s3_uri("s3://test-bucket/test-prefix");
+    ASSERT_TRUE(s3_uri.parse().ok());
+
+    S3Conf s3_conf;
+    ASSERT_TRUE(S3ClientFactory::convert_properties_to_s3_conf(properties, 
s3_uri, &s3_conf).ok());
+    ASSERT_EQ(s3_conf.client_conf.cred_provider_type, 
CredProviderType::Default);
+
+    properties["AWS_CREDENTIALS_PROVIDER_TYPE"] = "WEB_IDENTITY";
+    ASSERT_TRUE(S3ClientFactory::convert_properties_to_s3_conf(properties, 
s3_uri, &s3_conf).ok());
+    ASSERT_EQ(s3_conf.client_conf.cred_provider_type, 
CredProviderType::WebIdentity);
+}
+
+TEST_F(S3ClientFactoryTest, ConvertPropertiesToS3ConfProviderTypeMatrix) {
+    S3URI s3_uri("s3://test-bucket/test-prefix");
+    ASSERT_TRUE(s3_uri.parse().ok());
+
+    std::map<std::string, std::string> base_properties {
+            {"AWS_ENDPOINT", "s3.us-west-2.amazonaws.com"},
+            {"AWS_REGION", "us-west-2"},
+    };
+
+    struct TestCase {
+        const char* provider_type;
+        CredProviderType expected;
+    };
+
+    std::vector<TestCase> cases = {
+            {"DEFAULT", CredProviderType::Default},
+            {"ENV", CredProviderType::Env},
+            {"SYSTEM_PROPERTIES", CredProviderType::SystemProperties},
+            {"WEB_IDENTITY", CredProviderType::WebIdentity},
+            {"CONTAINER", CredProviderType::Container},
+            {"INSTANCE_PROFILE", CredProviderType::InstanceProfile},
+            {"ANONYMOUS", CredProviderType::Anonymous},
+    };
+
+    for (const auto& test_case : cases) {
+        S3Conf s3_conf;
+        auto properties = base_properties;
+        properties["AWS_CREDENTIALS_PROVIDER_TYPE"] = test_case.provider_type;
+        ASSERT_TRUE(
+                S3ClientFactory::convert_properties_to_s3_conf(properties, 
s3_uri, &s3_conf).ok())
+                << "provider_type=" << test_case.provider_type;
+        ASSERT_EQ(s3_conf.client_conf.cred_provider_type, test_case.expected)
+                << "provider_type=" << test_case.provider_type;
+    }
+}
+
+TEST_F(S3ClientFactoryTest, ConvertPropertiesToS3ConfCredentialValidation) {
+    S3URI s3_uri("s3://test-bucket/test-prefix");
+    ASSERT_TRUE(s3_uri.parse().ok());
+
+    std::map<std::string, std::string> base_properties {
+            {"AWS_ENDPOINT", "s3.us-west-2.amazonaws.com"},
+            {"AWS_REGION", "us-west-2"},
+    };
+    {
+        auto properties = base_properties;
+        properties["AWS_ACCESS_KEY"] = "ak";
+        S3Conf s3_conf;
+        ASSERT_FALSE(
+                S3ClientFactory::convert_properties_to_s3_conf(properties, 
s3_uri, &s3_conf).ok());
+    }
+
+    {
+        auto properties = base_properties;
+        properties["AWS_SECRET_KEY"] = "sk";
+        S3Conf s3_conf;
+        ASSERT_FALSE(
+                S3ClientFactory::convert_properties_to_s3_conf(properties, 
s3_uri, &s3_conf).ok());
+    }
+
+    {
+        auto properties = base_properties;
+        S3Conf s3_conf;
+        ASSERT_TRUE(
+                S3ClientFactory::convert_properties_to_s3_conf(properties, 
s3_uri, &s3_conf).ok());
+    }
+
+    {
+        auto properties = base_properties;
+        properties["AWS_ROLE_ARN"] = 
"arn:aws:iam::123456789012:role/test-role";
+        S3Conf s3_conf;
+        ASSERT_TRUE(
+                S3ClientFactory::convert_properties_to_s3_conf(properties, 
s3_uri, &s3_conf).ok());
+    }
+
+    {
+        auto properties = base_properties;
+        properties["AWS_ACCESS_KEY"] = "ak";
+        properties["AWS_ROLE_ARN"] = 
"arn:aws:iam::123456789012:role/test-role";
+        S3Conf s3_conf;
+        ASSERT_TRUE(
+                S3ClientFactory::convert_properties_to_s3_conf(properties, 
s3_uri, &s3_conf).ok());
+    }
+
+    {
+        auto properties = base_properties;
+        properties["AWS_SECRET_KEY"] = "sk";
+        properties["AWS_ROLE_ARN"] = 
"arn:aws:iam::123456789012:role/test-role";
+        S3Conf s3_conf;
+        ASSERT_TRUE(
+                S3ClientFactory::convert_properties_to_s3_conf(properties, 
s3_uri, &s3_conf).ok());
+    }
+}
+
+TEST_F(S3ClientFactoryTest, 
AwsCredentialsProviderV2ProviderTypeWithoutRoleArn) {
+    S3ClientFactory& factory = S3ClientFactory::instance();
+    config::aws_credentials_provider_version = "v2";
+
+    S3ClientConf default_conf;
+    default_conf.cred_provider_type = CredProviderType::Default;
+    auto provider = factory.get_aws_credentials_provider(default_conf);
+    
ASSERT_NE(std::dynamic_pointer_cast<CustomAwsCredentialsProviderChain>(provider),
 nullptr);
+
+    S3ClientConf env_conf;
+    env_conf.cred_provider_type = CredProviderType::Env;
+    provider = factory.get_aws_credentials_provider(env_conf);
+    
ASSERT_NE(std::dynamic_pointer_cast<Aws::Auth::EnvironmentAWSCredentialsProvider>(provider),
+              nullptr);
+
+    S3ClientConf sys_conf;
+    sys_conf.cred_provider_type = CredProviderType::SystemProperties;
+    provider = factory.get_aws_credentials_provider(sys_conf);
+    ASSERT_NE(
+            
std::dynamic_pointer_cast<Aws::Auth::ProfileConfigFileAWSCredentialsProvider>(provider),
+            nullptr);
+
+    S3ClientConf web_identity_conf;
+    web_identity_conf.cred_provider_type = CredProviderType::WebIdentity;
+    provider = factory.get_aws_credentials_provider(web_identity_conf);
+    
ASSERT_NE(std::dynamic_pointer_cast<Aws::Auth::STSAssumeRoleWebIdentityCredentialsProvider>(
+                      provider),
+              nullptr);
+
+    const char* old_container_uri = 
std::getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI");
+    if (old_container_uri == nullptr) {
+        setenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", 
"/v2/credentials/mock", 1);
+    }
+    S3ClientConf container_conf;
+    container_conf.cred_provider_type = CredProviderType::Container;
+    provider = factory.get_aws_credentials_provider(container_conf);
+    
ASSERT_NE(std::dynamic_pointer_cast<Aws::Auth::TaskRoleCredentialsProvider>(provider),
 nullptr);
+    if (old_container_uri == nullptr) {
+        unsetenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI");
+    }
+
+    S3ClientConf instance_profile_conf;
+    instance_profile_conf.cred_provider_type = 
CredProviderType::InstanceProfile;
+    provider = factory.get_aws_credentials_provider(instance_profile_conf);
+    
ASSERT_NE(std::dynamic_pointer_cast<Aws::Auth::InstanceProfileCredentialsProvider>(provider),
+              nullptr);
+
+    S3ClientConf anonymous_conf;
+    anonymous_conf.cred_provider_type = CredProviderType::Anonymous;
+    provider = factory.get_aws_credentials_provider(anonymous_conf);
+    
ASSERT_NE(std::dynamic_pointer_cast<Aws::Auth::AnonymousAWSCredentialsProvider>(provider),
+              nullptr);
+}
+
+TEST_F(S3ClientFactoryTest, 
AwsCredentialsProviderV2WithRoleArnAlwaysAssumeRole) {
+    S3ClientFactory& factory = S3ClientFactory::instance();
+    config::aws_credentials_provider_version = "v2";
+
+    std::vector<CredProviderType> provider_types = {
+            CredProviderType::Default,          CredProviderType::Env,
+            CredProviderType::SystemProperties, CredProviderType::WebIdentity,
+            CredProviderType::Container,        
CredProviderType::InstanceProfile,
+            CredProviderType::Anonymous,
+    };
+
+    for (auto provider_type : provider_types) {
+        S3ClientConf conf;
+        conf.cred_provider_type = provider_type;
+        conf.role_arn = "arn:aws:iam::123456789012:role/test-role";
+        conf.external_id = "external-id";
+        auto provider = factory.get_aws_credentials_provider(conf);
+        
ASSERT_NE(std::dynamic_pointer_cast<Aws::Auth::STSAssumeRoleCredentialsProvider>(provider),
+                  nullptr);
+    }
+}
+
+TEST_F(S3ClientFactoryTest, 
AwsCredentialsProviderAkSkTakePrecedenceOverRoleArn) {
+    S3ClientFactory& factory = S3ClientFactory::instance();
+    S3ClientConf conf;
+    conf.ak = "ak";
+    conf.sk = "sk";
+    conf.role_arn = "arn:aws:iam::123456789012:role/test-role";
+    conf.external_id = "external-id";
+    conf.cred_provider_type = CredProviderType::InstanceProfile;
+
+    config::aws_credentials_provider_version = "v2";
+    auto provider_v2 = factory.get_aws_credentials_provider(conf);
+    
ASSERT_NE(std::dynamic_pointer_cast<Aws::Auth::SimpleAWSCredentialsProvider>(provider_v2),
+              nullptr);
+
+    config::aws_credentials_provider_version = "v1";
+    auto provider_v1 = factory.get_aws_credentials_provider(conf);
+    
ASSERT_NE(std::dynamic_pointer_cast<Aws::Auth::SimpleAWSCredentialsProvider>(provider_v1),
+              nullptr);
+
+    config::aws_credentials_provider_version = "v2";
+}
+
+TEST_F(S3ClientFactoryTest, AwsCredentialsProviderV1RoleArnDefaultFallback) {
+    S3ClientFactory& factory = S3ClientFactory::instance();
+    config::aws_credentials_provider_version = "v1";
+
+    S3ClientConf conf;
+    conf.cred_provider_type = CredProviderType::Default;
+    conf.role_arn = "arn:aws:iam::123456789012:role/test-role";
+    auto provider = factory.get_aws_credentials_provider(conf);
+    
ASSERT_NE(std::dynamic_pointer_cast<Aws::Auth::AnonymousAWSCredentialsProvider>(provider),
+              nullptr);
+
+    config::aws_credentials_provider_version = "v2";
+}
+
+} // namespace doris


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to