How to do Cross Account Access

Overview

UseCase: A Lambda function in Account 1 wants to call lambda:ListFunctions in account 2.

Cross Account

Create a Role in Sub Account (right)

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

Create a Role in Main Account (left)

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"
},

Assume a Cross Account Role with GO

1 - Call AssumeRole

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.

2 - Create config

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",
        },
    }))

3 - Initialize client

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 also

Source

See the full source on github.

Sources