Debugging SQS subscription issues to topics
Tags: aws, serverless, security
Published: 2023-06-22 07:09:27

When we want to subscribe an SQS queue to an SNS topic, it must have the relevant permissions to send messages to the queue. How we add it as a subscriber to the topic via the AWS Console matters because the SQS access policy doesn't always contain the correct permission statement.

## 1. The scenario

Say we want to build a <a href="https://docs.aws.amazon.com/sns/latest/dg/sns-common-scenarios.html" class="link" target="_blank" rel="noopener noreferrer">fanout</a> serverless architecture.

The key service that **publishes** messages to its **subscribers** is <a href="https://aws.amazon.com/sns/" class="link" target="_blank" rel="noopener noreferrer">Simple Notification Service (SNS)</a>. We can add multiple different subscribers to a **topic**, for example, email addresses, phone numbers, or <a href="https://aws.amazon.com/sqs/" class="link" target="_blank" rel="noopener noreferrer">SQS</a> queues.

One use case of queues is for buffering purposes. When the consumer can process the messages slower than the producer sends them, queues can temporarily store them until the consumer eventually processes them.

In AWS, everything is about **permissions**. Even AWS services can't call other services if the relevant permissions are missing.

When we use <a href="https://aws.amazon.com/cdk/" class="link" target="_blank" rel="noopener noreferrer">CDK</a> to create our infrastructure, the framework will take care of the permissions.

But what if we need to put together a quick demo in the <a href="https://aws.amazon.com/console/" class="link" target="_blank" rel="noopener noreferrer">Console</a>? It should work, too, right?

## 2. Ways to solve the task

This blog post will not explain how we create a topic or a queue. Please see the references section at the end if you need help.

The task is to subscribe the queue to the topic. To continue with the serverless momentum, assume that a <a href="https://aws.amazon.com/lambda/" class="link" target="_blank" rel="noopener noreferrer">Lambda function</a> polls the queue and does something with the message.

We seem to have two options.

### 2.1. Subscribe to the topic from the SNS page

We select the topic and choose **Create subscription** in the **Subscriptions** section. Select **Amazon SQS** for **Protocol**, specify the <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html" class="link" target="_blank" rel="noopener noreferrer">ARN</a> of the queue, and we should be good to go.

Well, not really. Chances are that it will not work. At the end of a long day, one can spend precious minutes (hours) debugging why the Lambda function is not running after we have published a message on the topic.

The reason is the SNS will not add the relevant permissions to the SQS queue's **access policy**. The access policy is a <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_identity-vs-resource.html" class="link" target="_blank" rel="noopener noreferrer">resource-based policy</a>, and it must contain the **principal** element that specifies who or which service can send messages to the queue. SNS is not an identity, so we should use the access policy here.

By default, the access policy of the queue `test-queue` looks like this:

```json
{
  "Version": "2012-10-17",
  "Id": "__default_policy_ID",
  "Statement": [
    {
      "Sid": "__owner_statement",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": "SQS:*",
      "Resource": "arn:aws:sqs:eu-central-1:123456789012:test-queue"
    }
  ]
}
```

We might first think that the policy should suffice because it gives the account full permissions on the queue. (Account and `root` user are the same when specified in the `Principal` element.) But this policy only delegates authority to the account, and **will not give permission** to the SNS topic. We still need to ensure that the SQS access policy **explicitly allows** the topic to send messages to the queue.

The problem is that the Console will create the subscription as expected. We can find it under the **Subscriptions** section, but the SQS access policy will not receive permission. If we forget about the mandatory explicit permission requirements in AWS, we can scratch our heads and stare at the monitor thinking why our simple architecture is not working.

I haven't seen this issue with other protocols, and it works well with a direct Lambda or email subscription.

### 2.2. Try from the SQS side

Luckily the Console allows us to subscribe `test-queue` to the topic from the SQS service page, too.

The process is very similar. We click on `test-queue`, and then **SNS subscriptions**.

![Subscribe an SQS queue to a topic](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8takf5f7efid80wk4kfd.png)

When we click **Subscribe to Amazon SNS topic**, we will select the topic from the dropdown, and done!

It **will** work, because the queue's access policy will contain the following statement:

```json
{
  "Sid": "topic-subscription-arn:aws:sns:eu-central-1:123456789012:test-sns-topic",
  "Effect": "Allow",
  "Principal": {
    "AWS": "*"
  },
  "Action": "SQS:SendMessage",
  "Resource": "arn:aws:sqs:eu-central-1:123456789012:test-queue",
  "Condition": {
    "ArnLike": {
      "aws:SourceArn": "arn:aws:sns:eu-central-1:123456789012:test-sns-topic"
    }
  }
}
```

This statement allows `test-sns-topic` to `SendMessage`s to `test-queue. This permission was missing from the access policy when we tried to add the subscription from the SNS service page.

## 3. Summary

Everything in AWS is about permissions.

When we want to add an SQS queue as a subscriber to an SNS topic in the Console, we can do it in one of two ways. The subscription process will not always add the necessary permissions to the access policy of the queue. This way, it will not receive the messages we publish on the topic.

But we can perform the same action from the SQS service page. The permission will be there, and the flow will work as expected.

## 4. Further reading

<a href="https://docs.aws.amazon.com/sns/latest/dg/sns-create-topic.html" class="link" target="_blank" rel="noopener noreferrer">Creating an Amazon SNS topic</a> - Step-by-step guide to create an SNS topic

<a href="https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/step-create-queue.html" class="link" target="_blank" rel="noopener noreferrer">Create a queue (console)</a> - Same for SQS queues