Search code examples
amazon-web-servicesamazon-iamamazon-snsaws-access-policy

AWS SNS topic access policy does not prevent from users to subscribe


I have the access policy set up like the below for an SNS topic. I thought I have allowed only the user2 to subscribe to the topic but user1 can subscribe the topic. How can I configure this for what I want to do?

{
  "Version": "2008-10-17",
  "Id": "__default_policy_ID",
  "Statement": [
    {
      "Sid": "__console_pub_0",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::${account_id}:user/user1"
      },
      "Action": "SNS:Publish",
      "Resource": "arn:aws:sns:eu-west-2:${account_id}:topic1"
    },
    {
      "Sid": "__console_sub_0",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::${account_id}:user/user2"
      },
      "Action": [
        "SNS:Subscribe",
        "SNS:Receive"
      ],
      "Resource": "arn:aws:sns:eu-west-2:${account_id}:topic1"
    }
  ]
}

Solution

  • User1 can subscribe because it has an identity-based policy that allows the action (the full SNS permission). If you look at the policy evaluation logic, you'll see that either resource-based policies (the ones you added to the SNS topic) and identity-based policies (the full SNS permissions you added to user1) is enough to allow access.

    When user1 tries to subscribe to the topic, IAM looks at both policies. The topic policy does not apply, but the SNS full access does, so the operation is allowed.

    If you want to make sure that user1 can not subscribe, you can add a Deny policy to the SNS topic:

        {
          "Effect": "Deny",
          "Principal": {
            "AWS": "arn:aws:iam::${account_id}:user/user1"
          },
          "Action": [
            "SNS:Subscribe",
            "SNS:Receive"
          ],
          "Resource": "arn:aws:sns:eu-west-2:${account_id}:topic1"
        }
    

    If you add this statement, when user1 tries to subscribe, IAM will see that there is a matching Deny statement and will reject the request.

    If you want to make sure only user2 can subscribe, you can use a NotPrincipal with a reject:

        {
          "Effect": "Deny",
          "NotPrincipal": {
            "AWS": "arn:aws:iam::${account_id}:user/user2"
          },
          "Action": [
            "SNS:Subscribe",
            "SNS:Receive"
          ],
          "Resource": "arn:aws:sns:eu-west-2:${account_id}:topic1"
        }
    

    This matches all users except user2 and denies subscribing, no matter what other policies they might have.