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

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


The following commit(s) were added to refs/heads/main by this push:
     new 29ccdd179 STS roleArn: enable 3rd party STS services (#3619)
29ccdd179 is described below

commit 29ccdd179b23b470bf673e94aefd730fba2c09d0
Author: Robert Stupp <[email protected]>
AuthorDate: Tue Feb 3 11:38:04 2026 +0100

    STS roleArn: enable 3rd party STS services (#3619)
    
    Certain non-AWS STS service implementations use role ARNs that look quite 
different from AWS ones.
    This change shall enable those STS implementations.
    
    Example role ARNs that currently fail:
    * `urn:ecs:sts::s3:assumed-role/s3assumeRole/user1-105-temp`
    * `urn:sgws:identity::12345:group/foo-bar-abcdef`
    
    Related issue #2743
---
 CHANGELOG.md                                       |  2 ++
 .../aws/AwsCredentialsStorageIntegration.java      | 26 +++++++++++-----------
 .../storage/aws/AwsStorageConfigurationInfo.java   |  4 +---
 .../aws/AwsStorageConfigurationInfoTest.java       | 26 ++++++++++++++++++----
 4 files changed, 38 insertions(+), 20 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 02ffef1ed..34ef7108a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -68,6 +68,8 @@ request adding CHANGELOG notes for breaking (!) changes and 
possibly other secti
 
 ### Fixes
 
+- Enable non-AWS STS role ARNs
+
 ### Commits
 
 ## [1.3.0-incubating]
diff --git 
a/polaris-core/src/main/java/org/apache/polaris/core/storage/aws/AwsCredentialsStorageIntegration.java
 
b/polaris-core/src/main/java/org/apache/polaris/core/storage/aws/AwsCredentialsStorageIntegration.java
index 3b43c5beb..0fe618284 100644
--- 
a/polaris-core/src/main/java/org/apache/polaris/core/storage/aws/AwsCredentialsStorageIntegration.java
+++ 
b/polaris-core/src/main/java/org/apache/polaris/core/storage/aws/AwsCredentialsStorageIntegration.java
@@ -93,7 +93,6 @@ public class AwsCredentialsStorageIntegration
         realmConfig.getConfig(STORAGE_CREDENTIAL_DURATION_SECONDS);
     AwsStorageConfigurationInfo storageConfig = config();
     String region = storageConfig.getRegion();
-    String accountId = storageConfig.getAwsAccountId();
     StorageAccessConfig.Builder accessConfig = StorageAccessConfig.builder();
 
     boolean includePrincipalNameInSubscopedCredential =
@@ -120,8 +119,7 @@ public class AwsCredentialsStorageIntegration
                           allowListOperation,
                           allowedReadLocations,
                           allowedWriteLocations,
-                          region,
-                          accountId)
+                          region)
                       .toJson())
               .durationSeconds(storageCredentialDurationSeconds);
 
@@ -215,8 +213,7 @@ public class AwsCredentialsStorageIntegration
       boolean allowList,
       Set<String> readLocations,
       Set<String> writeLocations,
-      String region,
-      String accountId) {
+      String region) {
     IamPolicy.Builder policyBuilder = IamPolicy.builder();
     IamStatement.Builder allowGetObjectStatementBuilder =
         IamStatement.builder()
@@ -261,7 +258,8 @@ public class AwsCredentialsStorageIntegration
                           .addResource(key));
             });
 
-    if (!writeLocations.isEmpty()) {
+    boolean canWrite = !writeLocations.isEmpty();
+    if (canWrite) {
       IamStatement.Builder allowPutObjectStatementBuilder =
           IamStatement.builder()
               .effect(IamEffect.ALLOW)
@@ -275,13 +273,15 @@ public class AwsCredentialsStorageIntegration
                     arnPrefix + 
StorageUtil.concatFilePrefixes(parseS3Path(uri), "*", "/")));
           });
       policyBuilder.addStatement(allowPutObjectStatementBuilder.build());
