Four AWS CLI Commands to Set Up a Cross-Region/Account SNS Topic Subscription & Permissions

As I mentioned in my previous post, you can subscribe an AWS SNS topic in one region/account to a Lambda function in a different region and/or account (assuming you already have the accounts talking to each other) via the CLI. This can’t be done with CloudFormation (I’m told cross-region subscriptions are in the works), and you can’t do it through the console, so the CLI is your only option if you want to make this happen. Luckily, it can be done in four easy steps.

In this example, I’m setting up a cross-account, cross-region subscription, but you can adapt this to be one or the other. (Obviously, all account IDs have been replaced with 111111111111 and 222222222222, and these names are based on ideas discussed in previous posts related to automating Infoblox DNS entries with Lambda, so you’ll need to make the relevant substitutions for IDs and names throughout.)

First, create the Amazon SNS topic:
(The console requires SNS topic names to be 10 characters or less, so to be safe, I adhere to that restriction when using the CLI too.)
Change “region” & “profile” as necessary:

aws sns create-topic --name SNSInfblx --region "eu-central-1" --profile "nonprod"

The response you get back looks like this:

{  "TopicArn": "arn:aws:sns:eu-central-1:111111111111:SNSInfblx"  }

(Note that ARN, as it will be used in the following steps!)

Next, give permission to subscribe to the topic:
Change “topic-arn”, “region” & “profile” as necessary:

aws sns add-permission --topic-arn arn:aws:sns:eu-central-1:111111111111:SNSInfblx --label Infoblx-LambdaAccess --aws-account-id 222222222222--action-name Subscribe ListSubscriptionsByTopic Receive --region "eu-central-1" --profile "nonprod"

There will be no response/blank.

Third, add the Lambda permission to allow it to be invoked from SNS:
Change “source-arn” and “statement-id” as necessary (adding “-NP-eu-central-1” or similar to the end of “Statement-id” importantly makes each one unique)):

aws lambda add-permission --function-name "Lambda-DNS-Infblx" --statement-id "Lambda-DNS-Infblx-NP-eu-central-1" --action "lambda:InvokeFunction" --principal sns.amazonaws.com --source-arn arn:aws:sns:eu-central-1:111111111111:SNSInfblx --region "us-east-1" --profile "shared"

The response you get back looks like this:

{  "Statement": "{\"Sid\":\"Lambda-DNS-Infblx-NP-eu-central-1\",\"Effect\":\"Allow\",\"Principal\"  :{\"Service\":\"sns.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:us-east-1:222222222222:function:Lambda-DNS-Infblx\",\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:sns:eu  -central-1:111111111111:SNSInfblx\"}}}"  }

Finally, subscribe the Lambda function to the topic:
Change “topic-arn” and “region” as necessary:

aws sns subscribe --topic-arn arn:aws:sns:eu-central-1:111111111111:SNSInfblx --protocol lambda --notification-endpoint arn:aws:lambda:us-east-1:222222222222:function:Lambda-DNS-Infblx --region "eu-central-1" --profile "shared"

The response you get back looks like this:

{  "SubscriptionArn": "arn:aws:sns:eu-central-1:111111111111:SNSInfblx:45e232e1-ccc7-4142-9cae-d7fc1b40fa6"  }

That’s it!
Now when you want to do something like invoking a Lambda function in another account/region via an SNS topic through a custom resource in AWS CloudFormation, it should work like a charm! This kind of thing isn’t well documented, IMHO, so getting this all straight and functioning smoothly can be a little confusing. I hope this post saved you some head-scratching!

Steve