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

CalvinKirs pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 5c7110b978c [fix](glue) cache credentials provider in 
ConfigurationAWSCredentialsProvider (#65165)
5c7110b978c is described below

commit 5c7110b978c86def1ea60ca7e98e4734d036d414
Author: Calvin Kirs <[email protected]>
AuthorDate: Mon Jul 6 09:52:41 2026 +0800

    [fix](glue) cache credentials provider in 
ConfigurationAWSCredentialsProvider (#65165)
    
    ### What problem does this PR solve?
    
    Issue Number: close #xxx
    
    Related PR: #xxx
    
    Problem Summary:
    
    The AWS SDK signer calls `AWSCredentialsProvider.getCredentials()` for
    every Glue API request, but `ConfigurationAWSCredentialsProvider` (used
    by the Hive-Glue metastore client via
    `aws.catalog.credentials.provider.factory.class`) rebuilt the entire
    provider chain — including a fresh `InstanceProfileCredentialsProvider`
    / `STSAssumeRoleSessionCredentialsProvider` — inside every
    `getCredentials()` call. The providers' internal credential caching was
    therefore defeated, and **every single Glue request triggered a full
    IMDS round trip** (token PUT + credential GET under IMDSv2), or a full
    STS AssumeRole call in the `glue.role_arn` case.
    
    Low-rate operations survive this, but per-partition fan-out paths
    overwhelm the EC2 instance metadata service. Observed in production
    (Glue catalog without explicit credentials, base table with ~160k
    partitions): `SHOW PARTITIONS` on an MTMV whose base table is a Glue
    Hive table runs `MTMVPartitionUtil.isSyncWithPartitions`, which issues
    one `GetPartition` RPC per base-table partition; each RPC re-fetched
    credentials from IMDS, IMDS throttling then killed one of the fetches
    and the whole statement failed:
    
    ```
    MetaException: Unable to get partition with values: .../2024/01/26/...
    com.amazonaws.SdkClientException: Unable to load AWS credentials from any 
provider in the chain:
    [com.amazonaws.auth.InstanceProfileCredentialsProvider@...: Failed to 
connect to service endpoint: ,
    EnvironmentVariableCredentialsProvider: ..., 
SystemPropertiesCredentialsProvider: ...]
    ```
    
    Bulk paths (`listPartitionNames`, `SHOW DATABASES`, `table$partitions`)
    issue a single RPC and keep working, which makes the failure look
    selective and hard to diagnose.
    
    What I changed:
    
    Build the delegate provider once per
    `ConfigurationAWSCredentialsProvider` instance (double-checked locking
    on a `volatile` field) and let the SDK-native providers cache and
    auto-refresh temporary credentials as designed; `refresh()` now forwards
    to the delegate. IMDS/STS traffic drops from O(requests) to cold-start
    plus periodic refresh.
    
    Notes:
    - AK/SK branch behavior is unchanged (now wrapped in
    `AWSStaticCredentialsProvider`).
    - Config snapshot-at-first-use is safe: `ALTER CATALOG` rebuilds the
    HiveConf and the metastore client pool.
    - The SDK v2 variant `ConfigurationAWSCredentialsProvider2x` (Iceberg
    path) is static-only and not affected.
    
    ### Release note
    
    Fix: Glue Hive catalog no longer fetches AWS credentials from IMDS/STS
    on every metastore request; fixes 'Unable to load AWS credentials from
    any provider in the chain' failures on partition-heavy operations (e.g.
    SHOW PARTITIONS on an MTMV over a Glue table).
    
    ### Check List (For Author)
    
    - Test
        - [ ] Regression test
        - [ ] Unit Test
        - [ ] Integration test
        - [x] Manual test (add detailed scripts or steps below)
    - Verified on a production 26.x deployment: with the fixed jar, MTMV
    `SHOW PARTITIONS` over a Glue base table no longer floods IMDS and
    completes successfully.
        - [ ] No need to test or manual test. Explain why.
---
 .../ConfigurationAWSCredentialsProvider.java       | 45 +++++++++++++++++-----
 1 file changed, 35 insertions(+), 10 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/com/amazonaws/glue/catalog/credentials/ConfigurationAWSCredentialsProvider.java
 
b/fe/fe-core/src/main/java/com/amazonaws/glue/catalog/credentials/ConfigurationAWSCredentialsProvider.java
index 23ba972fdfe..293e6a099b0 100644
--- 
a/fe/fe-core/src/main/java/com/amazonaws/glue/catalog/credentials/ConfigurationAWSCredentialsProvider.java
+++ 
b/fe/fe-core/src/main/java/com/amazonaws/glue/catalog/credentials/ConfigurationAWSCredentialsProvider.java
@@ -20,6 +20,7 @@ package com.amazonaws.glue.catalog.credentials;
 import com.amazonaws.SdkClientException;
 import com.amazonaws.auth.AWSCredentials;
 import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.auth.AWSStaticCredentialsProvider;
 import com.amazonaws.auth.BasicAWSCredentials;
 import com.amazonaws.auth.BasicSessionCredentials;
 import com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider;
@@ -32,7 +33,13 @@ import org.apache.hadoop.conf.Configuration;
 
 public class ConfigurationAWSCredentialsProvider implements 
AWSCredentialsProvider {
 
-    private Configuration conf;
+    private final Configuration conf;
+
+    // The SDK signer invokes getCredentials() on every request, so the 
underlying provider must
+    // be built only once: providers like InstanceProfileCredentialsProvider 
and
+    // STSAssumeRoleSessionCredentialsProvider cache their temporary 
credentials per instance,
+    // and rebuilding them per call would hit IMDS/STS on every single Glue 
request.
+    private volatile AWSCredentialsProvider delegate;
 
     public ConfigurationAWSCredentialsProvider(Configuration conf) {
         this.conf = conf;
@@ -40,17 +47,34 @@ public class ConfigurationAWSCredentialsProvider implements 
AWSCredentialsProvid
 
     @Override
     public AWSCredentials getCredentials() {
+        AWSCredentialsProvider provider = delegate;
+        if (provider == null) {
+            synchronized (this) {
+                if (delegate == null) {
+                    delegate = buildDelegate();
+                }
+                provider = delegate;
+            }
+        }
+        return provider.getCredentials();
+    }
+
+    private AWSCredentialsProvider buildDelegate() {
         String accessKey = 
StringUtils.trim(conf.get(AWSGlueConfig.AWS_GLUE_ACCESS_KEY));
         String secretKey = 
StringUtils.trim(conf.get(AWSGlueConfig.AWS_GLUE_SECRET_KEY));
         String sessionToken = 
StringUtils.trim(conf.get(AWSGlueConfig.AWS_GLUE_SESSION_TOKEN));
         String roleArn = 
StringUtils.trim(conf.get(AWSGlueConfig.AWS_GLUE_ROLE_ARN));
         String externalId = 
StringUtils.trim(conf.get(AWSGlueConfig.AWS_GLUE_EXTERNAL_ID));
         if (!StringUtils.isNullOrEmpty(accessKey) && 
!StringUtils.isNullOrEmpty(secretKey)) {
-            return (StringUtils.isNullOrEmpty(sessionToken) ? new 
BasicAWSCredentials(accessKey,
-                    secretKey) : new BasicSessionCredentials(accessKey, 
secretKey, sessionToken));
+            AWSCredentials credentials = 
StringUtils.isNullOrEmpty(sessionToken)
+                    ? new BasicAWSCredentials(accessKey, secretKey)
+                    : new BasicSessionCredentials(accessKey, secretKey, 
sessionToken);
+            return new AWSStaticCredentialsProvider(credentials);
         }
-        String credentialsProviderModeString = 
StringUtils.lowerCase(conf.get(AWSGlueConfig.AWS_CREDENTIALS_PROVIDER_MODE));
-        AwsCredentialsProviderMode 
credentialsProviderMode=AwsCredentialsProviderMode.fromString(credentialsProviderModeString);
+        String credentialsProviderModeString =
+                
StringUtils.lowerCase(conf.get(AWSGlueConfig.AWS_CREDENTIALS_PROVIDER_MODE));
+        AwsCredentialsProviderMode credentialsProviderMode =
+                
AwsCredentialsProviderMode.fromString(credentialsProviderModeString);
         AWSCredentialsProvider longLivedProvider = 
AwsCredentialsProviderFactory.createV1(credentialsProviderMode);
         if (!StringUtils.isNullOrEmpty(roleArn)) {
             STSAssumeRoleSessionCredentialsProvider.Builder builder =
@@ -60,19 +84,20 @@ public class ConfigurationAWSCredentialsProvider implements 
AWSCredentialsProvid
             if (!StringUtils.isNullOrEmpty(externalId)) {
                 builder.withExternalId(externalId);
             }
-            STSAssumeRoleSessionCredentialsProvider provider = builder.build();
-            return provider.getCredentials();
+            return builder.build();
         }
         if (Config.aws_credentials_provider_version.equalsIgnoreCase("v2")) {
-            return longLivedProvider.getCredentials();
+            return longLivedProvider;
         }
         throw new SdkClientException("Unable to load AWS credentials from any 
provider in the chain");
-
     }
 
     @Override
     public void refresh() {
-
+        AWSCredentialsProvider provider = delegate;
+        if (provider != null) {
+            provider.refresh();
+        }
     }
 
     @Override


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

Reply via email to