This is an automated email from the ASF dual-hosted git repository.
yuqi1129 pushed a commit to branch branch-1.3
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/branch-1.3 by this push:
new cdce64d430 [Cherry-pick to branch-1.3] [MINOR] fix(aws): Support MinIO
role ARNs in IRSA credential vending (#11883) (#11887)
cdce64d430 is described below
commit cdce64d4305edc0c27f2323f5442b812a5e78c79
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Fri Jul 3 09:14:27 2026 +0800
[Cherry-pick to branch-1.3] [MINOR] fix(aws): Support MinIO role ARNs in
IRSA credential vending (#11883) (#11887)
**Cherry-pick Information:**
- Original commit: 2de6492d6f995c9e329c7f53ccc26169e5cd1612
- Target branch: `branch-1.3`
- Status: ✅ Clean cherry-pick (no conflicts)
Co-authored-by: Qi Yu <[email protected]>
---
.../s3/credential/AwsIrsaCredentialGenerator.java | 9 +++++-
.../webidentity/WebIdentityTokenSources.java | 5 +--
.../credential/TestAwsIrsaCredentialGenerator.java | 37 ++++++++++++++++++++++
.../webidentity/TestWebIdentityTokenSources.java | 11 ++++---
docs/security/credential-vending.md | 16 +++++-----
5 files changed, 62 insertions(+), 16 deletions(-)
diff --git
a/bundles/aws/src/main/java/org/apache/gravitino/s3/credential/AwsIrsaCredentialGenerator.java
b/bundles/aws/src/main/java/org/apache/gravitino/s3/credential/AwsIrsaCredentialGenerator.java
index c960da6900..2d5fe0f6ba 100644
---
a/bundles/aws/src/main/java/org/apache/gravitino/s3/credential/AwsIrsaCredentialGenerator.java
+++
b/bundles/aws/src/main/java/org/apache/gravitino/s3/credential/AwsIrsaCredentialGenerator.java
@@ -335,12 +335,19 @@ public class AwsIrsaCredentialGenerator implements
CredentialGenerator<AwsIrsaCr
throw new IllegalStateException(
"No role ARN available. Either configure s3-role-arn or ensure
AWS_ROLE_ARN environment variable is set.");
}
- if (!effectiveRoleArn.startsWith("arn:aws")) {
+ if (!isSupportedRoleArn(effectiveRoleArn)) {
throw new IllegalArgumentException("Invalid role ARN format: " +
effectiveRoleArn);
}
return effectiveRoleArn;
}
+ private boolean isSupportedRoleArn(String effectiveRoleArn) {
+ // Support both AWS and MinIO role ARNs. MinIO role ARNs start with
"arn:minio:" and require a
+ // custom STS endpoint.
+ return effectiveRoleArn.startsWith("arn:aws")
+ || (StringUtils.isNotBlank(stsEndpoint) &&
effectiveRoleArn.startsWith("arn:minio:"));
+ }
+
private Credentials assumeRoleWithWebIdentity(
String roleArn, String userName, String webIdentityToken,
Optional<IamPolicy> sessionPolicy) {
try (StsClient stsClient = createStsClient()) {
diff --git
a/bundles/aws/src/main/java/org/apache/gravitino/s3/credential/webidentity/WebIdentityTokenSources.java
b/bundles/aws/src/main/java/org/apache/gravitino/s3/credential/webidentity/WebIdentityTokenSources.java
index 80f77a0490..9280aec530 100644
---
a/bundles/aws/src/main/java/org/apache/gravitino/s3/credential/webidentity/WebIdentityTokenSources.java
+++
b/bundles/aws/src/main/java/org/apache/gravitino/s3/credential/webidentity/WebIdentityTokenSources.java
@@ -49,8 +49,9 @@ public final class WebIdentityTokenSources {
static WebIdentityTokenSource create(
Map<String, String> properties, Iterable<WebIdentityTokenSource>
candidates) {
String type =
- properties.getOrDefault(
- WebIdentityTokenSourceConfig.SOURCE,
WebIdentityTokenSourceConfig.DEFAULT_SOURCE);
+ StringUtils.defaultIfBlank(
+ properties.get(WebIdentityTokenSourceConfig.SOURCE),
+ WebIdentityTokenSourceConfig.DEFAULT_SOURCE);
List<String> available = new ArrayList<>();
List<WebIdentityTokenSource> matched = new ArrayList<>();
diff --git
a/bundles/aws/src/test/java/org/apache/gravitino/s3/credential/TestAwsIrsaCredentialGenerator.java
b/bundles/aws/src/test/java/org/apache/gravitino/s3/credential/TestAwsIrsaCredentialGenerator.java
index dbe75f2d42..f8c48b5c0d 100644
---
a/bundles/aws/src/test/java/org/apache/gravitino/s3/credential/TestAwsIrsaCredentialGenerator.java
+++
b/bundles/aws/src/test/java/org/apache/gravitino/s3/credential/TestAwsIrsaCredentialGenerator.java
@@ -20,6 +20,7 @@ package org.apache.gravitino.s3.credential;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.sun.net.httpserver.HttpExchange;
@@ -31,11 +32,13 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.gravitino.credential.AwsIrsaCredential;
+import org.apache.gravitino.credential.PathBasedCredentialContext;
import
org.apache.gravitino.s3.credential.webidentity.WebIdentityTokenSourceConfig;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@@ -93,6 +96,40 @@ class TestAwsIrsaCredentialGenerator {
assertEquals(1, requestCount.get());
}
+ @Test
+ void minioRoleArnAcceptedWhenCustomStsEndpointConfigured(@TempDir Path dir)
throws IOException {
+ Map<String, String> properties = createProperties(dir);
+ properties.put("s3-role-arn", "arn:minio:iam:::role/test-role");
+
+ try (AwsIrsaCredentialGenerator generator = new
AwsIrsaCredentialGenerator()) {
+ generator.initialize(properties);
+
+ AwsIrsaCredential credential = generator.generate(() -> "test-user");
+
+ assertEquals("access-key", credential.accessKeyId());
+ assertEquals("secret-key", credential.secretAccessKey());
+ assertEquals("session-token", credential.sessionToken());
+ }
+ }
+
+ @Test
+ void minioRoleArnRejectedWhenStsEndpointMissing(@TempDir Path dir) throws
IOException {
+ Map<String, String> properties = createProperties(dir);
+ properties.put("s3-role-arn", "arn:minio:iam:::role/test-role");
+ // Without a custom STS endpoint a MinIO role ARN is not a valid target.
+ properties.remove("s3-token-service-endpoint");
+
+ try (AwsIrsaCredentialGenerator generator = new
AwsIrsaCredentialGenerator()) {
+ generator.initialize(properties);
+
+ PathBasedCredentialContext context =
+ new PathBasedCredentialContext(
+ "test-user", Collections.emptySet(),
Collections.singleton("s3://bucket/object"));
+
+ assertThrows(IllegalArgumentException.class, () ->
generator.generate(context));
+ }
+ }
+
private Map<String, String> createProperties(Path dir) throws IOException {
Path tokenFile = dir.resolve("token");
Files.write(tokenFile,
"configured-token".getBytes(StandardCharsets.UTF_8));
diff --git
a/bundles/aws/src/test/java/org/apache/gravitino/s3/credential/webidentity/TestWebIdentityTokenSources.java
b/bundles/aws/src/test/java/org/apache/gravitino/s3/credential/webidentity/TestWebIdentityTokenSources.java
index 56b960894a..f339366ba9 100644
---
a/bundles/aws/src/test/java/org/apache/gravitino/s3/credential/webidentity/TestWebIdentityTokenSources.java
+++
b/bundles/aws/src/test/java/org/apache/gravitino/s3/credential/webidentity/TestWebIdentityTokenSources.java
@@ -85,17 +85,18 @@ class TestWebIdentityTokenSources {
}
@Test
- void blankSourcePropertyIsRejected(@TempDir Path dir) throws IOException {
+ void blankSourcePropertyFallsBackToDefault(@TempDir Path dir) throws
IOException {
Path tokenFile = dir.resolve("token");
Files.write(tokenFile, "tok".getBytes(StandardCharsets.UTF_8));
- // The default applies only when the key is absent; an explicitly blank
value
- // is treated as an unknown source rather than silently falling back.
+ // A blank (or whitespace-only) value is treated the same as an absent key
and
+ // falls back to the default source rather than being rejected as unknown.
Map<String, String> props = new HashMap<>();
- props.put(WebIdentityTokenSourceConfig.SOURCE, "");
+ props.put(WebIdentityTokenSourceConfig.SOURCE, " ");
props.put(WebIdentityTokenSourceConfig.FILE_PATH, tokenFile.toString());
- assertThrows(IllegalArgumentException.class, () ->
WebIdentityTokenSources.create(props));
+ WebIdentityTokenSource source = WebIdentityTokenSources.create(props);
+ assertInstanceOf(FileWebIdentityTokenSource.class, source);
}
@Test
diff --git a/docs/security/credential-vending.md
b/docs/security/credential-vending.md
index 1df065d12e..c4969cd262 100644
--- a/docs/security/credential-vending.md
+++ b/docs/security/credential-vending.md
@@ -14,14 +14,14 @@ Gravitino credential vending is used to generate temporary
or static credentials
- Supports Gravitino Iceberg REST server.
- Supports Gravitino server with the following catalog types:
- | Catalog type | Supported credential types
| Since version |
-
|-----------------|-----------------------------------------------------------------|------------------|
- | Hadoop (Fileset)| S3, OSS, GCS, ADLS
| 0.7.0-incubating |
- | Hive | S3, OSS, GCS, ADLS
| 1.3.0 |
- | Iceberg | S3, OSS, GCS, ADLS
| 1.3.0 |
- | Glue | S3
| 1.3.0 |
- | JDBC | JDBC user/password (`jdbc-user-password`)
| 1.3.0 |
- | Paimon | S3, OSS, JDBC user/password (`jdbc-user-password`)
| 1.3.0 |
+ | Catalog type | Supported credential types |
Since version |
+
|-----------------|----------------------------------------------------|------------------|
+ | Hadoop (Fileset)| S3, OSS, GCS, ADLS |
0.7.0-incubating |
+ | Hive | S3, OSS, GCS, ADLS |
1.3.0 |
+ | Iceberg | S3, OSS, GCS, ADLS |
1.3.0 |
+ | Glue | S3 |
1.3.0 |
+ | JDBC | JDBC user/password (`jdbc-user-password`) |
1.3.0 |
+ | Paimon | S3, OSS, JDBC user/password (`jdbc-user-password`) |
1.3.0 |
- Supports pluggable credentials with build-in credentials:
- S3: `S3TokenCredential`, `S3SecretKeyCredential`, `AwsIrsaCredential`
- GCS: `GCSTokenCredential`