Categories
Java

Using AWS Credentials with Service Client in Java Spring

AWS provides Java SDK to make requests to Amazon Web services. Using SDK we can make requests and perform the different operations of AWS services. We need to provide AWS credentials while making requests, by default SDK tries to use the default credentials configured on the host.

There are various ways to provide credentials to service clients. For Java SDK there are four ways to provide credentials to clients.

The default credential provider chain

If you have installed AWS CLI and configured default credentials with region then JAVA SDK will use credentials from AWS default configuration. Using AWS CLI you can configure the default credentials.

For more details about the credential, chain read AWS documentation here. It will try to retrieve credentials in order of chain.

In this case, you do not need to provide any credentials in the client code.

For Example

S3Client s3Client 
 = S3Client.builder().region(Region.of(awsRegion)).build();
// Or even without region, below will create with default information
S3Client s3Client = S3Client.create();

As given above you can create all clients using AWS service builder class create or build() method.

The credential provider chain has 6 providers and you can use specific one’s according to you requirements.

SystemPropertyCredentialsProvider

This is the first provider in the credential provider chain, Java SDK first tries to use this provider. In this, it checks two Java system properties  aws.accessKeyId and aws.secretKey, if your java program has these properties configured then you can use this. It will use accessId and secreteKey from Java system properties.

S3Client s3Client = S3Client.builder().region(Region.of(awsRegion))
.credentialsProvider(SystemPropertyCredentialsProvider.create()).build();

EnvironmentVariableCredentialsProvider

This is the second provider in the chain. EnvironmentVariableCredentialsProvider class loads credentials from the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY system environment variables. If AWS_SESSION_TOKEN is also specified, the SDK will use temporary credentials. You can use this as given below. This option is useful when populating credentials in the environment via the secrete store or from the build server during deployment.

S3Client s3Client = S3Client.builder().region(Region.of(awsRegion))     .credentialsProvider(EnvironmentVariableCredentialsProvider.create()).build();

WebIdentityTokenFileCredentialsProvider

A credential provider that will read web identity token file path, aws role arn, and aws session name from system properties or environment variables for using web identity token credentials with STS. Use of this credentials provider requires the ‘sts’ module to be on the classpath.

S3Client s3Client = S3Client.builder().region(Region.of(awsRegion))
.credentialsProvider(WebIdentityTokenFileCredentialsProvider.create()).build();

ProfileCredentialsProvider

This provider loads credentials from shared credentials and configs on the system. These can be configured using AWS CLI or can be created/update as location .aws/credentials and .aws/config under the user profile folder. By default, it will read properties from [default] profile or from a specified profile.

S3Client s3Client = S3Client.builder().region(Region.of(awsRegion))
.credentialsProvider(ProfileCredentialsProvider.create("s3_cred")).build();

ContainerCredentialsProvider

The URI path is retrieved from the environment variable AWS_CONTAINER_CREDENTIALS_RELATIVE_URI or AWS_CONTAINER_CREDENTIALS_FULL_URI in the container’s environment. If the environment variable is not set, this credentials provider will throw an exception.

This can be used only with ECS container services.

S3Client s3Client = S3Client.builder().region(Region.of(awsRegion))
.credentialsProvider(ContainerCredentialsProvider.builder().build()).build();

InstanceProfileCredentialsProvider

InstanceProfileCredentialsProvider class to load credentials from the Amazon EC2 metadata service. It uses credentials for EC2 IAM role.

S3Client s3Client = S3Client.builder().region(Region.of(awsRegion))
.credentialsProvider(InstanceProfileCredentialsProvider.create()).build();

StaticCredentialsProvider

We can also use StaticCredentialsProvider with AwsBasicCredentials and awsAccessKeyId, awsSecretKey as input paramets.

One can also read environment variables or AWS Secret Manager service and use these classes to provide credentials.

