AWS S3 with Spring Boot error "profile file cannot be null"

Viewed 3254

I have IAM role and client region. How to grant permission to access S3 in my Spring boot app which is not present inside EC2 instance?

@Configuration
public class AWSConfiguration {

    String clientRegion = "...";
    String roleARN = "...";

    @Bean
    public AmazonS3 amazonS3Client() {

        try {
            AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.standard()
                    .withCredentials(new ProfileCredentialsProvider()).withRegion(clientRegion).build();

            AssumeRoleRequest roleRequest = new AssumeRoleRequest().withRoleArn(roleARN);
            AssumeRoleResult roleResponse = stsClient.assumeRole(roleRequest);
            Credentials sessionCredentials = roleResponse.getCredentials();

            BasicAWSCredentials basicAwsCred = new BasicAWSCredentials(sessionCredentials.getAccessKeyId(), sessionCredentials.getSecretAccessKey());

            return AmazonS3ClientBuilder.standard()
                    .withCredentials(new AWSStaticCredentialsProvider(basicAwsCred)).withRegion(clientRegion).build();

        } catch (AmazonServiceException e) {
            e.printStackTrace();
        } catch (SdkClientException e) {
            e.printStackTrace();
        }
        return null;
    }
}

I am getting the following error

Caused by: java.lang.IllegalArgumentException: profile file cannot be null
    at com.amazonaws.util.ValidationUtils.assertNotNull(ValidationUtils.java:37) ~[aws-java-sdk-core-1.11.946.jar:na]
    at com.amazonaws.auth.profile.ProfilesConfigFile.<init>(ProfilesConfigFile.java:142) ~[aws-java-sdk-core-1.11.946.jar:na]
    at com.amazonaws.auth.profile.ProfilesConfigFile.<init>(ProfilesConfigFile.java:133) ~[aws-java-sdk-core-1.11.946.jar:na]
    at com.amazonaws.auth.profile.ProfilesConfigFile.<init>(ProfilesConfigFile.java:100) ~[aws-java-sdk-core-1.11.946.jar:na]
    at com.amazonaws.auth.profile.ProfileCredentialsProvider.getCredentials(ProfileCredentialsProvider.java:135) ~[aws-java-sdk-core-1.11.946.jar:na]
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.getCredentialsFromContext(AmazonHttpClient.java:1257) ~[aws-java-sdk-core-1.11.946.jar:na]
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.runBeforeRequestHandlers(AmazonHttpClient.java:833) ~[aws-java-sdk-core-1.11.946.jar:na]
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:783) ~[aws-java-sdk-core-1.11.946.jar:na]

I tried to change ProfileCredentialsProvider to DefaultAWSCredentialsProviderChain.getInstance() but it is still giving me same error and also asking me for role session name.

2 Answers

You need to provide your credentials using env variables, java system properties, etc. SDK to be able to assume a role. This is not mandatory if your code is running from EC2 instance with Instance Profile correctly configured, the role will be used automatically.

This is a 2 steps process:

  • you need to authenticate with an user which is authorized to assume the role
  • then you can retrieve session credentials for the role and use them to access S3 with role permissions

To use in EC2, you can find the documentation here.

EDIT:

A good page to learn about best pratices to access AWS using access keys: here

For applications, AWS CLI, and Tools for Windows PowerShell commands that run on the instance, you do not have to explicitly get the temporary security credentials—the AWS SDKs, AWS CLI, and Tools for Windows PowerShell automatically get the credentials from the EC2 instance metadata service and use them. To make a call outside of the instance using temporary security credentials (for example, to test IAM policies), you must provide the access key, secret key, and the session token.

You are using the older V1 Java S3 API. You should consider moving to the Java V2 API for Amazon S3.

Your issue looks like how you are setting your creds. If you are developing a Spring Boot app, you should set credentials using Environment variables. For example:

Region region = Region.US_WEST_2;
    S3Client s3 = S3Client.builder()
            .credentialsProvider(EnvironmentVariableCredentialsProvider.create())
            .region(region)
            .build();

If you want to deploy this web app to (for example, AWS Elastic Beanstalk), all you need to do is set the environment variables and your Spring Boot application that interact with Amazon S3.

To see how to successfully invoke Amazon S3 from a Spring Boot web app, see this AWS tutorial tutorial. This tutorial discusses how to build a Spring Boot app that can retrieve images from an Amazon S3 bucket (using the S3 Java V2 API) and analyze them using the Amazon Rekognition service. It also discusses how to deploy the web app to Elastic Beanstalk.

Creating an example AWS photo analyzer application using the AWS SDK for Java

Related