-      if (shouldUseKms(storageConfigurationInfo)) {
-        addKmsKeyPolicy(currentKmsKey, allowedKmsKeys, policyBuilder, true, 
region, accountId);
-      }
-    } else {
-      if (shouldUseKms(storageConfigurationInfo)) {
-        addKmsKeyPolicy(currentKmsKey, allowedKmsKeys, policyBuilder, false, 
region, accountId);
-      }
+    }
+    if (shouldUseKms(storageConfigurationInfo)) {
+      addKmsKeyPolicy(
+          currentKmsKey,
+          allowedKmsKeys,
+          policyBuilder,
+          canWrite,
+          region,
+          storageConfigurationInfo.getAwsAccountId());
     }
     if (!bucketListStatementBuilder.isEmpty()) {
       bucketListStatementBuilder
diff --git 
a/polaris-core/src/main/java/org/apache/polaris/core/storage/aws/AwsStorageConfigurationInfo.java
 
b/polaris-core/src/main/java/org/apache/polaris/core/storage/aws/AwsStorageConfigurationInfo.java
index 067140a59..1f28b5ef3 100644
--- 
a/polaris-core/src/main/java/org/apache/polaris/core/storage/aws/AwsStorageConfigurationInfo.java
+++ 
b/polaris-core/src/main/java/org/apache/polaris/core/storage/aws/AwsStorageConfigurationInfo.java
@@ -45,9 +45,7 @@ public abstract class AwsStorageConfigurationInfo extends 
PolarisStorageConfigur
     return ImmutableAwsStorageConfigurationInfo.builder();
   }
 
-  // Technically, it should be 
^arn:(aws|aws-cn|aws-us-gov):iam::(\d{12}):role/.+$, but we've
-  // generalized it to support non-aws S3 implementations
-  @JsonIgnore public static final String ROLE_ARN_PATTERN = 
"^.+:(.*):iam:.*:(.*):role/.+$";
+  @JsonIgnore public static final String ROLE_ARN_PATTERN = 
"^.+:(.*):.+:.*:(.*):.+$";
 
   private static final Pattern ROLE_ARN_PATTERN_COMPILED = 
Pattern.compile(ROLE_ARN_PATTERN);
 
diff --git 
a/polaris-core/src/test/java/org/apache/polaris/core/storage/aws/AwsStorageConfigurationInfoTest.java
 
b/polaris-core/src/test/java/org/apache/polaris/core/storage/aws/AwsStorageConfigurationInfoTest.java
index f3fb3b348..4ea5eda6d 100644
--- 
a/polaris-core/src/test/java/org/apache/polaris/core/storage/aws/AwsStorageConfigurationInfoTest.java
+++ 
b/polaris-core/src/test/java/org/apache/polaris/core/storage/aws/AwsStorageConfigurationInfoTest.java
@@ -22,8 +22,12 @@ package org.apache.polaris.core.storage.aws;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.net.URI;
+import java.util.stream.Stream;
 import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 
 public class AwsStorageConfigurationInfoTest {
 
@@ -134,12 +138,14 @@ public class AwsStorageConfigurationInfoTest {
     
assertThat(newBuilder().kmsUnavailable(true).build().getKmsUnavailable()).isTrue();
   }
 
-  @Test
-  public void testRoleArnParsing() {
+  @ParameterizedTest
+  @MethodSource
+  public void testRoleArnParsing(
+      String roleArn, String expectedAccountId, String expectedPartition) {
     AwsStorageConfigurationInfo awsConfig =
         AwsStorageConfigurationInfo.builder()
             .addAllowedLocation("s3://bucket/path/to/warehouse")
-            .roleARN("arn:aws:iam::012345678901:role/jdoe")
+            .roleARN(roleArn)
             .region("us-east-2")
             .build();
 
@@ -148,6 +154,18 @@ public class AwsStorageConfigurationInfoTest {
             AwsStorageConfigurationInfo::getRoleARN,
             AwsStorageConfigurationInfo::getAwsAccountId,
             AwsStorageConfigurationInfo::getAwsPartition)
-        .containsExactly("arn:aws:iam::012345678901:role/jdoe", 
"012345678901", "aws");
+        .containsExactly(roleArn, expectedAccountId, expectedPartition);
+  }
+
+  static Stream<Arguments> testRoleArnParsing() {
+    return Stream.of(
+        Arguments.of("arn:aws:iam::012345678901:role/jdoe", "012345678901", 
"aws"),
+        Arguments.of("arn:aws-us-gov:iam::012345678901:role/jdoe", 
"012345678901", "aws-us-gov"),
+        Arguments.of("arn:aws-cn:iam::012345678901:role/jdoe", "012345678901", 
"aws-cn"),
+        // Following are only there to have test coverage for non-AWS 
role-ARNs/URNs. ARN specific
+        // parts are irrelevant for those URNs.
+        Arguments.of(
+            "urn:ecs:sts::namespace:assumed-role/s3assumeRole/user1-105-temp", 
"namespace", "ecs"),
+        Arguments.of("urn:sgws:identity::12345:group/foo-bar-abcdef", "12345", 
"sgws"));
   }
 }

Reply via email to