How to Create AWS SNS Topic Policy using CloudFormation

How to Create AWS SNS Topic Policy using CloudFormation
Sharing is Caring:

How to Create AWS SNS Topic Policy using CloudFormation

Dear reader, I hope you are doing great. In one of my previous post, I explained how to use CloudFormation to create SNS topic and subscription.

In today’s post, I am here to help you create SNS Topic Policy using CloudFormation. By the end of this tutorial, you should be able to apply an access policy or topic policy to an SNS topic(or list of topics) using CloudFormation.

Let’s start with understanding amazon SNS Topic Policy !!!

What is Amazon SNS Topic Policy?

Amazon SNS Topic Policy or Access Policy is a resource bases policy which gets applied on an SNS topic resource. It basically defines who can publish or subscribe or do other actions to your topic.

Just to let you know, Amazon SNS adds a default policy to all the newly created topic and it looks like below-

{
  "Version": "2008-10-17",
  "Id": "__default_policy_ID",
  "Statement": [
    {
      "Sid": "__default_statement_ID",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": [
        "SNS:GetTopicAttributes",
        "SNS:SetTopicAttributes",
        "SNS:AddPermission",
        "SNS:RemovePermission",
        "SNS:DeleteTopic",
        "SNS:Subscribe",
        "SNS:ListSubscriptionsByTopic",
        "SNS:Publish"
      ],
      "Resource": "arn:aws:sns:ap-south-1:123456789012:test",
      "Condition": {
        "StringEquals": {
          "AWS:SourceOwner": "123456789012"
        }
      }
    }
  ]
}

If you look closely on above policy, you will see by default only the topic owner can publish or subscribe to the topic.

This is the default policy. However, you can change it as per your requirement. Here are few example use-cases of SNS topic policies: SNS topic policy use-cases

When to use SNS Access Policy?

Ideally, you can use IAM policies or SNS access policy or both to provide permission to your users to be able to access your topics . However, SNS access policy or topic policy comes really handy, when it comes to giving cross account access to your topic.

For example- you can create an access policy on your topic in Account A to allow another account B to publish and subscribe to topic in Account A.

Alright?

Okay !!!

I guess, you have got an idea about SNS topic policies. So can we go ahead and see how to create an SNS Topic Policy using CloudFormation?

Let’s start 🙂

Steps to Create AWS SNS Topic Policy using CloudFormation?

  1. Provide proper permission to your user/role
  2. Prepare policy for your use-case
  3. Prepare the template
  4. Create a stack using prepared template
  5. Validate the applied policy in SNS console

Let’s see the step by step instruction to create AWS SNS topic policy using CloudFormation.

Step 1: Provide proper permission to your user/role

  • If you are not an admin user, you should explicitly provide these permission for your user/role that will be used to create this CloudFormation stack.
    • sns:CreateTopic
    • sns:DeleteTopic
    • sns:SetTopicAttributes
  • Additionally, the user will also need cloudformation:* to be able to do CloudFormation stack creation, updation , deletion etc.

Important Note: If you are unable to figure out correct permission in the beginning, you can use sns:*. However, keep in mind that, it’s not safe to allow all action and you should only use it till you find correct set of permission.

Step 2: Prepare policy for your use-case

Once you have proper permission, It’s time to prepare the policy that you want to apply to your SNS topic. You can either craft permission yourself or go to Policy Generator to generate a policy using GUI.

Use-case that we will implement is to allow a user to be able to publish and subscribe on specified topic.

Go to Policy Generator –> Select Policy Type as SNS Topic Policy –> Provide Permission Details –> Click Add Statement –> Generate Policy

Permission/Statement Details:

  • Effect : Allow
  • Principal: arn:aws:iam::123456789012:user/username
  • AWS Service: Amazon SNS(Preselected)
  • Actions:
    • Publish
    • Subscribe
  • Amazon Resource Name(ARN): arn:aws:sns:ap-south-1:123456789012:topicname
How to Create AWS SNS Topic Policy using CloudFormation

And you will have a policy like-

{
  "Id": "Policy1643807614413",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1643807474528",
      "Action": [
        "sns:Publish",
        "sns:Subscribe"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:sns:ap-south-1:123456789012:test",
      "Principal": {
        "AWS": [
          "arn:aws:iam::123456789012:user/test"
        ]
      }
    }
  ]
}

This policy allows specified actions to user test which has ARN like below-

arn:aws:iam::123456789012:user/test

You may decide to give permission to other accounts. In that case you can mention the principal like below.

 "Principal": {
        "AWS": "123456789012"
 }

Important Note: Please note that in above policy, I have specified dummy account Id and username due to security reasons. Please make sure to use correct one otherwise your policy creation will fail with Invalid parameter: Policy Error: PrincipalNotFound error

Step 3: Prepare the template

You can use YAML or JSON for your template. I prefer YAML for writing my templates. But don’t worry, If you want it in JSON, I will provide JSON template as well.

To apply a topic policy or access policy to an SNS topic, we use AWS::SNS::TopicPolicy resource.

Type: AWS::SNS::TopicPolicy
Properties: 
  PolicyDocument: Json
  Topics: 
    - String

