User: arn:aws:sts::{account_id}:assumed-role/* is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::{account_id}:role/*
I am creating two resources AWS Lambda function and Role using cloudformation template.
I am using role arn as Environment variable. Later using it in code for S3 connection.
But getting exception as
com.amazonaws.services.securitytoken.model.AWSSecurityTokenServiceException:
User: arn:aws:sts::{account_id}:assumed-role/* is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::{account_id}:role/*
Service: AWSSecurityTokenService; Status Code: 403; Error Code: AccessDenied; Request ID: ; Proxy: null)
How can I add same role arn in Trust Relationship and in inline policy?
How to overcome above exception?
Other solutions appreciated
CF Template snippet
Resources:
LambdaFunctionExecutionRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
# AWS:
# - {Role ARN}
Action:
- 'sts:AssumeRole'
Path: /
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
- 'arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole'
- 'arn:aws:iam::aws:policy/SecretsManagerReadWrite'
- 'arn:aws:iam::aws:policy/AmazonS3FullAccess'
- 'arn:aws:iam::aws:policy/CloudWatchLogsFullAccess'
- 'arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess'
- 'arn:aws:iam::aws:policy/service-role/AWSLambdaRole'
Policies:
- PolicyName: CustomLambdaPolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- 'ec2:Describe*'
- 'ec2:Get*'
Resource: '*'
LambdaFunction:
Type: AWS::Serverless::Function
Properties:
Description: !Ref Name
FunctionName: !Ref Name
Handler: com.fileservice::handleRequest
Role: !GetAtt LambdaFunctionExecutionRole.Arn
Timeout: 900
MemorySize: 512
Environment:
Variables:
bucketName: !Ref S3BucketName
roleARN: !GetAtt LambdaFunctionExecutionRole.Arn
CodeUri: target/fileservice-1.0.0.jar
Runtime: java11
AWS S3 Connectivity Code Snippet
public AmazonS3 connectS3(String roleArn, String region) {
STSAssumeRoleSessionCredentialsProvider stsAssumeRoleSessionCredentialsProvider = new STSAssumeRoleSessionCredentialsProvider.Builder(
roleArn, "MySession").withStsClient(AWSSecurityTokenServiceClientBuilder.standard().build())
.withRoleSessionDurationSeconds(900).build();
BasicSessionCredentials basicSessionCredentials = new BasicSessionCredentials(
stsAssumeRoleSessionCredentialsProvider.getCredentials().getAWSAccessKeyId(),
stsAssumeRoleSessionCredentialsProvider.getCredentials().getAWSSecretKey(),
stsAssumeRoleSessionCredentialsProvider.getCredentials().getSessionToken());
System.out.println("serviceEndpoint:- "+ String.format("https://s3.%s.amazonaws.com", region) );
AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(basicSessionCredentials))
.withEndpointConfiguration( new EndpointConfiguration( String.format("https://s3.%s.amazonaws.com", region), region) )
.build();
return s3Client;
}
Solution 1:
LambdaFunction:
Type: AWS::Serverless::Function
Properties:
Role: !GetAtt LambdaFunctionExecutionRole.Arn
If you are using the role property of AWS::Serverless::Function, you do not need to assume the role again in your Lambda code. Any AWS SDK or CLI will automatically retrieve credentials associated with that role.
Reference: https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html (From the documentation: You provide this role when you create a function, and Lambda assumes the role when your function is invoked.)
Ignoring the fact that you should not have reason to allow a role to assume itself, with CloudFormation, it is not possible to reference the ARN of the role inside the role definition itself. Attempting to use !GetAtt LambdaFunctionExecutionRole.Arn in the trust policy of LambdaFunctionExecutionRole would give a Circular Dependency error.
Edit for changes in code which OP has now included in the question:
Instead of:
public AmazonS3 connectS3(String roleArn, String region) {
STSAssumeRoleSessionCredentialsProvider stsAssumeRoleSessionCredentialsProvider = new STSAssumeRoleSessionCredentialsProvider.Builder(
roleArn, "MySession").withStsClient(AWSSecurityTokenServiceClientBuilder.standard().build())
.withRoleSessionDurationSeconds(900).build();
BasicSessionCredentials basicSessionCredentials = new BasicSessionCredentials(
stsAssumeRoleSessionCredentialsProvider.getCredentials().getAWSAccessKeyId(),
stsAssumeRoleSessionCredentialsProvider.getCredentials().getAWSSecretKey(),
stsAssumeRoleSessionCredentialsProvider.getCredentials().getSessionToken());
System.out.println("serviceEndpoint:- "+ String.format("https://s3.%s.amazonaws.com", region) );
AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(basicSessionCredentials))
.withEndpointConfiguration( new EndpointConfiguration( String.format("https://s3.%s.amazonaws.com", region), region) )
.build();
return s3Client;
}
Why not just do this?
public AmazonS3 connectS3(String region) {
AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withRegion(region).build();
return s3Client;
}
If your code is running in an AWS Lambda function, you don't need to do an AssumeRole action to get credentials, you can just directly use the role which is assigned to the Lambda function to access S3. The only reason for trying to assume a role would be if it is a completely separate role which has the required permissions which the role assigned to AWS Lambda function does not have.