gnodet-bot commented on code in PR #26674: URL: https://github.com/apache/camel/pull/26674#discussion_r4062596801
########## 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: ⚠️ **WEB_IDENTITY branch returns the full SDK chain — env var credentials silently win over IRSA** When `AWS_WEB_IDENTITY_TOKEN_FILE` + `AWS_ROLE_ARN` are detected, the code returns `DefaultCredentialsProvider.builder().build()`. That chain tries system properties first, then env vars, then web identity. On a pod that has IRSA configured but *also* has `AWS_ACCESS_KEY_ID` set (e.g. from a mounted secret for a different purpose), the env var credentials will silently win over the IRSA token — the opposite of the detection intent. The user enabled auto-detect, saw `"web identity token / IRSA detected"` in the logs, but is actually using different credentials. For all other detected sources the code returns a chain whose *head* is the targeted provider (`AwsCredentialsProviderChain.of(providerFor(source), DefaultCredentialsProvider.builder().build())`). For consistency, `WEB_IDENTITY` should do the same once `sts` is available — or at minimum document this caveat explicitly and note that the env var case is not an issue because IRSA and raw env var credentials are mutually exclusive in practice (though not enforced). The simplest fix that stays within the current no-`sts`-dependency constraint: ```suggestion 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. // Note: DefaultCredentialsProvider tries env vars before web identity; if AWS_ACCESS_KEY_ID is also // set in the environment the env var credentials will win over the IRSA token. 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(); ``` -- 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]
