Skip to content

Instantly share code, notes, and snippets.

@helephant
Last active October 24, 2023 03:52
Show Gist options
  • Star 35 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save helephant/57d10c022f22e8209118b459a5afb60d to your computer and use it in GitHub Desktop.
Save helephant/57d10c022f22e8209118b459a5afb60d to your computer and use it in GitHub Desktop.
Calling a lambda in another AWS account by assuming a cross-account IAM role

Set up a cross-account IAM role in the destination account

  • Add a new IAM role
  • For type of trusted entity select "another AWS account"
  • Specify the accountId of the account that will be using the resource in the destination account. You can find your AWS Account ID, which is available on the support homepage when you are logged in.
  • Create a policy that allows lambda:InvokeFunction for your function and attach it to this new role.

Create a lambda in the calling account.

  • Set up a role for your lambda that is allowed to assumeRole
  • Use the AWS SDK to assume the new role in the destination account.
  • Pass the credentials to the lambda object when you create it
  • Invoke the lambda
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn-for-lambda-that-is-calling-cross-account"
}
}
exports.handler = async (event) => {
var aws = require('aws-sdk');
var sts = new aws.STS({ region: process.env.REGION });
var stsParams = {
RoleArn: "arn-of-role-in-other-account",
DurationSeconds: 3600,
RoleSessionName: "Any string"
};
const stsResults = await sts.assumeRole(stsParams).promise();
console.log(stsResults);
var lambda = new aws.Lambda({
region: process.env.REGION,
accessKeyId: stsResults.Credentials.AccessKeyId,
secretAccessKey:stsResults.Credentials.SecretAccessKey,
sessionToken: stsResults.Credentials.SessionToken
});
const result = await lambda.invoke({
FunctionName: 'arn-of-function-in-other-account',
InvocationType: 'RequestResponse',
Payload: "{}" // pass params
}).promise();
console.log("The result was: " + JSON.stringify(result));
const response = {
statusCode: 200,
body: result.Payload
};
return response;
};
AWSTemplateFormatVersion: 2010-09-09
# just hard-coding these because it's a demo
Parameters:
CallingAccountId:
Type: String
Default: 'calling-account-id'
Resources:
DestinationLambda:
Type: AWS::Lambda::Function
Properties:
Handler: index.handler
Role: !Join ["", ['arn:aws:iam::', !Ref 'AWS::AccountId', ':role/service-role/execute-lambda']]
Code:
ZipFile: !Sub |
var response = require('cfn-response');
exports.handler = function(event, context) {
const response = {
statusCode: 200,
body: "{ 'message': 'greetings from another account' }",
};
return response;
};
Runtime: nodejs8.10
DestinationIAMRole:
Type: AWS::IAM::Role
Properties:
RoleName: "destination-lambda-iam-role"
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Sid: ''
Effect: Allow
Principal:
AWS: !Sub "arn:aws:iam::${CallingAccountId}:root"
Action: 'sts:AssumeRole'
Policies:
-
PolicyName: "run-destination-lambda"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action: "lambda:InvokeFunction"
Resource: !GetAtt DestinationLambda.Arn
AWSTemplateFormatVersion: 2010-09-09
# just hard-coding these because it's a demo
Parameters:
DestinationRoleArn:
Type: String
Default: 'your-destination-role-arn'
DestinationLambdaArn:
Type: String
Default: 'your-destination-lambda-arn'
# to call from the aws cli: aws lambda invoke --function-name 'arn-of-source-lambda' out.txt
Resources:
SourceLambda:
Type: AWS::Lambda::Function
Properties:
Handler: index.handler
Role: !GetAtt SourceIAMRole.Arn
Code:
ZipFile: !Sub |
exports.handler = async (event) => {
var aws = require('aws-sdk');
var sts = new aws.STS({ region: process.env.REGION });
var stsParams = {
RoleArn: "${DestinationRoleArn}",
DurationSeconds: 3600,
RoleSessionName: "cross-account-lambda-session" // any string
};
const stsResults = await sts.assumeRole(stsParams).promise();
var lambda = new aws.Lambda({
region: process.env.REGION,
accessKeyId: stsResults.Credentials.AccessKeyId,
secretAccessKey:stsResults.Credentials.SecretAccessKey,
sessionToken: stsResults.Credentials.SessionToken
});
const result = await lambda.invoke({
FunctionName: '${DestinationLambdaArn}',
InvocationType: 'RequestResponse',
Payload: "{}" // pass params
}).promise();
const response = {
statusCode: 200,
body: JSON.stringify(result)
};
return response;
};
Timeout: 25
Runtime: nodejs8.10
SourceIAMRole:
Type: AWS::IAM::Role
Properties:
RoleName: "source-lambda-iam-role"
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Sid: ''
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: 'sts:AssumeRole'
Policies:
-
PolicyName: "helen-assume-destination-role-policy"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action: "sts:AssumeRole"
Resource: !Join ["", [!Sub "${DestinationRoleArn}"]]
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "lambda:InvokeFunction",
"Resource": "arn-for-lambda-you-want-to-invoke"
}
}
exports.handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
body: JSON.stringify('Hello from cross-account Lambda!'),
};
return response;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment