Create the Lambda function in account A with the proper permissions, eg, use this cloudformation template:
Parameters:
OtherAccountId:
Type: String
Resources:
TestFunction:
Type: AWS::Lambda::Function
Properties:
Runtime: python2.7
Handler: index.handler
Role: !GetAtt TestRole.Arn
Code:
ZipFile: !Sub |
from botocore.vendored import requests
import json
def send(event, context, responseStatus, responseData, physicalResourceId):
responseUrl = event['ResponseURL']
print responseUrl
responseBody = {}
responseBody['Status'] = responseStatus
responseBody['Reason'] = 'See the details in CloudWatch Log Stream: ' + context.log_stream_name
responseBody['PhysicalResourceId'] = physicalResourceId or context.log_stream_name
responseBody['StackId'] = event['StackId']
responseBody['RequestId'] = event['RequestId']
responseBody['LogicalResourceId'] = event['LogicalResourceId']
responseBody['Data'] = responseData
json_responseBody = json.dumps(responseBody)
print "Response body:\n" + json_responseBody
headers = {
'content-type' : '',
'content-length' : str(len(json_responseBody))
}
try:
response = requests.put(responseUrl,
data=json_responseBody,
headers=headers)
print "Status code: " + response.reason
except Exception as e:
print "send(..) failed executing requests.put(..): " + str(e)
def handler(event, context):
print event
print context
responseData = {}
send(event, context, "SUCCESS", responseData, "CustomResourcePhysicalID")
CrossAccountPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !Ref TestFunction
Principal: !Ref OtherAccountId
TestRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
-
Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: AllowAccess
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- "logs:*"
Resource: "arn:aws:logs:*:*:*"
The CrossAccountPermission
record is the important one here, there we grant access to account B.
In account B, test it with the following template:
Parameters:
LambdaArn:
Type: String
Resources:
CustomResourceTest:
Type: Custom::Demo
Properties:
ServiceToken: !Ref LambdaArn
There is an additional possible gotcha here: The user/role that is running cloudformation in account B also needs permission to execute the Lambda function, if you are running CF with an admin user that shouldn't be an issue as you would have lambda:*
permissions on resource *
anyway.