Repository: aws/serverless-application-model

Issue:
Feature Request: Add SQS option to SNS event
**Description:**

SAM offers simplified syntax for SNS -> Lambda and with #261 supports adding subscription filter policies. However, a common use case is SNS -> SQS -> Lambda. SAM offers simplified syntax for SQS -> Lambda, but you have to use standard CloudFormation to setup the SNS -> SQS connection and subscription filter policy, which can be verbose.

SAM could add a lot of value by adding an option to the existing SNS event type to create an SQS queue.

Here's an example that uses simple default settings for the queue:

```yaml
Type: SNS
Properties:
  Topic: arn:aws:sns:us-east-1:123456789012:my_topic
  # new property that creates an SQS queue between the topic and Lambda function
  # When only the boolean is specified, SAM uses the following defaults:
  # AWS::SQS::Queue logicalId: <function logicalId><SNS event key>Queue
  # AWS::SQS::QueuePolicy logicalId: <function logicalId><SNS event key>QueuePolicy
  # BatchSize: default behavior - don't add to `AWS::Lambda::EventSourceMapping` resource so default value is used.
  # Enabled: default behavior - don't add to `AWS::Lambda::EventSourceMapping` resource so default value is used.
  SqsSubscription: true
  FilterPolicy:
    store: 
      - example_corp
    price_usd: 
      - numeric: 
          - ">="
          - 100
```

Here's an example that specifies additional options for the queue:

```yaml
Type: SNS
Properties:
  Topic: arn:aws:sns:us-east-1:123456789012:my_topic
  # new property that creates an SQS queue between the topic and Lambda function
  # Default values can be overridden by passing an object instead of a boolean. Supported keys:
  # QueuePolicyLogicalId: overrides default logicalId naming of the AWS::SQS::QueuePolicy resource.
  # QueueArn: allows the user to specify their own queue instead of having SAM create one on their behalf, allowing them to specify non-default properties on the queue.
  # BatchSize: if specified, add BatchSize property with given value to `AWS::Lambda::EventSourceMapping` resource.
  # Enabled: if specified, add BatchSize property with given value to `AWS::Lambda::EventSourceMapping` resource.
  SqsSubscription:
    QueuePolicyLogicalId: CustomQueuePolicyLogicalId
    QueueArn: !GetAtt MyCustomQueue.Arn
    BatchSize: 5
    Enabled: false
  FilterPolicy:
    store: 
      - example_corp
    price_usd: 
      - numeric: 
          - ">="
          - 100
```

Implementation Note: When SAM expands this into CloudFormation, the `AWS::SQS::QueuePolicy` resource should look like this:

```yaml
  ExampleQueuePolicy:
    Type: AWS::SQS::QueuePolicy
    Properties:
      Queues:
        - !Ref ExampleQueue
      PolicyDocument:
        Version: '2012-10-17'
        Id: ExampleQueuePolicy
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - sns.amazonaws.com
            Action:
              - sqs:SendMessage
            Resource:
              - !GetAtt ExampleQueue.Arn
            Condition:
              ArnEquals:
                aws:SourceArn: <SNS Topic ARN>
```


Discussion:
That would be really helpful indeed. 
Happy to work with anyone interested in picking this up!
@jlhood I would like to work on this issue.
@Buffer0x7cd Awesome, thank you so much! Before implementing, we need to finalize the SAM spec. The draft I created above just has a simple `UseSQS` boolean, but we'll want a way to surface some of the options of the SQS event source like BatchSize and Enabled. I'll update the spec in the issue description with exactly what we want to support, then I'll post a comment so you'll know when it's ready to start implementation.
@brettstack @keetonian I've updated the issue description with the proposed SAM spec for this feature. Can you both review?
Do we have precedent for overriding generated logical resource id like `QueuePolicyLogicalId`? Do we need it?

What's a better name than `UseSQS` - `[Forward|Push|Send]ToSqs`? `SqsSubscriptions`?

Can we allow an array of queues also?
Thanks for the feedback, @brettstack!

> Do we have precedent for overriding generated logical resource id like QueuePolicyLogicalId? Do we need it?