Explanation –

  • PolicyDocument is the actual policy that you want to apply to topic
  • Topics parameter takes the ARN of all the topics to which you want to add the policy

Note: If you are defining the topic in the same template like me, use !Ref as using !Ref on topic returns topic ARN.

Template to Create AWS SNS Topic Policy using CloudFormation : YAML

In this template, we are creating an SNS named demo-topic. After the creation of topic, we are applying a policy to the same topic to allow user test to publish and subscribe to the topic.

AWSTemplateFormatVersion: 2010-09-09
Description: AWS CloudFormation Template to create an SNS topic and apply an access policy

Parameters:
  TopicName:
    Type: String
    Description: Topic Name
    Default: demo-topic
  UserArn:
    Type: String
    Description: User to which SNS will allow perfoming actions
    Default: arn:aws:iam::123456789012:user/test
  Email:
    Type: String
    Description: EmailId
    Default: contact@cloudkatha.com

  

Resources:
  DemoTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: TestTopic
      Subscription:
      - Endpoint: !Ref Email
        Protocol: email

  DemoTopicPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties:
      PolicyDocument:
        Id: MyDemoTopicPolicy
        Version: '2012-10-17'
        Statement:
          - Sid: Stmt1643807474528
            Effect: Allow
            Principal:
              AWS: !Ref UserArn
            Action:
              - sns:Publish
              - sns:Subscribe
            Resource: !Ref DemoTopic
      Topics:
        - !Ref DemoTopic

Note: When you want to apply policy to multiple topic, make your Topics parameter like below. Also, you can use your existing topics as well. All you need is the ARN of existing topic.

Topics:
  - !Ref DemoTopic
  - !Ref AnotherTopic
  - arn:aws:sns:ap-south-1:123456789012:existingtopic

Template to Create AWS SNS Topic Policy using CloudFormationJSON

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "AWS CloudFormation Template to create an SNS topic and apply an access policy",
    "Parameters": {
        "TopicName": {
            "Type": "String",
            "Description": "Topic Name",
            "Default": "demo-topic"
        },
        "UserArn": {
            "Type": "String",
            "Description": "User to which SNS will allow perfoming actions",
            "Default": "arn:aws:iam::123456789012:user/test"
        },
        "Email": {
            "Type": "String",
            "Description": "EmailId",
            "Default": "contact@cloudkatha.com"
        }
    },
    "Resources": {
        "DemoTopic": {
            "Type": "AWS::SNS::Topic",
            "Properties": {
                "TopicName": "TestTopic",
                "Subscription": [
                    {
                        "Endpoint": {
                            "Ref": "Email"
                        },
                        "Protocol": "email"
                    }
                ]
            }
        },
        "DemoTopicPolicy": {
            "Type": "AWS::SNS::TopicPolicy",
            "Properties": {
                "PolicyDocument": {
                    "Id": "MyDemoTopicPolicy",
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Sid": "Stmt1643807474528",
                            "Effect": "Allow",
                            "Principal": {
                                "AWS": {
                                    "Ref": "UserArn"
                                }
                            },
                            "Action": [
                                "sns:Publish",
                                "sns:Subscribe"
                            ],
                            "Resource": {
                                "Ref": "DemoTopic"
                            }
                        }
                    ]
                },
                "Topics": [
                    {
                        "Ref": "DemoTopic"
                    }
                ]
            }
        }
    }
}

Step 4: Create the Stack using prepared template

Now, we know the basics and we have the template so let’s go and create the stack.

  1. Grab the YAML or JSON template from above as per your convenience.
  2. Change the parameters as per your requirement specially change the user to actual user or principal you want you SNS access policy to apply
  3. Save the template with .yml or .json as per the choice of template and follow below steps.
  4. Login to AWS Management Console, navigate to CloudFormation and click on Create stack
  5. Click on “Upload a template file”, upload your saved .yml  or .json file and click Next
  6. Enter the stack name and click on Next. In configuration, keep everything as default and click on Next.
  7. In the events tab of stack, you can view the status. Once, successful, we will verify the policy
How to Create AWS SNS Topic Policy using CloudFormation 1

Step 5: Validate the applied policy in SNS console

Go to SNS, Click on your topic name

Go to Access Policy tab

You should be able to see the applied policy like below.

How to Create AWS SNS Topic Policy using CloudFormation Verified

Congratulations !!!

You have successfully applied the access policy to your topic.

Clean Up

If you are creating this SNS topic and access policy for learning purpose, don’t forget to delete your CloudFormation stack, so that your topic is deleted and you don’t bear any cost.

Happy Learning !!!

Conclusion:

In this post, we learnt how to create amazon SNS topic policy using CloudFormation.

  • We started with figuring out correct set of permission.
  • Then we prepared policy for our usecase
  • After that, we crafted the CloudFormation Template
  • We created the stack and verified the applied policy in SNS console.

I hope you found this post helpful.

Enjoyed the content?

Subscribe to our newsletter below to get awesome AWS learning materials delivered straight to your inbox.

Don’t forget to motivate me by-

Suggested Read:

Sharing is Caring:

Leave a Reply

Your email address will not be published.