How do I create a subscription between my Amazon SQS queue and an Amazon SNS topic in AWS CloudFormation?

Last updated: 2019-10-02

How do I create a subscription between my Amazon Simple Queue Service (Amazon SQS) queue and Amazon Simple Notification Service (Amazon SNS) topic in AWS CloudFormation?

Resolution

Choose one of the following solutions based on your use case:

  • If the SNS topic and SQS queue are in the same stack, use an AWS CloudFormation template to create a topic that sends messages to SQS queues.
  • If the SNS topic is in one stack and the SQS queue that will subscribe to that SNS topic is in another stack in the same AWS Region, create a cross-stack reference.
    Note: When you create a cross-stack reference, export the Amazon Resource Name (ARN) of the SQS queue in one stack. Then, import that SQS queue ARN in the subscription endpoint property of the SNS topic in the other stack.
  • If the SNS topic and SQS queue are in separate AWS Regions, follow the steps in the Use the AWS::SNS::Subscription resource to set up a cross-region subscription section.
  • If the SNS topic and SQS queue are in separate AWS accounts, follow the steps in the Use the AWS::SNS::Subscription resource to set up a cross-account subscription section.

Use the AWS::SNS::Subscription resource to set up a cross-region subscription

1.    In the AWS CloudFormation template for the stack in one AWS Region, declare the SNS topic in that Region, and then create an output resource to annotate the SNS topic ARN.

See the following JSON and YAML example templates.

JSON:

{
 "Resources": {
  "SnsTopic": {
   "Type": "AWS::SNS::Topic"
  }
 },
 "Outputs": {
  "SnsTopicArn": {
   "Value": "SnsTopic"
  }
 }
}

YAML:

Resources:
  SnsTopic:
    Type: AWS::SNS::Topic
Outputs:
  SnsTopicArn:
    Value: !Ref SnsTopic

2.    In an AWS CloudFormation template for the other stack in the other AWS Region, define the AWS::SNS::Subscription resource and the SQS queue.

Note: Replace awsSNSTopicArnExample with your SNS topic ARN, and replace us-east-1 with your AWS Region.

See the following JSON and YAML example templates.

JSON:

{
 "Parameters": {
  "SNSTopicARN": {
   "Type": "String",
   "Description": "awsSNSTopicArnExample"
  },
  "TopicRegion": {
   "Type": "String",
   "Description": "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"
    }
   }
  }
 }
}

YAML:

Parameters:
  SNSTopicARN:
    Type: String
    Description: awsSNSTopicArnExample 
  TopicRegion:
    Type: String
    Description: 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

Your cross-region subscription is now set up.

Use the AWS::SNS::Subscription resource to set up a cross-account subscription

1.    In the AWS CloudFormation template for the stack in one AWS source account, declare the SNS topic and AWS::SNS::TopicPolicy. Then, create an output resource to annotate the SNS topic ARN and provide your destination AWS account as a parameter.

See the following JSON and YAML example templates.

JSON:

{
  "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"
      }
    }
  }
}

YAML:

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

2.    In an AWS CloudFormation template for the stack in the AWS account where you want to extend your subscription, define the AWS::SNS::Subscription resource, SQS queue, and AWS::SQS::QueuePolicy policy.

Note: Replace awsSNSTopicArn with your SNS topic ARN and replace us-east-1 with your AWS Region.

See the following JSON and YAML example templates.

JSON:

{
 "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"
    }
   }
  }
 }
}

YAML:

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

Did this article help you?

Anything we could improve?


Need more help?