I am trying to use the AWS Java SDK to interact with S3 and Lambda.
Because our accounts are required to use multi-factor authentication, my ~/.aws/credentials file has two profiles, [default] and [auth]. The default has an aws_access_key_id and aws_secret_access_key I generated through the IAM management console - but this profile can't be used to do much of anything. The second profile, auth, is generated by a script that uses the MFA code to create a set of credentials that will last for 12 hours. This one has an aws_security_token in addition to the aws_access_key_id and aws_secret_access_key. (Potentially of note, this aws_security_token is NOT in my IAM management console -- but the profile works fine with the AWS CLI, and my coworkers confirm that this is true for them as well.)
I have tried various permutations of creating an S3 or Lambda client:
//private static AWSLambdaClient lambda = new AWSLambdaClient();
private static AWSLambda lambda = AWSLambdaClientBuilder.standard().withCredentials(new ProfileCredentialsProvider("auth")).withRegion(Regions.US_WEST_2).build();
//private static AmazonS3 s3client = new AmazonS3Client();
private static AmazonS3 s3client = new AmazonS3Client(new ProfileCredentialsProvider("auth"));
In all cases it fails when I try to do anything with these clients. (Either s3client.listBuckets() or lambda.invoke(request).)
With the default profile, it fails in expected ways -- saying that the user doesn't have permissions for that operation.
With the "auth" profile, it fails in different ways for S3 and Lambda. S3 fails with "The AWS Access Key Id you provided does not exist in our records." Lambda fails with "The security token included in the request is invalid."
Full error messages below:
S3 with default profile:
Exception in thread "main" com.amazonaws.services.s3.model.AmazonS3Exception: Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied; Request ID: 1A8FE9A40C6CF4FC), S3 Extended Request ID: M+IaUw223nj7ClIv3oB4sp7pOw2af8VMsrhLl/18oQB0rLMRFNjf8LFyXKj+AQNanGoUVgMpPNM=
S3 with auth profile:
Exception in thread "main" com.amazonaws.services.s3.model.AmazonS3Exception: The AWS Access Key Id you provided does not exist in our records. (Service: Amazon S3; Status Code: 403; Error Code: InvalidAccessKeyId; Request ID: E388FFE85FC71492), S3 Extended Request ID: f3RU7uEXK+2tt98fQYCkHMbsa7odsnsgTIdRJvx2xbvKUmDtT2xXWZ2Eqor1I1ODqEZ0xDe3Quc=
Lambda with default profile:
Caused by: com.amazonaws.services.lambda.model.AWSLambdaException: User: arn:aws:iam::181136347741:user/bkc is not authorized to perform: lambda:InvokeFunction on resource: arn:aws:lambda:us-east-1:181136347741:function:sensor (Service: AWSLambda; Status Code: 403; Error Code: AccessDeniedException; Request ID: e4670c43-61b6-11e7-8eeb-db8360af9fe6)
Lambda with auth profile:
Caused by: com.amazonaws.services.lambda.model.AWSLambdaException: The security token included in the request is invalid. (Service: AWSLambda; Status Code: 403; Error Code: UnrecognizedClientException; Request ID: 00a397f0-61b7-11e7-beb6-df232368bb9e)
So what am I doing wrong here? Is there something wrong with the way I'm creating the ProfileCredentialsProvider and passing that to the AWS clients? Is there something wrong with my auth profile, even though it works from the CLI? (Do we need to fix something in our script that creates the auth profile perhaps?)
For reference, here's the interesting parts of the script that generates the auth profile:
def get_mfa_tokens(serial, code):
'''Generate MFA access tokens using the given device serial and MFA code.'''
sts = boto3.client('sts')
return sts.get_session_token(
SerialNumber=serial,
TokenCode=code)
def add_auth_tokens(config, tokens):
'''Modify the given config object, adding certain token fields to it.'''
#auth section will be there most of the time, so LBYL.
if not config.has_section('auth'):
config.add_section('auth')
config.set('auth', '# expires {}'.format(tokens['Credentials']['Expiration']))
config.set('auth', 'aws_access_key_id', tokens['Credentials']['AccessKeyId'])
config.set('auth', 'aws_secret_access_key', tokens['Credentials']['SecretAccessKey'])
config.set('auth', 'aws_security_token', tokens['Credentials']['SessionToken'])