You’ve got a SNS topic in Account A and you wish to subscribe a Lambda function to this topic in Account B.
Setting this up requires configuration on both account sides with resource-based permission policies being applied to SNS in one account and Lambda in the other.
In other words, you’ll need to setup the permissions for SNS and Lambda to allow both subscription and invocation.
Getting Started
You should already have your SNS topic in Account A and a suitable Lambda function subscriber in Account B. For example:
- Account A Id: 5556667778 (SNS topic lives here)
- Account B Id: 12345678901 (Lambda function lives here)
Configure SNS topic in Account A to allow Subscriptions from Account B
Use the AWS CLI to add a resource-based permission policy to the SNS topic (using it’s ARN). This will allow the Receive and Subscribe actions from Account B.
aws sns add-permission \ --topic-arn "arn:aws:sns:us-east-1:5556667778:cross-account-topic" \ --label "AllowSubscriptionFromAccountB" \ --aws-account-id "12345678901" \ --action-name "Receive" "Subscribe"
Configure the Lambda function in Account B to allow invocation from the SNS topic in Account A
Next, add a resource-based permission policy to your Lambda function in Account B. This policy will effectively allow the specific SNS topic in Account A to invoke the Lambda function.
It’s always good practice to follow the principle of least privilege (POLP). In this case you’re only allowing the specific SNS topic in one account to invoke the specific Lambda function you’re adding the policy to.
aws lambda add-permission \ --function-name "cross-account-lambda-subscriber" \ --statement-id "AllowInvokeFromExampleSns" \ --principal "sns.amazonaws.com" \ --action "lambda:InvokeFunction" \ --source-arn "arn:aws:sns:us-east-1:5556667778:cross-account-topic"
Subscribe the Lambda function in Account B to the SNS topic in Account A
Of course you’ll need to actually subscribe the Lambda function to the SNS topic. From Account B (where your Lambda function is setup), run the following command to subscribe it to the SNS topic in Account A.
aws sns subscribe \ --topic-arn "arn:aws:sns:us-east-1:5556667778:cross-account-topic" \ --protocol "lambda" \ --notification-endpoint "arn:aws:lambda:us-east-1:12345678901:function:cross-account-lambda-subscriber"
Concluding
Send a test message to your SNS topic and you should see the Lambda function process the message in the other account.
If you need to diagnose anything, remember to check Lambda CloudWatch monitoring logs, or use the SNS Delivery Status feature.
That’s all there is to setting up SNS to Lambda cross account permissions.
When you are experiencing:
“An error occurred (InvalidParameter) when calling the Subscribe operation: Invalid parameter: TopicArn”
While subscribing Lambda function in Account B to the SNS topic in Account A.
check if you are not using different AWS region in –topic-arn and in your default aws settings (~/.aws/config). In such a case try to run subscription command with “–region ”
The command would looks like this:
aws sns subscribe \
–topic-arn “arn:aws:sns:us-east-1:5556667778:cross-account-topic” \
–protocol “lambda” \
–notification-endpoint “arn:aws:lambda:us-east-1:12345678901:function:cross-account-lambda-subscriber”\
–region us-east-1
Fantastic guide and a brilliant solution to a problem I was scratching my head over for too long. Much appreciated for sharing your wisdom on this.
Hi,
How does your topic arn:aws:sns:us-east-1:5556667778:cross-account-topic”looks like?
I converted your code to cloudformation like
LambdaSNS:
Type: “AWS::SNS::Topic”
this topic is a target for an eventrule, unf i do not see the lambda triggered ..
if i’m trying to setup cloudformation in account A like
LambdaSNS:
Type: “AWS::SNS::Topic”
Subscription:
– Endpoint: “arn:aws:lambda-Account B”
Protocol: “lambda”
the resource can’t be created because of an error stating you are not the owner of the endpoint
Should be possible. You’ll need to look up how to add a resource based policy using Serverless. If its not feature of SLS, then you should at least be able to use the serverless hooks or plugins system to at least do it by running aws cli as part of the sls deploy command lifecycle.
Any advice on how to do this with serverless?
Thanks for the nice comment Dmitrijs! 🙂
I think it is a crime to leave such a wonderful guide without a comment. Works perfectly and nice code examples, helped me a lot.