Description
Ensure that no Amazon SNS topic has an access policy that makes it public. A topic is public when its policy has an Allow statement for any principal ("*" or {"AWS": "*"}) that is not limited by a restrictive condition, such as aws:SourceAccount, aws:SourceOwner or aws:PrincipalAccount set to your account, aws:PrincipalOrgID set to your organization, a specific aws:SourceArn, or an sns:Endpoint condition.
Rationale
A public SNS topic allows anyone, or unknown AWS accounts, to subscribe and receive its messages, to publish spoofed messages that change the behavior of downstream workflows, or to flood the topic, causing outages and extra cost. It also allows cross-account abuse that bypasses expected trust boundaries. Restricting the topic policy to specific principals and the minimum required actions, with conditions such as aws:SourceArn, aws:SourceAccount or aws:PrincipalOrgID, applies least privilege to the topic.
Impact
Prevents unknown principals from subscribing to, publishing to or managing the topic
Protects the confidentiality and integrity of messages and the availability of subscribers
Principals or AWS services in other accounts that rely on the public statement will lose access until they are explicitly allowed
Default Value
The default access policy of a new SNS topic allows all principals only under the condition AWS:SourceOwner equal to the topic owner's account, so a new topic is not public.
Pre-Requisites
IAM permissions: sns:ListTopics, sns:GetTopicAttributes and sns:SetTopicAttributes
A list of the accounts, roles and AWS services that legitimately publish to or subscribe to the topic
Remediation
Test Plan
Console:
Sign in to the AWS Management Console at https://console.aws.amazon.com.
Open the Amazon SNS console and select Topics.
Select a topic and open the Access policy tab.
Check for any statement that:
has "Effect": "Allow",
has "Principal": "*" or "Principal": {"AWS": "*"}, and
has no Condition that limits access to your account, your organization, a specific source ARN or a specific endpoint.
Repeat for each topic in each region in use.
If such a statement exists, follow the implementation steps.
CLI:
List the topics in a region:
aws sns list-topics --region <REGION> --query "Topics[].TopicArn"
Show the attributes of a topic, including its access policy in the Policy attribute:
aws sns get-topic-attributes --region <REGION> --topic-arn <TOPIC_ARN>
A topic fails if any Allow statement has a public principal (*) and either no Condition, or a condition that does not restrict access to your account (aws:SourceAccount, aws:SourceOwner, aws:PrincipalAccount), your organization (aws:PrincipalOrgID), a specific aws:SourceArn or an sns:Endpoint.
Implementation Steps
Console:
Sign in to the AWS Management Console at https://console.aws.amazon.com.
Open the Amazon SNS console and select Topics.
Select the topic and choose Edit.
Expand the Access policy section.
In the JSON editor, for each public statement, either:
replace the "*" principal with the specific account or role ARNs that need access, or
add a condition that limits access, for example "Condition": {"StringEquals": {"aws:SourceAccount": "<ACCOUNT_ID>"}}, or
delete the statement if it is not needed.
Choose Save changes.
Repeat for each affected topic in each region in use.
CLI:
The suggested command grants only sns:Publish and replaces the whole policy, which removes the owner's management permissions, so the policy below restores the owner-account access instead. Add any other statements the topic still needs (for example, for AWS services, with an aws:SourceArn or aws:SourceAccount condition). Save the following as policy.json:
{"Version": "2012-10-17", "Statement": [{"Sid": "OwnerAccountAccess", "Effect": "Allow", "Principal": {"AWS": "arn:aws:iam::<ACCOUNT_ID>:root"}, "Action": ["sns:Publish", "sns:Subscribe", "sns:Receive", "sns:GetTopicAttributes", "sns:SetTopicAttributes", "sns:ListSubscriptionsByTopic", "sns:AddPermission", "sns:RemovePermission", "sns:DeleteTopic"], "Resource": "<TOPIC_ARN>"}]}
Apply the policy to the topic:
aws sns set-topic-attributes --region <REGION> --topic-arn <TOPIC_ARN> --attribute-name Policy --attribute-value file://policy.json
Backout Plan
Before making changes, save the current topic attributes, then copy the value of the Policy attribute (as plain JSON, without the escape characters) into a file named topic-policy-backup.json:
aws sns get-topic-attributes --region <REGION> --topic-arn <TOPIC_ARN> > topic-attributes-backup.json
To roll back:
Sign in to the AWS Management Console at https://console.aws.amazon.com.
Open the Amazon SNS console, select Topics and select the topic.
Choose Edit and expand the Access policy section.
Paste the saved policy into the JSON editor.
Choose Save changes.
CLI:
aws sns set-topic-attributes --region <REGION> --topic-arn <TOPIC_ARN> --attribute-name Policy --attribute-value file://topic-policy-backup.json
Note: rolling back makes the topic public again. Use it only as a temporary measure while the required principals are allowed explicitly.
Reference
https://docs.aws.amazon.com/sns/latest/dg/sns-access-policy-use-cases.html
https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html
https://docs.aws.amazon.com/config/latest/developerguide/sns-topic-policy.html
https://docs.aws.amazon.com/cli/latest/reference/sns/set-topic-attributes.html