Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AWSCredentialsProviderChain should return Exceptions from providers, not just the combined message #3160

Open
1 of 2 tasks
ivankhoosty opened this issue Nov 7, 2024 · 8 comments
Labels
feature-request A feature should be added or improved.

Comments

@ivankhoosty
Copy link

Upcoming End-of-Support

  • I acknowledge the upcoming end-of-support for AWS SDK for Java v1 was announced, and migration to AWS SDK for Java v2 is recommended.

Describe the bug

If an error occurs when fetching secrets from the secretsmanager during Spring startup, no logs are available as described in awspring/spring-cloud-aws#165 . The only information that is available to diagnose what went wrong with DefaultCredentialsProvider is the exception stacktrace/message generated on https://github.com/aws/aws-sdk-java/blob/df2ce8afe8f1c1ecebc110b9c451de4c904250fc/aws-java-sdk-core/src/main/java/com/amazonaws/auth/AWSCredentialsProviderChain.java#L142C38-L142C100

In my situation, ContainerCredentialsProvider provided message "Failed to load credentials from metadata service.", but the original (proxy/network/etc related) cause Exception was not visible in the logs, as

log.debug("Unable to load credentials from " + message);
doesn't actually produce any logs at this early stage.

The workaround was to replace DefaultCredentialsProvider with ContainerCredentialsProvider to see the cause Exception and fix the issue.

@maciejwalkowiak

Regression Issue

  • Select this option if this issue appears to be a regression.

Expected Behavior

I would want to see the exceptions that caused each provider to fail in the stacktrace of the

throw new SdkClientException("Unable to load AWS credentials from any provider in the chain: "

Current Behavior

only messages from the exceptions that caused each provider to fail are part of the exception generated on

throw new SdkClientException("Unable to load AWS credentials from any provider in the chain: "

Reproduction Steps

this is only reproducible if your app is fetching secrets via spring.config.import: aws-secretsmanager . Failures during this boostrap stage do not have any logs printed.

Possible Solution

Chain causes of failures of all providers and set as the cause for the exception thrown on line 142 ?

Additional Information/Context

No response

AWS Java SDK version used

2.28.28

JDK version used

21.0.1

Operating System and version

unix

@ivankhoosty ivankhoosty added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Nov 7, 2024
@debora-ito
Copy link
Member

Hi @ivankhoosty Java SDK 1.x is in Maintenance Mode, it'll only get security updates and critical bug fixes. We don't have plans to change the logging.

The workaround was to replace DefaultCredentialsProvider with ContainerCredentialsProvider to see the cause Exception and fix the issue.

This is exactly the instruction we give when troubleshooting credential issues: replace the default chain for the credential provider you expect to be used, and check the logs.

@debora-ito debora-ito added feature-request A feature should be added or improved. closing-soon This issue will close in 2 days unless further comments are made. and removed bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Nov 7, 2024
@ivankhoosty
Copy link
Author

@debora-ito I have just noticed I pasted the links to sdk 1.x by mistake, I had both open to compare the code, and 2.x classes code is the same.

@debora-ito
Copy link
Member

In 2.x if you set the log level to DEBUG you'll see the stacktraces of the individual credential provider calls in the chain:

<Logger name="software.amazon.awssdk" level="DEBUG" />

@github-actions github-actions bot removed the closing-soon This issue will close in 2 days unless further comments are made. label Nov 7, 2024
@debora-ito debora-ito added the closing-soon This issue will close in 2 days unless further comments are made. label Nov 7, 2024
@ivankhoosty
Copy link
Author

That’s not what happens because of the stage in spring boot loader. I will prepare a sample spring boot app to show you the issue

@github-actions github-actions bot removed the closing-soon This issue will close in 2 days unless further comments are made. label Nov 11, 2024
@maciejwalkowiak
Copy link

maciejwalkowiak commented Nov 11, 2024

@ivankhoosty perhaps this issue should be moved to https://github.com/awspring/spring-cloud-aws project?

@ivankhoosty
Copy link
Author

@maciejwalkowiak I dont know what you can do when Spring is not logging DeferredLog during boostrap failure.

I think AwsCredentialsProviderChain appending error messages from various credentialsProviders to use it as the SdkClientException message is not consistent, they should be chaining the actual exceptions into the cause of SdkClientException as well. @debora-ito makes a comment above "This is exactly the instruction we give when troubleshooting credential issues: replace the default chain for the credential provider you expect to be used, and check the logs." - this would not be necessary at all if exceptions from credentialsProviders were preserved and stored in SdkClientException

@debora-ito
Copy link
Member

"... replace the default chain for the credential provider you expect to be used, and check the logs" is the instruction when using Java SDK 1.x.

In Java SDK 2.x you can see the full stacktraces when you use DEBUG level logging. Maybe this is a configuration that spring-cloud-aws needs to expose? We wouldn't like to change to print those at regular level as they are pretty verbose and will be printed with every client that uses the default chain.

@ivankhoosty
Copy link
Author

@debora-ito the code in AWSCredentialsProviderChain and AwsCredentialsProviderChain resolveCredentials() methods is pretty much the same as to how it logs credentialProvider exceptions. I am not talking about changing logging level, that would make no difference to this issue.

I am interested in exceptions not being lost, so if ALL providers fail, we can still see them in the stacktrace:

public AwsCredentials resolveCredentials() {
if (reuseLastProviderEnabled && lastUsedProvider != null) {
return CredentialUtils.toCredentials(CompletableFutureUtils.joinLikeSync(lastUsedProvider.resolveIdentity()));
}

List<String> exceptionMessages = new ArrayList<>();
**List<Throwable> exceptions = new ArrayList<>();**

for (IdentityProvider<? extends AwsCredentialsIdentity> provider : credentialsProviders) {
    try {
        AwsCredentialsIdentity credentials = CompletableFutureUtils.joinLikeSync(provider.resolveIdentity());

        log.debug(() -> "Loading credentials from " + provider);

        lastUsedProvider = provider;
        return CredentialUtils.toCredentials(credentials);
    } catch (RuntimeException e) {
        // Ignore any exceptions and move onto the next provider
        String message = provider + ": " + e.getMessage();
        log.debug(() -> "Unable to load credentials from " + message, e);

        exceptionMessages.add(message);
        **exceptions.add(e);**
    }
}

SdkClientException sdkClientException = SdkClientException.builder()
    .message("Unable to load credentials from any of the providers in the chain " + this + " : " + exceptionMessages)
    .build();

//SdkClientException.builder doesn't support addSuppressed, so have to add directly to the exception
for (Throwable exception : exceptions) {
sdkClientException.addSuppressed(exception);
}

throw sdkClientException;

}

can be optimised to generate exceptionMessages from the exceptions list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request A feature should be added or improved.
Projects
None yet
Development

No branches or pull requests

3 participants