This would be something new. Maybe this is a little selfish, but in the [Event Fork Pipelines](https://github.com/aws-samples/aws-serverless-event-fork-pipelines) apps we just released today, I'm specifying the Queue and QueuePolicy explicitly. Once this SAM feature is released, I'd love to convert over to using it since it makes the template even easier to read. However, without being able to override the logical id, I don't have a way to use the SAM feature while keeping my apps backwards-compatible. 😞 Allowing overrides of logical ids would allow customers to simplify existing templates as new SAM features are added while maintaining backwards-compatibility. However, I won't fight too hard if you really don't want to add it.

> What's a better name than UseSQS

Yeah I'm not loving the key name, but I couldn't think of anything better. None of your suggestions are jumping out to me as obviously better. Some others I can think of: `EnableSQS` or just `SQS`. I'm kind of liking just `SQS`, honestly. `SQS: true` and `SQS: <additional properties>` seems concise and readable. What do you think?

> Can we allow an array of queues also?

You can already achieve this with multiple Events entries. Accepting a list could make the syntax slightly shorter, but I think it adds complexity since then there'd be two ways of doing this within the same resource.
Given that use case I'm okay with adding the logical resource id name override.

The wording in docs is around "subscribing" an SQS Queue to an SNS Topic, so I'd like to get that word in there to make it clear what it is you achieve by specifying this property. `SqsSubscription`, `SubscribeSqs` (variation: replace `Sqs` with `Queue` or `SqsQueue`).

Multiple Event entries wouldn't be as succinct.
I like `SqsSubscription`
Thanks. Updated it to `SqsSubscription` in the top-level RFC comment.
@Buffer0x7cd I've updated the top-level issue comment with the finalized spec for this feature, so it should be ready to implement once you're finished with your [other PR](https://github.com/awslabs/serverless-application-model/pull/848). Let me know if you have any questions. Thanks!

Resolving patch:
diff --git a/samtranslator/model/eventsources/push.py b/samtranslator/model/eventsources/push.py
--- a/samtranslator/model/eventsources/push.py
+++ b/samtranslator/model/eventsources/push.py
@@ -10,6 +10,8 @@
 from samtranslator.model.sns import SNSSubscription
 from samtranslator.model.lambda_ import LambdaPermission
 from samtranslator.model.events import EventsRule
+from samtranslator.model.eventsources.pull import SQS
+from samtranslator.model.sqs import SQSQueue, SQSQueuePolicy, SQSQueuePolicies
 from samtranslator.model.iot import IotTopicRule
 from samtranslator.translator.arn_generator import ArnGenerator
 from samtranslator.model.exceptions import InvalidEventException, InvalidResourceException
@@ -352,7 +354,8 @@ class SNS(PushEventSource):
     property_types = {
             'Topic': PropertyType(True, is_str()),
             'Region': PropertyType(False, is_str()),
-            'FilterPolicy': PropertyType(False, dict_of(is_str(), list_of(one_of(is_str(), is_type(dict)))))
+            'FilterPolicy': PropertyType(False, dict_of(is_str(), list_of(one_of(is_str(), is_type(dict))))),
+            'SqsSubscription': PropertyType(False, is_type(bool))
     }
 
     def to_cloudformation(self, **kwargs):
@@ -363,28 +366,67 @@ def to_cloudformation(self, **kwargs):
         :rtype: list
         """
         function = kwargs.get('function')
+        role = kwargs.get('role')
 
         if not function:
             raise TypeError("Missing required keyword argument: function")
 
-        return [self._construct_permission(function, source_arn=self.Topic),
-                self._inject_subscription(function, self.Topic, self.Region, self.FilterPolicy)]
+        # SNS -> Lambda
+        if not self.SqsSubscription:
+            subscription = self._inject_subscription(
+                'lambda', function.get_runtime_attr("arn"),
+                self.Topic, self.Region, self.FilterPolicy, function.resource_attributes
+            )
+            return [self._construct_permission(function, source_arn=self.Topic), subscription]
 
-    def _inject_subscription(self, function, topic, region, filterPolicy):
+        # SNS -> SQS -> Lambda
+        resources = []
+        queue = self._inject_sqs_queue()
+        queue_policy = self._inject_sqs_queue_policy(self.Topic, queue)
+        subscription = self._inject_subscription(
+            'sqs', queue.get_runtime_attr('arn'),
+            self.Topic, self.Region, self.FilterPolicy, function.resource_attributes
+        )
+
+        resources = resources + self._inject_sqs_event_source_mapping(function, role, queue.get_runtime_attr('arn'))
+        resources.append(queue)
+        resources.append(queue_policy)
+        resources.append(subscription)
+        return resources
+
+    def _inject_subscription(self, protocol, endpoint, topic, region, filterPolicy, resource_attributes):
         subscription = SNSSubscription(self.logical_id)
-        subscription.Protocol = 'lambda'
-        subscription.Endpoint = function.get_runtime_attr("arn")
+        subscription.Protocol = protocol
+        subscription.Endpoint = endpoint
         subscription.TopicArn = topic
         if region is not None:
             subscription.Region = region
-        if CONDITION in function.resource_attributes:
-            subscription.set_resource_attribute(CONDITION, function.resource_attributes[CONDITION])
+        if CONDITION in resource_attributes:
+            subscription.set_resource_attribute(CONDITION, resource_attributes[CONDITION])
 
         if filterPolicy is not None:
             subscription.FilterPolicy = filterPolicy
 
         return subscription
 
+    def _inject_sqs_queue(self):
+        return SQSQueue(self.logical_id + 'Queue')
+
+    def _inject_sqs_event_source_mapping(self, function, role, queue_arn):
+        event_source = SQS(self.logical_id + 'EventSourceMapping')
+        event_source.Queue = queue_arn
+        event_source.BatchSize = 10
+        event_source.Enabled = True
+        return event_source.to_cloudformation(function=function, role=role)
+
+    def _inject_sqs_queue_policy(self, topic_arn, queue):
+        policy = SQSQueuePolicy(self.logical_id + 'QueuePolicy')
+        policy.PolicyDocument = SQSQueuePolicies.sns_topic_send_message_role_policy(
+            topic_arn, queue.get_runtime_attr('arn')
+        )
+        policy.Queues = [queue.get_runtime_attr('queue_url')]
+        return policy
+
 
 class Api(PushEventSource):
     """Api method event source for SAM Functions."""
diff --git a/samtranslator/model/sqs.py b/samtranslator/model/sqs.py
new file mode 100644
--- /dev/null
+++ b/samtranslator/model/sqs.py
@@ -0,0 +1,44 @@
+from samtranslator.model import PropertyType, Resource
+from samtranslator.model.types import is_type, list_of
+from samtranslator.model.intrinsics import fnGetAtt, ref
+
+
+class SQSQueue(Resource):
+    resource_type = 'AWS::SQS::Queue'
+    property_types = {
+    }
+    runtime_attrs = {
+        "queue_url": lambda self: ref(self.logical_id),
+        "arn": lambda self: fnGetAtt(self.logical_id, "Arn"),
+    }
+
+
+class SQSQueuePolicy(Resource):
+    resource_type = 'AWS::SQS::QueuePolicy'
+    property_types = {
+        'PolicyDocument': PropertyType(True, is_type(dict)),
+        'Queues': PropertyType(True, list_of(str)),
+    }
+    runtime_attrs = {
+        "arn": lambda self: fnGetAtt(self.logical_id, "Arn")
+    }
+
+
+class SQSQueuePolicies:
+    @classmethod
+    def sns_topic_send_message_role_policy(cls, topic_arn, queue_arn):
+        document = {
+            'Version': '2012-10-17',
+            'Statement': [{
+                'Action': 'sqs:SendMessage',
+                'Effect': 'Allow',
+                'Principal': '*',
+                'Resource': queue_arn,
+                'Condition': {
+                    'ArnEquals': {
+                        'aws:SourceArn': topic_arn
+                    }
+                }
+            }]
+        }
+        return document


Test patch:
diff --git a/tests/translator/input/sns_sqs.yaml b/tests/translator/input/sns_sqs.yaml
new file mode 100644
--- /dev/null
+++ b/tests/translator/input/sns_sqs.yaml
@@ -0,0 +1,23 @@
+Resources:
+  SaveNotificationFunction:
+    Type: AWS::Serverless::Function
+    Properties:
+      CodeUri: s3://sam-demo-bucket/notifications.zip
+      Handler: index.save_notification
+      Runtime: nodejs8.10
+      Events:
+        NotificationTopic:
+          Type: SNS
+          Properties:
+            Topic: !Ref Notifications
+            SqsSubscription: true
+            FilterPolicy:
+              store:
+                - example_corp
+              price_usd:
+                - numeric:
+                    - ">="
+                    - 100
+
+  Notifications:
+    Type: AWS::SNS::Topic
diff --git a/tests/translator/output/aws-cn/sns_sqs.json b/tests/translator/output/aws-cn/sns_sqs.json
new file mode 100644
--- /dev/null
+++ b/tests/translator/output/aws-cn/sns_sqs.json
@@ -0,0 +1,136 @@
+{
+  "Resources": {
+    "Notifications": {
+      "Type": "AWS::SNS::Topic"
+    }, 
+    "SaveNotificationFunctionNotificationTopicQueue": {
+      "Type": "AWS::SQS::Queue", 
+      "Properties": {}
+    }, 
+    "SaveNotificationFunctionNotificationTopicQueuePolicy": {
+      "Type": "AWS::SQS::QueuePolicy", 
+      "Properties": {
+        "Queues": [
+          {
+            "Ref": "SaveNotificationFunctionNotificationTopicQueue"
+          }
+        ], 
+        "PolicyDocument": {
+          "Version": "2012-10-17", 
+          "Statement": [
+            {
+              "Action": "sqs:SendMessage", 
+              "Resource": {
+                "Fn::GetAtt": [
+                  "SaveNotificationFunctionNotificationTopicQueue", 
+                  "Arn"
+                ]
+              }, 
+              "Effect": "Allow", 
+              "Condition": {
+                "ArnEquals": {
+                  "aws:SourceArn": {
+                    "Ref": "Notifications"
+                  }
+                }
+              }, 
+              "Principal": "*"
+            }
+          ]
+        }
+      }
+    }, 
+    "SaveNotificationFunctionNotificationTopic": {
+      "Type": "AWS::SNS::Subscription", 
+      "Properties": {
+        "FilterPolicy": {
+          "price_usd": [
+            {
+              "numeric": [
+                ">=", 
+                100
+              ]
+            }
+          ], 
+          "store": [
+            "example_corp"
+          ]
+        }, 
+        "Endpoint": {
+          "Fn::GetAtt": [
+            "SaveNotificationFunctionNotificationTopicQueue", 
+            "Arn"
+          ]
+        }, 
+        "Protocol": "sqs", 
+        "TopicArn": {
+          "Ref": "Notifications"
+        }
+      }
+    }, 
+    "SaveNotificationFunctionRole": {
+      "Type": "AWS::IAM::Role", 
+      "Properties": {
+        "ManagedPolicyArns": [
+          "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", 
+          "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole"
+        ], 
+        "AssumeRolePolicyDocument": {
+          "Version": "2012-10-17", 
+          "Statement": [
+            {
+              "Action": [
+                "sts:AssumeRole"
+              ], 
+              "Effect": "Allow", 
+              "Principal": {
+                "Service": [
+                  "lambda.amazonaws.com"
+                ]
+              }
+            }
+          ]
+        }
+      }
+    }, 
+    "SaveNotificationFunctionNotificationTopicEventSourceMapping": {
+      "Type": "AWS::Lambda::EventSourceMapping", 
+      "Properties": {
+        "BatchSize": 10, 
+        "Enabled": true, 
+        "EventSourceArn": {
+          "Fn::GetAtt": [
+            "SaveNotificationFunctionNotificationTopicQueue", 
+            "Arn"
+          ]
+        }, 
+        "FunctionName": {
+          "Ref": "SaveNotificationFunction"
+        }
+      }
+    }, 
+    "SaveNotificationFunction": {
+      "Type": "AWS::Lambda::Function", 
+      "Properties": {
+        "Handler": "index.save_notification", 
+        "Code": {
+          "S3Bucket": "sam-demo-bucket", 
+          "S3Key": "notifications.zip"
+        }, 
+        "Role": {
+          "Fn::GetAtt": [
+            "SaveNotificationFunctionRole", 
+            "Arn"
+          ]
+        }, 
+        "Runtime": "nodejs8.10", 
+        "Tags": [
+          {
+            "Value": "SAM", 
+            "Key": "lambda:createdBy"
+          }
+        ]
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/tests/translator/output/aws-us-gov/sns_sqs.json b/tests/translator/output/aws-us-gov/sns_sqs.json
new file mode 100644
--- /dev/null
+++ b/tests/translator/output/aws-us-gov/sns_sqs.json
@@ -0,0 +1,136 @@
+{
+  "Resources": {
+    "Notifications": {
+      "Type": "AWS::SNS::Topic"
+    },
+    "SaveNotificationFunctionNotificationTopicQueue": {
+      "Type": "AWS::SQS::Queue",
+      "Properties": {}
+    },
+    "SaveNotificationFunctionNotificationTopicQueuePolicy": {
+      "Type": "AWS::SQS::QueuePolicy",
+      "Properties": {
+        "Queues": [
+          {
+            "Ref": "SaveNotificationFunctionNotificationTopicQueue"
+          }
+        ],
+        "PolicyDocument": {
+          "Version": "2012-10-17",
+          "Statement": [
+            {
+              "Action": "sqs:SendMessage",
+              "Resource": {
+                "Fn::GetAtt": [
+                  "SaveNotificationFunctionNotificationTopicQueue",
+                  "Arn"
+                ]
+              },
+              "Effect": "Allow",
+              "Condition": {
+                "ArnEquals": {
+                  "aws:SourceArn": {
+                    "Ref": "Notifications"
+                  }
+                }
+              },
+              "Principal": "*"
+            }
+          ]
+        }
+      }
+    },
+    "SaveNotificationFunctionNotificationTopic": {
+      "Type": "AWS::SNS::Subscription",
+      "Properties": {
+        "FilterPolicy": {
+          "price_usd": [
+            {
+              "numeric": [
+                ">=",
+                100
+              ]
+            }
+          ],
+          "store": [
+            "example_corp"
+          ]
+        },
+        "Endpoint": {
+          "Fn::GetAtt": [
+            "SaveNotificationFunctionNotificationTopicQueue",
+            "Arn"
+          ]
+        },
+        "Protocol": "sqs",
+        "TopicArn": {
+          "Ref": "Notifications"
+        }
+      }
+    },
+    "SaveNotificationFunctionRole": {
+      "Type": "AWS::IAM::Role",
+      "Properties": {
+        "ManagedPolicyArns": [
+          "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
+          "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole"
+        ],
+        "AssumeRolePolicyDocument": {
+          "Version": "2012-10-17",
+          "Statement": [
+            {
+              "Action": [
+                "sts:AssumeRole"
+              ],
+              "Effect": "Allow",
+              "Principal": {
+                "Service": [
+                  "lambda.amazonaws.com"
+                ]
+              }
+            }
+          ]
+        }
+      }
+    },
+    "SaveNotificationFunctionNotificationTopicEventSourceMapping": {
+      "Type": "AWS::Lambda::EventSourceMapping",
+      "Properties": {
+        "BatchSize": 10,
+        "Enabled": true,
+        "EventSourceArn": {
+          "Fn::GetAtt": [
+            "SaveNotificationFunctionNotificationTopicQueue",
+            "Arn"
+          ]
+        },
+        "FunctionName": {
+          "Ref": "SaveNotificationFunction"
+        }
+      }
+    },
+    "SaveNotificationFunction": {
+      "Type": "AWS::Lambda::Function",
+      "Properties": {
+        "Handler": "index.save_notification",
+        "Code": {
+          "S3Bucket": "sam-demo-bucket",
+          "S3Key": "notifications.zip"
+        },
+        "Role": {
+          "Fn::GetAtt": [
+            "SaveNotificationFunctionRole",
+            "Arn"
+          ]
+        },
+        "Runtime": "nodejs8.10",
+        "Tags": [
+          {
+            "Value": "SAM",
+            "Key": "lambda:createdBy"
+          }
+        ]
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/tests/translator/output/sns_sqs.json b/tests/translator/output/sns_sqs.json
new file mode 100644
--- /dev/null
+++ b/tests/translator/output/sns_sqs.json
@@ -0,0 +1,136 @@
+{
+  "Resources": {
+    "Notifications": {
+      "Type": "AWS::SNS::Topic"
+    },
+    "SaveNotificationFunctionNotificationTopicQueue": {
+      "Type": "AWS::SQS::Queue",
+      "Properties": {}
+    },
+    "SaveNotificationFunctionNotificationTopicQueuePolicy": {
+      "Type": "AWS::SQS::QueuePolicy",
+      "Properties": {
+        "Queues": [
+          {
+            "Ref": "SaveNotificationFunctionNotificationTopicQueue"
+          }
+        ],
+        "PolicyDocument": {
+          "Version": "2012-10-17",
+          "Statement": [
+            {
+              "Action": "sqs:SendMessage",
+              "Resource": {
+                "Fn::GetAtt": [
+                  "SaveNotificationFunctionNotificationTopicQueue",
+                  "Arn"
+                ]
+              },
+              "Effect": "Allow",
+              "Condition": {
+                "ArnEquals": {
+                  "aws:SourceArn": {
+                    "Ref": "Notifications"
+                  }
+                }
+              },
+              "Principal": "*"
+            }
+          ]
+        }
+      }
+    },
+    "SaveNotificationFunctionNotificationTopic": {
+      "Type": "AWS::SNS::Subscription",
+      "Properties": {
+        "FilterPolicy": {
+          "price_usd": [
+            {
+              "numeric": [
+                ">=",
+                100
+              ]
+            }
+          ],
+          "store": [
+            "example_corp"
+          ]
+        },
+        "Endpoint": {
+          "Fn::GetAtt": [
+            "SaveNotificationFunctionNotificationTopicQueue",
+            "Arn"
+          ]
+        },
+        "Protocol": "sqs",
+        "TopicArn": {
+          "Ref": "Notifications"
+        }
+      }
+    },
+    "SaveNotificationFunctionRole": {
+      "Type": "AWS::IAM::Role",
+      "Properties": {
+        "ManagedPolicyArns": [
+          "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
+          "arn:aws:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole"
+        ],
+        "AssumeRolePolicyDocument": {
+          "Version": "2012-10-17",
+          "Statement": [
+            {
+              "Action": [
+                "sts:AssumeRole"
+              ],
+              "Effect": "Allow",
+              "Principal": {
+                "Service": [
+                  "lambda.amazonaws.com"
+                ]
+              }
+            }
+          ]
+        }
+      }
+    },
+    "SaveNotificationFunctionNotificationTopicEventSourceMapping": {
+      "Type": "AWS::Lambda::EventSourceMapping",
+      "Properties": {
+        "BatchSize": 10,
+        "Enabled": true,
+        "EventSourceArn": {
+          "Fn::GetAtt": [
+            "SaveNotificationFunctionNotificationTopicQueue",
+            "Arn"
+          ]
+        },
+        "FunctionName": {
+          "Ref": "SaveNotificationFunction"
+        }
+      }
+    },
+    "SaveNotificationFunction": {
+      "Type": "AWS::Lambda::Function",
+      "Properties": {
+        "Handler": "index.save_notification",
+        "Code": {
+          "S3Bucket": "sam-demo-bucket",
+          "S3Key": "notifications.zip"
+        },
+        "Role": {
+          "Fn::GetAtt": [
+            "SaveNotificationFunctionRole",
+            "Arn"
+          ]
+        },
+        "Runtime": "nodejs8.10",
+        "Tags": [
+          {
+            "Value": "SAM",
+            "Key": "lambda:createdBy"
+          }
+        ]
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py
--- a/tests/translator/test_translator.py
+++ b/tests/translator/test_translator.py
@@ -195,6 +195,7 @@ class TestTranslatorEndToEnd(TestCase):
         's3_multiple_functions',
         's3_with_dependsOn',
         'sns',
+        'sns_sqs',
         'sns_existing_other_subscription',
         'sns_topic_outside_template',
         'alexa_skill',