UseCase: A Lambda function in Account 1 wants to call lambda:ListFunctions in account 2.
To achive that, I create a IAM Role in Account 2, which allows Account 1 with Account ID 111111111111 to assume a certain role showfunctionsrole in Account B.
We also talk about “establishing a trust, because now B trusts A.
CrossAccountFunctionListRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: 'sts:AssumeRole'
Effect: Allow
Principal:
AWS: 'arn:aws:iam::111111111111:role/showfunctionsrole'
With the established trust in AssumeRolePolicyDocument a authenticated principle arn:aws:iam::111111111111:role/showfunctionsrole is allowed to assume the role and gets the permission described in this role.
As a security measure IAM checks whether the showfunctionsrole in Account 1 really do exist.
The file for the running app is located in infra/policy/template.yaml
:
Resources:
CrossAccountFunctionListRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: 'sts:AssumeRole'
Effect: Allow
Principal:
AWS: 'arn:aws:iam::111111111111:role/showfunctionsrole'
Version: 2012-10-17
RoleName: CrossAccountListFunctionsRole
Path: /
Policies:
- PolicyName: listlambda
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'lambda:ListFunctions'
Resource: '*'
As you see in the Policies section, you only allow the call to lambda:ListFunctions
Now in Account A the Lambda needs the permission to assume the Role named CrossAccountFunctionListRole:
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Resource": "arn:aws:iam::222222222222:role/CrossAccountListFunctionsRole",
"Sid": "AllowCrossAccountGroupList0"
},
With an initialized STS client, call AssumeRole and give the ARN of the role to be assumed as parameter.
roleArn := "arn:aws:iam::" + member + ":role/CrossAccountListFunctionsRole"
sessionname := "showfunctions"
params := &sts.AssumeRoleInput{
RoleArn: &roleArn,
RoleSessionName: &sessionname,
}
credentialsSubResponse, err := client.AssumeRole(context.TODO(), params)
The credentials will be in the response structure:
credentialsSub := *credentialsSubResponse.Credentials
You get back an AccessKeyID an SecretAccessKey and a SessionToken.
With these credentials, you create a config structure, which is valid for Account 2:
cfgSub, err := config.LoadDefaultConfig(context.TODO(),
config.WithCredentialsProvider(credentials.StaticCredentialsProvider{
Value: aws.Credentials{
AccessKeyID: *credentialsSub.AccessKeyId,
SecretAccessKey: *credentialsSub.SecretAccessKey,
SessionToken: *credentialsSub.SessionToken,
Source: "assumerole",
},
}))
client := lambda.NewFromConfig(cfgSub)
Now you may initialize the client with the credentials from the member account and use it.
In the next chapter i show you how to loop through several Accounts and regions with that.
See the full source on github.