S3Client s3Client = S3Client.builder().region(Region.of("us-east-1"))
.credentialsProvider(StaticCredentialsProvider
.create(AwsBasicCredentials.create("awsAccessKeyId", "awsSecretKey")))
.build();

all the above providers will provide credentials with associated roles.

How to include AWS Java SDK 2 ?

AWS Java SDK 2 can be easily included using Maven or Gradle or any other build system.

All security credentials of AWS API can be found in Auth artifact. You need to include this artifact in your build system.

Maven Entry

<!-- https://mvnrepository.com/artifact/software.amazon.awssdk/auth -->
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>auth</artifactId>
    <version>2.16.68</version>
</dependency>

Gradle Enrty

// https://mvnrepository.com/artifact/software.amazon.awssdk/auth
implementation group: 'software.amazon.awssdk', name: 'auth', version: '2.16.68'

How to use AWS credential Provide in Spring?

AWS credential providers can be configured very easily into Spring project using Java config.

@Configuration
public class AwsConfig {

    @Value("${spring.aws.accessId}")
    private String awsAccessKeyId;

    @Value("${spring.aws.secretId}")
    private String awsSecretKey;

    @Value("${spring.aws.region}")
    private String awsRegion;

    private AwsBasicCredentials awsBasicCredentials() {
        return AwsBasicCredentials.create(awsAccessKeyId, awsSecretKey);
    }

    @Bean
    public StaticCredentialsProvider staticCredentialsProvider() {
        return StaticCredentialsProvider.create(awsBasicCredentials());
    }

    @Bean
    public S3Client s3Client() {
        return S3Client.builder().region(Region.of(awsRegion))
                .credentialsProvider(staticCredentialsProvider())
                .build();
    }
    @Bean
    public ProfileCredentialsProvider profileCredentialsProvider() {
        return ProfileCredentialsProvider.create("s3_cred");
    }

    @Bean
    public EnvironmentVariableCredentialsProvider environmentVariableCredentialsProvider() {
        // will create using default aws access key id and secret
        return EnvironmentVariableCredentialsProvider.create();
    }
}

In the above code, credentials were loaded from the spring application property file. You can also use the environment variables or other providers while creating beans for service clients like s3, SQS, etc.

Spring property file to read values from Environment

spring.aws.accessId = ${AWS_ACCESS_KEY_ID}
spring.aws.secretId = ${AWS_SECRET_ACCESS_KEY}
spring.aws.region = ${AWS_DEFAULT_REGION}

Junit Code to Test Aws Security Config

@SpringBootTest
class AwsConfigTest {

    @Autowired
    private StaticCredentialsProvider staticCredentialsProvider;

    @Autowired
    private ProfileCredentialsProvider profileCredentialsProvider;

    @Autowired
    private EnvironmentVariableCredentialsProvider environmentVariableCredentialsProvider;

    @Value("${spring.aws.accessId}")
    private String awsAccessKeyId;

    @Value("${spring.aws.secretId}")
    private String awsSecretKey;

    @Value("${spring.aws.region}")
    private String awsRegion;

    @Test
    void staticCredentialsProvider_ok() {
        final AwsCredentials actualCredentials =
                staticCredentialsProvider.resolveCredentials();

        assertEquals(actualCredentials.accessKeyId(), awsAccessKeyId);
        assertEquals(actualCredentials.secretAccessKey(), awsSecretKey);
    }

    @Test
    void profileCredentialsProvider_ok() {
        final AwsCredentials actualCredentials =
                profileCredentialsProvider.resolveCredentials();

        assertEquals(actualCredentials.accessKeyId(), awsAccessKeyId);
        assertEquals(actualCredentials.secretAccessKey(), awsSecretKey);
    }

    @Test
    void environmentVariableCredentialsProvider_ok() {
        final AwsCredentials actualCredentials =
                environmentVariableCredentialsProvider.resolveCredentials();
        assertEquals(actualCredentials.accessKeyId(), awsAccessKeyId);
        assertEquals(actualCredentials.secretAccessKey(), awsSecretKey);
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.