Skip to content

Commit ed35cd8

Browse files
authored
[fix](s3)Use anonymous credentials for S3-compatible storage when credentials are absent (#60443)
… For S3-compatible object storages such as COS and OBS, authentication does not fully follow the AWS native credential provider chain. In these systems, anonymous access is a valid and commonly used mode when no AK/SK is configured. However, when `aws_credentials_provider_version` is set to `v2`, BE currently falls back to the AWS SDK v2 default credential provider chain if no credentials are explicitly provided. This behavior is AWS-specific and is not applicable to S3-compatible storage systems like COS and OBS, which may not support or require the AWS credential resolution chain. Problem ------- When `aws_credentials_provider_version = v2` and no AK/SK is configured: - BE attempts to resolve credentials using the AWS SDK v2 provider chain - This may lead to unexpected authentication failures or unnecessary environment dependency - The behavior is inconsistent with S3-compatible storage expectations Expected Behavior ----------------- For S3-compatible object storage: - If AK/SK is explicitly provided, use the configured credentials - If no credentials are provided, fall back to anonymous credentials - Do NOT trigger the AWS SDK v2 default credential provider chain
1 parent d95d647 commit ed35cd8

File tree

6 files changed

+54
-5
lines changed

6 files changed

+54
-5
lines changed

fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/AbstractS3CompatibleProperties.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package org.apache.doris.datasource.property.storage;
1919

2020
import org.apache.doris.common.UserException;
21+
import org.apache.doris.datasource.property.common.AwsCredentialsProviderMode;
2122

2223
import com.google.common.base.Preconditions;
2324
import com.google.common.base.Strings;
@@ -108,9 +109,20 @@ private Map<String, String> doBuildS3Configuration(String maxConnections,
108109
if (StringUtils.isNotBlank(getSessionToken())) {
109110
s3Props.put("AWS_TOKEN", getSessionToken());
110111
}
112+
String credentialsProviderType = getAwsCredentialsProviderTypeForBackend();
113+
if (StringUtils.isNotBlank(credentialsProviderType)) {
114+
s3Props.put("AWS_CREDENTIALS_PROVIDER_TYPE", credentialsProviderType);
115+
}
111116
return s3Props;
112117
}
113118

119+
protected String getAwsCredentialsProviderTypeForBackend() {
120+
if (StringUtils.isBlank(getAccessKey()) && StringUtils.isBlank(getSecretKey())) {
121+
return AwsCredentialsProviderMode.ANONYMOUS.name();
122+
}
123+
return null;
124+
}
125+
114126
@Override
115127
public Map<String, String> getBackendConfigProperties() {
116128
return generateBackendS3Configuration();

fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/S3Properties.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -291,13 +291,14 @@ public Map<String, String> getBackendConfigProperties() {
291291
if (StringUtils.isNotBlank(s3ExternalId)) {
292292
backendProperties.put("AWS_EXTERNAL_ID", s3ExternalId);
293293
}
294-
// Pass credentials provider type to BE
295-
if (awsCredentialsProviderMode != null) {
296-
backendProperties.put("AWS_CREDENTIALS_PROVIDER_TYPE", awsCredentialsProviderMode.getMode());
297-
}
298294
return backendProperties;
299295
}
300296

297+
@Override
298+
protected String getAwsCredentialsProviderTypeForBackend() {
299+
return awsCredentialsProviderMode == null ? null : awsCredentialsProviderMode.getMode();
300+
}
301+
301302
private void convertGlueToS3EndpointIfNeeded() {
302303
if (this.endpoint.contains("glue")) {
303304
this.endpoint = "https://s3." + this.region + ".amazonaws.com";
@@ -671,4 +672,3 @@ public static TS3StorageParam getS3TStorageParam(Map<String, String> properties)
671672
}
672673

673674
}
674-

fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/COSPropertiesTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,14 @@ public void testAwsCredentialsProvider() throws Exception {
173173
props.put("cos.endpoint", "cos.ap-beijing.myqcloud.com");
174174
COSProperties obsStorageProperties = (COSProperties) StorageProperties.createPrimary(props);
175175
Assertions.assertEquals(AnonymousCredentialsProvider.class, obsStorageProperties.getAwsCredentialsProvider().getClass());
176+
Map<String, String> backendProps = obsStorageProperties.getBackendConfigProperties();
177+
Assertions.assertEquals("ANONYMOUS", backendProps.get("AWS_CREDENTIALS_PROVIDER_TYPE"));
176178
props.put("cos.access_key", "myAccessKey");
177179
props.put("cos.secret_key", "mySecretKey");
178180
obsStorageProperties = (COSProperties) StorageProperties.createPrimary(props);
179181
Assertions.assertEquals(StaticCredentialsProvider.class, obsStorageProperties.getAwsCredentialsProvider().getClass());
182+
backendProps = obsStorageProperties.getBackendConfigProperties();
183+
Assertions.assertNull(backendProps.get("AWS_CREDENTIALS_PROVIDER_TYPE"));
180184
}
181185

182186
@Test

fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/OBSPropertyTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,14 @@ public void testAwsCredentialsProvider() throws Exception {
149149
props.put("obs.endpoint", "obs.cn-north-4.myhuaweicloud.com");
150150
OBSProperties obsStorageProperties = (OBSProperties) StorageProperties.createPrimary(props);
151151
Assertions.assertEquals(AnonymousCredentialsProvider.class, obsStorageProperties.getAwsCredentialsProvider().getClass());
152+
Map<String, String> backendProps = obsStorageProperties.getBackendConfigProperties();
153+
Assertions.assertEquals("ANONYMOUS", backendProps.get("AWS_CREDENTIALS_PROVIDER_TYPE"));
152154
props.put("obs.access_key", "myAccessKey");
153155
props.put("obs.secret_key", "mySecretKey");
154156
obsStorageProperties = (OBSProperties) StorageProperties.createPrimary(props);
155157
Assertions.assertEquals(StaticCredentialsProvider.class, obsStorageProperties.getAwsCredentialsProvider().getClass());
158+
backendProps = obsStorageProperties.getBackendConfigProperties();
159+
Assertions.assertNull(backendProps.get("AWS_CREDENTIALS_PROVIDER_TYPE"));
156160
}
157161

158162
@Test

fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/OSSPropertiesTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,14 @@ public void testAwsCredentialsProvider() throws Exception {
246246
ossProps.put("oss.endpoint", "oss-cn-hangzhou.aliyuncs.com");
247247
OSSProperties ossStorageProperties = (OSSProperties) StorageProperties.createPrimary(ossProps);
248248
Assertions.assertEquals(AnonymousCredentialsProvider.class, ossStorageProperties.getAwsCredentialsProvider().getClass());
249+
Map<String, String> backendProps = ossStorageProperties.getBackendConfigProperties();
250+
Assertions.assertEquals("ANONYMOUS", backendProps.get("AWS_CREDENTIALS_PROVIDER_TYPE"));
249251
ossProps.put("oss.access_key", "myAccessKey");
250252
ossProps.put("oss.secret_key", "mySecretKey");
251253
ossStorageProperties = (OSSProperties) StorageProperties.createPrimary(ossProps);
252254
Assertions.assertEquals(StaticCredentialsProvider.class, ossStorageProperties.getAwsCredentialsProvider().getClass());
255+
backendProps = ossStorageProperties.getBackendConfigProperties();
256+
Assertions.assertNull(backendProps.get("AWS_CREDENTIALS_PROVIDER_TYPE"));
253257
}
254258

255259
@Test

fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/S3PropertiesTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ public void testToNativeS3Configuration() throws UserException {
149149
Assertions.assertEquals("88", s3Props.get("AWS_MAX_CONNECTIONS"));
150150
Assertions.assertEquals("6000", s3Props.get("AWS_CONNECTION_TIMEOUT_MS"));
151151
Assertions.assertEquals("true", s3Props.get("use_path_style"));
152+
Assertions.assertEquals("DEFAULT", s3Props.get("AWS_CREDENTIALS_PROVIDER_TYPE"));
152153
origProps.remove("use_path_style");
153154
origProps.remove("s3.connection.maximum");
154155
origProps.remove("s3.connection.timeout");
@@ -159,6 +160,30 @@ public void testToNativeS3Configuration() throws UserException {
159160
Assertions.assertEquals("6000", s3Props.get("AWS_CONNECTION_TIMEOUT_MS"));
160161
}
161162

163+
@Test
164+
public void testBackendCredentialsProviderType() throws UserException {
165+
Map<String, String> props = new HashMap<>();
166+
props.put("s3.endpoint", "s3.us-west-2.amazonaws.com");
167+
props.put("s3.region", "us-west-2");
168+
169+
String[][] cases = new String[][] {
170+
{"default", "DEFAULT"},
171+
{"env", "ENV"},
172+
{"system_properties", "SYSTEM_PROPERTIES"},
173+
{"web_identity", "WEB_IDENTITY"},
174+
{"container", "CONTAINER"},
175+
{"instance_profile", "INSTANCE_PROFILE"},
176+
{"anonymous", "ANONYMOUS"}
177+
};
178+
179+
for (String[] testCase : cases) {
180+
props.put("s3.credentials_provider_type", testCase[0]);
181+
S3Properties s3Props = (S3Properties) StorageProperties.createPrimary(props);
182+
Map<String, String> backendProps = s3Props.getBackendConfigProperties();
183+
Assertions.assertEquals(testCase[1], backendProps.get("AWS_CREDENTIALS_PROVIDER_TYPE"));
184+
}
185+
}
186+
162187

163188
@Test
164189
public void testGetRegion() throws UserException {

0 commit comments

Comments
 (0)