aws / aws-sdk-java-v2

The official AWS SDK for Java - Version 2
Apache License 2.0
2.21k stars 854 forks source link

Profile File MFA Support #995

Open Sandmania opened 5 years ago

Sandmania commented 5 years ago

When using a role to access a different account with MFA Conditions, I would expect the SDKs ProfileCredentialsProvider to handle the token querying and using the session credentials to all subsequent calls. Something like this has already been proposed for the old SDK, see https://github.com/aws/aws-sdk-java/issues/1345.

Expected Behavior

Given ~/.aws/credentialslike

[default]
aws_access_key_id = AXXXXXXXXXXXXXX
aws_secret_access_key = 8XXXXXXXXXXXXXXXXXXXXXXXX
region = eu-west-1

[testAccountProfile]
role_arn = arn:aws:iam::111111111111:role/AnOrganizationAccountAccessRoleForTestAccount
source_profile = default
mfa_serial = arn:aws:iam::222222222222:mfa/User
region = eu-west-1

and a call like System.out.println(StsClient.create().getCallerIdentity().account())

When Running an executable jar with the aforementioned call like $ java -jar myExecutable.jar and $ AWS_PROFILE=testAccountProfile java -jar myExecutable.jar

Then For the first call, should print the account id for the default profile (222222222222) For the second call, should prompt for MFA token. Once correct code given, should print account if for testAccountProfile(111111111111)

Current Behavior

The first call works as expected. The second call does not prompt for MFA token and fails with the following exception:

Exception in thread "main" software.amazon.awssdk.core.exception.SdkClientException: Unable to load credentials from any of the providers in the chain AwsCredentialsProviderChain(credentialsProviders=[SystemPropertyCredentialsProvider(), EnvironmentVariableCredentialsProvider(), ProfileCredentialsProvider(profileName=testAccountProfile, profileFile=ProfileFile(profiles=[Profile(name=default, properties=[aws_access_key_id, region, aws_secret_access_key]), Profile(name=testAccountProfile, properties=[source_profile, role_arn, region, mfa_serial])])), 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)., ProfileCredentialsProvider(profileName=testAccountProfile, profileFile=ProfileFile(profiles=[Profile(name=default, properties=[aws_access_key_id, region, aws_secret_access_key]), Profile(name=testAccountProfile, properties=[source_profile, role_arn, region, mfa_serial])])): Access denied (Service: Sts, Status Code: 403, Request ID: bc214b4a-1276-11e9-b63d-03a743d3f549), ContainerCredentialsProvider(): Cannot fetch credentials from container - neither AWS_CONTAINER_CREDENTIALS_FULL_URI or AWS_CONTAINER_CREDENTIALS_RELATIVE_URI environment variables are set., InstanceProfileCredentialsProvider(): Unable to load credentials from service endpoint.]
    at software.amazon.awssdk.core.exception.SdkClientException$BuilderImpl.build(SdkClientException.java:97)
    at software.amazon.awssdk.auth.credentials.AwsCredentialsProviderChain.resolveCredentials(AwsCredentialsProviderChain.java:112)
    at software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider.resolveCredentials(DefaultCredentialsProvider.java:92)
    at software.amazon.awssdk.awscore.client.handler.AwsClientHandlerUtils.createExecutionContext(AwsClientHandlerUtils.java:70)
    at software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler.createExecutionContext(AwsSyncClientHandler.java:68)
    at software.amazon.awssdk.core.client.handler.BaseSyncClientHandler.execute(BaseSyncClientHandler.java:68)
    at software.amazon.awssdk.core.client.handler.SdkSyncClientHandler.execute(SdkSyncClientHandler.java:44)
    at software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler.execute(AwsSyncClientHandler.java:55)
    at software.amazon.awssdk.services.sts.DefaultStsClient.getCallerIdentity(DefaultStsClient.java:673)
    at software.amazon.awssdk.services.sts.StsClient.getCallerIdentity(StsClient.java:1216)
    at MFATest.main(MFATest.java:6)

Possible Solution

Something similar already suggested for the old SDK: https://github.com/aws/aws-sdk-java/issues/1345

Context

I'm using java sdk based command line tools to access multiple accounts. The access is role based and protected with MFA.

Your Environment

spfink commented 5 years ago

We will review how this works in the other AWS SDKs and work to add support for it.

akhon commented 5 years ago

any updates so far?

millems commented 5 years ago

Unfortunately not. We're willing to accept contributions for this feature, but it's behind quite a few other things in our backlog (see https://github.com/aws/aws-sdk-java-v2/projects/1 for what we're working on).

mjallday commented 5 years ago

wouldn't the more logical way to do this be to grab temporary credentials by using STS assume role and then adding those permissions to a profile in /.aws/credentials?

some psuedo code like

aws sts assume-role --role-arn arn:aws:iam::123456789012:role/xaccounts3access --role-session-name s3-access-example | jq .Credentials | some transform script here >> ~/.aws/credentials

and then use a temporary aws profile env after that?

i think the issue with using something like System.out.println(StsClient.create().getCallerIdentity().account()) to get the credentials assumes that you have an interactive terminal available to supply the mfa or similar.

there appears to be a couple of tools that do this already e.g. https://github.com/rik2803/aws-sts-assumerole

millems commented 3 years ago

We believe that the SSO feature fills a lot of the same gaps as this feature. It's documented here: https://docs.aws.amazon.com/sdkref/latest/guide/setting-global-sso_account_id.html

We won't close this feature, but feel free to see whether SSO works for your authentication scenario over the mfa_serial.