Romstar
Romstar

Reputation: 1265

How to programmatically create IAM Roles Anywhere sessions with AWS SDK for Java V2 in a Spring Boot service

I'm working on a Spring Boot backend service where I need to access certain S3 buckets programmatically using IAM Roles Anywhere. I found the following documentation for RolesAnywhereClient in the AWS SDK for Java V2:

https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/rolesanywhere/RolesAnywhereClient.html

However, I’m unsure how to use it to create IAM Roles Anywhere sessions and authenticate to access S3.

I have all credentials needed for IAM roles anywhere: profile-arn, trust-anchor-arn, role-arn, certificate and private key. How to programmatically create IAM Roles Anywhere sessions with AWS SDK for Java V2 in a Spring Boot service to access S3 buckets?

Upvotes: 1

Views: 309

Answers (2)

Todd Hill
Todd Hill

Reputation: 61

As a quick way to create a session and get temporary creds, you can leverage the credential helper tool.

After you get all the pieces assembled locally and you get the helper tool working from the command line to return temp creds, you can add the command to the ~/.aws/config file:

[profile roles_anywhere]
    credential_process = ./aws_signing_helper credential-process --certificate /path/to/certificate --private-key /path/to/private-key --trust-anchor-arn arn:aws:rolesanywhere:region:account:trust-anchor/TA_ID --profile-arn arn:aws:rolesanywhere:region:account:profile/PROFILE_ID --role-arn arn:aws:iam::account:role/role-name-with-path

Then in Java:

ProfileCredentialsProvider profileCredentialsProvider =  
            ProfileCredentialsProvider.builder()
                    .profileName("roles_anywhere")
                    .build();
 s3Client = S3Client.builder()
                  .credentialsProvider(profileCredentialsProvider)
                  .build();

Or use a ProcessCredentialsProvider if you want to do it all in code:

                ProcessCredentialsProvider processCredentialsProvider = ProcessCredentialsProvider.builder()
                    .command("""
                            ./aws_signing_helper credential-process \
                            --certificate /path/to/certificate \
                            --private-key /path/to/private-key \
                            --trust-anchor-arn arn:aws:rolesanywhere:region:account:trust-anchor/TA_ID \
                            --profile-arn arn:aws:rolesanywhere:region:account:profile/PROFILE_ID \
                            --role-arn arn:aws:iam::account:role/role-name-with-path
                        """).build();


                s3Client = S3Client.builder()//.create();
                  .credentialsProvider(processCredentialsProvider)
                  .build();

Upvotes: 1

kakabali
kakabali

Reputation: 4033

I had exact requirements for JAVA + Spring Boot!

⚠️ one may do some tweaks to make it non spring boot based ⚠️

I had created a blog relating to the almost same problem/ integration. Link here

The example code is on Github here

Main part is that I created a new Credential Provider that extends the AWS SDKs credential provider, that internally binds to a RestClient which calls the roles anywhere /sessions endpoint

🎉 Bonus Part 🎉 The code refreshes the AWS credentials just before expiry of the previous set of credentials. This action is configurable based on a simple boolean flag.

This approach, does not requires to create a customization around the build package to mandate the inclusion the aws signing helper

Additionally, with some tweaks this can be made reusable for non Spring based projects too.

Happy to assist further

Example configuration:-

@Configuration
public class AwsConfig {

    @Bean
    public AwsCredentialsProvider awsCredentialsProvider(final AwsRolesAnywhereProperties awsRolesAnywhereProperties,
                                                         final ObjectMapper objectMapper) {
        var rolesAnywhereCredentialsProvider = new IAMRolesAnywhereSessionsCredentialsProvider
                .Builder(awsRolesAnywhereProperties, objectMapper)
                .asyncCredentialUpdateEnabled(true)
                .build();
        return rolesAnywhereCredentialsProvider;
    }

    @Bean
    public AwsCredentialsProvider awsCredentialsProviderV2(final AwsRolesAnywhereProperties awsRolesAnywhereProperties,
                                                           final ObjectMapper objectMapper) {
        var rolesAnywhereCredentialsProvider = new IAMRolesAnywhereSessionsCredentialsProvider
                .Builder(objectMapper)
                .roleArn(awsRolesAnywhereProperties.getRoleArn())
                .profileArn(awsRolesAnywhereProperties.getProfileArn())
                .trustAnchorArn(awsRolesAnywhereProperties.getTrustAnchorArn())
                .encodedPrivateKey(awsRolesAnywhereProperties.getEncodedPrivateKey())
                .encodedX509Certificate(awsRolesAnywhereProperties.getEncodedX509Certificate())
                .durationSeconds(awsRolesAnywhereProperties.getDurationSeconds())
                .region(awsRolesAnywhereProperties.getRegion())
                .asyncCredentialUpdateEnabled(true)
                .prefetch(true)
                .build();
        return rolesAnywhereCredentialsProvider;
    }

    // pass the credentials provider as anyone would generally do
    @Bean
    S3Client s3Client(final AwsCredentialsProvider awsCredentialsProvider,
                      final AwsRolesAnywhereProperties awsRolesAnywhereProperties) {
        return S3Client.builder().credentialsProvider(awsCredentialsProvider).region(Region.of(awsRolesAnywhereProperties.getRegion())).build();
    }

}

Example application properties, strictly coupled with AwsRolesAnywhereProperties

# AWS account id
aws.account.id=111111111111
# AWS region for the aws roles anywhere, actual AWS resource client may use a different region
aws.roles.anywhere.region=us-east-1
# AWS IAM roles anywhere trusted role
aws.roles.anywhere.role-arn=arn:aws:iam::${aws.account.id}:role/ROLES_ANYWHERE_S3_READ_ONLY
# AWS IAM roles anywhere profile
aws.roles.anywhere.profile-arn=arn:aws:rolesanywhere:us-east-1:${aws.account.id}:profile/a-random-long-id
# AWS IAM roles anywhere trust anchor
aws.roles.anywhere.trust-anchor-arn=arn:aws:rolesanywhere:us-east-1:${aws.account.id}:trust-anchor/a-random-long-id
# AWS IAM roles anywhere session duration
aws.roles.anywhere.duration-seconds=900
# AWS IAM roles anywhere access related private key, in pem format, base 64 encoded
aws.roles.anywhere.encoded-private-key=removed for security and brevity
# AWS IAM roles anywhere access related X509 Cert, in pem format, base 64 encoded
aws.roles.anywhere.encoded-x509-certificate=removed for security and brevity

Upvotes: 1

Related Questions