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

yuqi1129 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 2de6492d6f [MINOR] fix(aws): Support MinIO role ARNs in IRSA 
credential vending (#11883)
2de6492d6f is described below

commit 2de6492d6f995c9e329c7f53ccc26169e5cd1612
Author: Qi Yu <[email protected]>
AuthorDate: Thu Jul 2 22:00:35 2026 +0800

    [MINOR] fix(aws): Support MinIO role ARNs in IRSA credential vending 
(#11883)
    
    ### What changes were proposed in this pull request?
    
    - Accept `arn:minio:` role ARNs in `AwsIrsaCredentialGenerator` when a
    custom STS endpoint is configured (in addition to `arn:aws` ARNs).
    - Fall back to the default web identity token source when the `SOURCE`
    property is present but blank.
    - Fix table formatting in `docs/security/credential-vending.md`.
    
    ### Why are the changes needed?
    
    IRSA credential vending previously rejected MinIO-style role ARNs,
    preventing its use against MinIO STS endpoints. A blank source property
    should behave the same as an unset one.
    
    ### Does this PR introduce any user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    Existing unit tests.
---
 .../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`

Reply via email to