oscerd commented on code in PR #26674:
URL: https://github.com/apache/camel/pull/26674#discussion_r4062655426


##########
components/camel-aws/camel-aws-common/src/main/java/org/apache/camel/component/aws/common/AwsRuntimeCredentialsResolver.java:
##########
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.aws.common;
+
+import java.io.File;
+
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
+import software.amazon.awssdk.auth.credentials.AwsCredentialsProviderChain;
+import software.amazon.awssdk.auth.credentials.ContainerCredentialsProvider;
+import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
+import 
software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
+import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
+import 
software.amazon.awssdk.auth.credentials.SystemPropertyCredentialsProvider;
+
+/**
+ * Detects which AWS credentials source applies to the current runtime - JVM 
system properties, environment variables,
+ * web identity / IRSA, a shared profile, or ECS / EKS Pod Identity container 
credentials - selects the matching
+ * provider, and reports the chosen source at INFO.
+ * <p>
+ * This is an opt-in enhancement over the SDK {@link 
DefaultCredentialsProvider} whose purpose is observability. The SDK
+ * chain already resolves credentials in the same order used here, so the 
selected source never differs from the SDK;
+ * this class simply makes the resolved source visible in the logs and returns 
it as a targeted provider. When no source
+ * is recognised it returns {@code null} so the caller falls back to the SDK 
default chain (which also covers EC2
+ * instance metadata).
+ * </p>
+ * <p>
+ * The detected provider is returned as the head of a chain whose tail is the 
full {@link DefaultCredentialsProvider},
+ * so a detected-but-unusable source (for example a profile without resolvable 
credentials) still falls back to the SDK
+ * default chain rather than failing.
+ * </p>
+ *
+ * @since 4.23
+ */
+public final class AwsRuntimeCredentialsResolver {
+
+    static final String ENV_ACCESS_KEY = "AWS_ACCESS_KEY_ID";
+    static final String ENV_SECRET_KEY = "AWS_SECRET_ACCESS_KEY";
+    static final String ENV_WEB_IDENTITY_TOKEN_FILE = 
"AWS_WEB_IDENTITY_TOKEN_FILE";
+    static final String ENV_ROLE_ARN = "AWS_ROLE_ARN";
+    static final String ENV_CONTAINER_RELATIVE_URI = 
"AWS_CONTAINER_CREDENTIALS_RELATIVE_URI";
+    static final String ENV_CONTAINER_FULL_URI = 
"AWS_CONTAINER_CREDENTIALS_FULL_URI";
+    static final String ENV_PROFILE = "AWS_PROFILE";
+
+    static final String SYS_ACCESS_KEY = "aws.accessKeyId";
+    static final String SYS_SECRET_KEY = "aws.secretAccessKey";
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(AwsRuntimeCredentialsResolver.class);
+
+    private AwsRuntimeCredentialsResolver() {
+    }
+
+    /**
+     * The credentials source detected for the current runtime.
+     */
+    public enum Source {
+        SYSTEM_PROPERTY("JVM system properties 
(aws.accessKeyId/aws.secretAccessKey)"),
+        ENVIRONMENT("environment variables 
(AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY)"),
+        WEB_IDENTITY("web identity token / IRSA 
(AWS_WEB_IDENTITY_TOKEN_FILE)"),
+        PROFILE("shared profile (AWS_PROFILE or ~/.aws/credentials)"),
+        CONTAINER("container credentials (ECS task role / EKS Pod Identity)"),
+        UNKNOWN("no recognised runtime");
+
+        private final String description;
+
+        Source(String description) {
+            this.description = description;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+    }
+
+    /**
+     * Detect the current runtime and return the matching credentials 
provider, or {@code null} when no runtime can be
+     * recognised (so the caller falls back to the SDK default credentials 
provider chain).
+     *
+     * @return the resolved credentials provider, or {@code null} to use the 
SDK default chain
+     */
+    public static AwsCredentialsProvider resolve() {
+        return resolve(RuntimeEnvironment.SYSTEM);
+    }
+
+    static AwsCredentialsProvider resolve(RuntimeEnvironment environment) {
+        Source source = detect(environment);
+
+        switch (source) {
+            case UNKNOWN:
+                LOG.info("AWS credentials auto-detect: {} - using the SDK 
default credentials provider chain",
+                        source.getDescription());
+                return null;
+            case WEB_IDENTITY:
+                // Web identity (IRSA) requires software.amazon.awssdk:sts on 
the classpath to assume the role;
+                // camel-aws-common does not pull sts, so delegate to the SDK 
default provider, which performs the
+                // web-identity exchange when sts is present and degrades 
gracefully otherwise.
+                LOG.info("AWS credentials auto-detect: detected {} - 
delegating to the SDK default credentials"
+                         + " provider chain (web identity requires 
software.amazon.awssdk:sts on the classpath)",
+                        source.getDescription());
+                return DefaultCredentialsProvider.builder().build();

Review Comment:
   Thanks — I dug into this, and the env-var case can't actually occur here. 
`detect()` checks `SYSTEM_PROPERTY` and `ENVIRONMENT` **before** 
`WEB_IDENTITY`, and both require *complete* static credentials 
(`EnvironmentVariableCredentialsProvider` needs `AWS_ACCESS_KEY_ID` **and** 
`AWS_SECRET_ACCESS_KEY`):
   
   - Both env vars set → `detect()` returns `ENVIRONMENT` and logs "environment 
variables", never `WEB_IDENTITY`.
   - Only `AWS_ACCESS_KEY_ID` set (the mounted-secret example) → the env 
provider is incomplete and can't win anyway; the chain falls through to web 
identity.
   
   So `WEB_IDENTITY` is only reached when env/system-property static creds are 
absent, which means `DefaultCredentialsProvider` resolves the web-identity 
token *first* among the remaining providers — it's equivalent to a targeted 
`of(webIdentity, default)` head. I kept it as-is rather than pulling in 
`WebIdentityTokenFileCredentialsProvider` (which still needs `sts` and would 
resolve identically here), and added a comment in d3160e8 documenting this so 
it doesn't trip up the next reader.
   
   The real caveat you're pointing at is genuine though: when `sts` is absent 
the token can't be assumed and the chain degrades to profile/container/IMDS, so 
the logged "web identity" source may differ from what ultimately resolves. The 
INFO line already flags the `sts` requirement — happy to make that more 
explicit if you think it's worth it.
   
   — _Claude Code on behalf of @oscerd_



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to