1

I inserted my AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in ~/.aws/credentials and they seem to work. However, my java application (running on that EC2 instance and using AWS Java v2 SDK) is unable to see them. I got this exception while uploading a file to S3 using java code.

Unable to load credentials from any of the providers in the chain AwsCredentialsProviderChain(credentialsProviders=[SystemPropertyCredentialsProvider(), EnvironmentVariableCredentialsProvider(), WebIdentityTokenCredentialsProvider(), ProfileCredentialsProvider(), ContainerCredentialsProvider(), InstanceProfileCredentialsProvider()]) : [SystemPropertyCredentialsProvider(): Unable to load credentials from system settings. Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId)., EnvironmentVariableCredentialsProvider(): Unable to load credentials from system settings. Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId)., WebIdentityTokenCredentialsProvider(): Either the environment variable AWS_WEB_IDENTITY_TOKEN_FILE or the javaproperty aws.webIdentityTokenFile must be set., ProfileCredentialsProvider(): Profile file contained no credentials for profile 'default': ProfileFile(profiles=[]), ContainerCredentialsProvider(): Cannot fetch credentials from container - neither AWS_CONTAINER_CREDENTIALS_FULL_URI or AWS_CONTAINER_CREDENTIALS_RELATIVE_URI environment variables are set., InstanceProfileCredentialsProvider(): The requested metadata is not found at http://169.254.169.254/latest/meta-data/iam/security-credentials/]

FYI, uploading the file using aws cli works fine while running this command in my ec2 instance: aws s3 cp foo.txt s3://mybucket-name

FYI, the same application runs correctly when I run it on my local machine with an STS client as a credential provider

According to AWS documentation,

Using the Default Credential Provider Chain When you initialize a new service client without supplying any arguments, the AWS SDK for Java attempts to find AWS credentials by using the default credential provider chain implemented by the DefaultAWSCredentialsProviderChain class. The default credential provider chain looks for credentials in this order:

  1. Environment variables-AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

  2. Java system properties-aws.accessKeyId and aws.secretKey.

  3. Web Identity Token credentials from the environment or container.

  4. The default credential profiles file- typically located at ~/.aws/credentials (location can vary per platform), and shared by many of the AWS SDKs and by the AWS CLI.

  5. Amazon ECS container credentials- loaded from the Amazon ECS if the environment variable AWS_CONTAINER_CREDENTIALS_RELATIVE_URI is set.

  6. Instance profile credentials- used on EC2 instances, and delivered through the Amazon EC2 metadata service.

If I understand correctly, the default credential provider chain will do everything for me and no credential provider needs to be mentioned. Is that correct?

Pryda
  • 899
  • 5
  • 14
  • 37
  • 1
    At a guess, your Java app is not running as the same effective user that you used when storing the `~/.aws/credentials` profile or you didn't save the creds as the default profile. That aside, don't supply creds to your app using IAM User credentials (regardless of whether you use credentials profile or environment variables). That's not a security best practice. Use IAM Roles. – jarmod Apr 19 '22 at 13:10
  • I didn't get the first point (the java app is not running as the same user I used when storing the credentials profile). Regarding the second point, I checked and I'm using the creds as the default profile – Pryda Apr 19 '22 at 14:33
  • You referenced the old v1 docs (v2 credentials doc is [here](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/credentials.html)) but yes, you should be able to leverage the default provider chain. – jarmod Apr 19 '22 at 14:54
  • 1
    On the "same user" comment, each user on the system has a different home directory. If you were logged in as ec2-user (or ubuntu) when saving `~/.aws/credentials` but then you ran your Java app under the user context of tomcat or apache or root then they would have a different home directory and it would *not* contain the credentials files, hence no profile would be read. This matches your symptoms (but something else could also be the cause). – jarmod Apr 19 '22 at 14:56

2 Answers2

2

Instead of using a Credential file under .aws, try setting EC2 environment variables. This is a valid cred provider and is described as Environment variables provider in the AWS SDK for Java V2 DEV Guide.

To use this provider with a AWS Java v2 Service client, you use:

Region region = Region.US_EAST_1;
     RdsDataClient dataClient = RdsDataClient.builder()
               .credentialsProvider(EnvironmentVariableCredentialsProvider.create())
                .region(region)
                .build(); 

This solution works nicely.

smac2020
  • 9,637
  • 4
  • 24
  • 38
  • I tried using env variables and I encountered the same error. That being said, I didn't mention the credentialProvider in my java code: '.credentialsProvider(EnvironmentVariableCredentialsProvider.create())'. Is it mandatory? According to https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/DefaultCredentialsProvider.html, AWS credentials provider chain looks for credentials in order. So I supposed that it will be handled automatically by the SDK. Am I wrong for doing this? – Pryda Apr 19 '22 at 13:02
  • 1
    If you want to use the Environment variables provider, use the syntax shown in my example – smac2020 Apr 19 '22 at 13:03
  • I updated my question with AWS documentation explaining why mentioning the credentials provider is not mandatory since the Default credential provider chain will get them automatically – Pryda Apr 19 '22 at 14:30
2

Don't use IAM User credentials on EC2 unless you absolutely have to. Instead, launch the EC2 instance with an appropriate IAM Role (or edit the instance later to apply an IAM Role).

The SDK will then automatically retrieve credentials and they will be auto-rotated for you (unlike IAM User credentials, which are fixed and hence your exposure is greater). You don't need to indicate which credentials provider to use. The SDK does this for you.

And, it should go without saying, always give the IAM Role the minimum set of permissions that it actually needs.

If you feel that you must use IAM User credentials, then these can be stored in the ~/.aws/credentials file but be sure that this is located under the HOME folder of the same OS user that your application will run as, otherwise the AWS SDK loaded by your app will not retrieve the credentials.

jarmod
  • 71,565
  • 16
  • 115
  • 122
  • is this correct way to use via IAM role `new DefaultAWSCredentialsProviderChain().getCredentials()` – littleAlien Jul 04 '23 at 18:53
  • @user_x you can do that afaik but the SDK will retrieve credentials for you from the default provider chain, so you don't typically need to do it explicitly. – jarmod Jul 04 '23 at 20:14