Resolution
If the topic and queue are in the same stack, then use a CloudFormation template to create a topic that sends messages to SQS queues.
If the topic is in one stack and the queue is in another, then create a cross-stack reference. Both stacks must be in the same AWS Region. When you create a cross-stack reference, export the ARN of the SQS queue in one stack. Then, import the ARN in the subscription endpoint property of the SNS topic in the other stack.
If your SNS topic and SQS queue are in different Regions or AWS accounts, then use AWS::SNS::Subscription to set up either a cross-account or cross-Region subscription.
Set up a cross-account subscription
Configure Account A
In the CloudFormation template for the source stack, configure the following settings:
Example JSON template:
{
"Parameters": {
"CrossAccountNumber": {
"AllowedPattern": "[0-9]+",
"Description": "The 12 digit AWS account number to grant access to.",
"MaxLength": "12",
"MinLength": "12",
"Type": "String",
"Default": 123456789101
}
},
"Resources": {
"SnsTopic": {
"Type": "AWS::SNS::Topic"
},
"SnsTopicPolicy": {
"Type": "AWS::SNS::TopicPolicy",
"DependsOn": "SnsTopic",
"Properties": {
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "SnsTopicPolicy",
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::Sub": "arn:aws:iam::${CrossAccountNumber}:root"
}
},
"Action": [
"sns:Subscribe"
],
"Resource": {
"Ref": "SnsTopic"
}
}
]
},
"Topics": [
{
"Ref": "SnsTopic"
}
]
}
}
},
"Outputs": {
"SnsTopicArn": {
"Value": {
"Ref": "SnsTopic"
}
}
}
}
Example YAML template:
Parameters:
CrossAccountNumber:
AllowedPattern: '[0-9]+'
Description: The 12 digit AWS account number to grant access to.
MaxLength: '12'
MinLength: '12'
Type: String
Default: 123456789101
Resources:
SnsTopic:
Type: AWS::SNS::Topic
SnsTopicPolicy:
Type: AWS::SNS::TopicPolicy
DependsOn: SnsTopic
Properties:
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: SnsTopicPolicy
Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${CrossAccountNumber}:root
Action:
- sns:Subscribe
Resource: !Ref SnsTopic
Topics:
- !Ref SnsTopic
Outputs:
SnsTopicArn:
Value: !Ref SnsTopic
Configure Account B
In the CloudFormation template for the destination stack, for Resources, declare the AWS::SNS::Subscription resource, the AWS::SQS::Queue, and the AWS::SQS::QueuePolicy.
Example JSON template:
{
"Parameters": {
"SNSTopicARN": {
"Type": "String",
"Default": "awsSNSTopicArn"
},
"TopicRegion": {
"Type": "String",
"Default": "us-east-1"
}
},
"Resources": {
"Queue": {
"Type": "AWS::SQS::Queue"
},
"SqsQueuePolicy": {
"Type": "AWS::SQS::QueuePolicy",
"Properties": {
"PolicyDocument": {
"Version": "2012-10-17",
"Id": "MyQueuePolicy",
"Statement": [
{
"Sid": "Allow-SNS-SendMessage",
"Effect": "Allow",
"Principal": "*",
"Action": [
"sqs:SendMessage"
],
"Resource": {
"Fn::GetAtt": [
"Queue",
"Arn"
]
},
"Condition": {
"ArnEquals": {
"aws:SourceArn": {
"Ref": "SNSTopicARN"
}
}
}
}
]
},
"Queues" : [
{
"Ref" : "Queue"
}
]
}
},
"SnsSubscription": {
"Type": "AWS::SNS::Subscription",
"Properties": {
"Protocol": "sqs",
"Endpoint": {
"Fn::GetAtt": [
"Queue",
"Arn"
]
},
"Region": {
"Ref": "TopicRegion"
},
"TopicArn": {
"Ref": "SNSTopicARN"
}
}
}
}
}
Example YAML template:
Parameters:
SNSTopicARN:
Type: String
Default: awsSNSTopicArn
TopicRegion:
Type: String
Default: us-east-1
Resources:
Queue:
Type: AWS::SQS::Queue
SqsQueuePolicy:
Type: AWS::SQS::QueuePolicy
Properties:
PolicyDocument:
Version: '2012-10-17'
Id: MyQueuePolicy
Statement:
- Sid: Allow-SNS-SendMessage
Effect: Allow
Principal: "*"
Action:
- sqs:SendMessage
Resource: !GetAtt Queue.Arn
Condition:
ArnEquals:
aws:SourceArn: !Ref SNSTopicARN
Queues:
- !Ref Queue
SnsSubscription:
Type: AWS::SNS::Subscription
Properties:
Protocol: sqs
Endpoint: !GetAtt Queue.Arn
Region: !Ref TopicRegion
TopicArn: !Ref SNSTopicARN
Note: In the preceding example templates, under Parameters, replace awsSNSTopicArn with your SNS topic ARN. Also, replace us-east-1 with the Region of the stack in the source account (Account A).
Set up a cross-Region subscription
Configure Region A
In the CloudFormation template for the stack in one Region, configure the following settings:
- For Resources, declare the AWS::SNS::Topic.
- Create an Outputs section to return the SnsTopicArn.
Example JSON template:
{
"Resources": {
"SnsTopic": {
"Type": "AWS::SNS::Topic"
}
},
"Outputs": {
"SnsTopicArn": {
"Value": {
"Ref": "SnsTopic"
}
}
}
}
Example YAML template:
Resources:
SnsTopic:
Type: AWS::SNS::Topic
Outputs:
SnsTopicArn:
Value: !Ref SnsTopic
Configure Region B
In the CloudFormation template for the stack in the other Region, for Resources, declare the AWS::SNS::Subscription resource and AWS::SQS::Queue.
Example JSON template:
{
"Parameters": {
"SNSTopicARN": {
"Type": "String",
"Default": "awsSNSTopicArnExample"
},
"TopicRegion": {
"Type": "String",
"Default": "us-east-1"
}
},
"Resources": {
"Queue": {
"Type": "AWS::SQS::Queue"
},
"SnsSubscription": {
"Type": "AWS::SNS::Subscription",
"Properties": {
"Protocol": "sqs",
"Endpoint": {
"Fn::GetAtt": [
"Queue",
"Arn"
]
},
"Region": {
"Ref": "TopicRegion"
},
"TopicArn": {
"Ref": "SNSTopicARN"
}
}
}
}
}
Example YAML template:
Parameters:
SNSTopicARN:
Type: String
Default: awsSNSTopicArnExample
TopicRegion:
Type: String
Default: us-east-1
Resources:
Queue:
Type: AWS::SQS::Queue
SnsSubscription:
Type: AWS::SNS::Subscription
Properties:
Protocol: sqs
Endpoint: !GetAtt Queue.Arn
Region: !Ref TopicRegion
TopicArn: !Ref SNSTopicARN
Note: In the preceding example templates, under Parameters, replace awsSNSTopicArnExample with your SNS topic ARN. Also, replace us-east-1 with the Region of the stack from Region A.