Property Topics cannot be empty - Cloudformation CREATE_FAILED on SNS TopicPolicy

0

I'm trying to build a Cloudformation template using examples I find online. I ran into a dependency issue between S3 and SNS resources which led me to this AWS article:

How do I avoid the "Unable to validate the following destination configurations" error in AWS CloudFormation

Using that as an example I created a parameterized S3 bucket name and SNS TopicPolicy, however on creating the Cloudformation stack I see CREATE_FAILED for the TopicPolicy with status Property Topics cannot be empty. My only attempt at a resolution was to add DependsOn to the TopicPolicy, a property that did not appear in the linked article above.

My best guess is that {"Ref": "TransactionUploadTopic"} in the Topics array is not resolving to the ARN for TransactionUploadTopic, despite it being successfully created in the CF stack (so I don't know why this would be the case.)

My template is below, I'm learning from the AMediaManager Tutorial (GitHub Repo) and other online resources (since my architecture is quite different from the AMM tutorial.)

{
  "AWSTemplateFormatVersion": "2010-09-09",

  "Description": "Provision resource dependencies for the app (e.g., RDS, S3, DynamoDB, etc..).",

  "Parameters": {
    "AppBucketNameSuffix": {
      "Description": "The S3 bucket for user uploads",
      "Type": "String"
    }
  },

  "Resources": {
    "InstanceSecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupDescription": "RDS allows ingress from EC2 instances in this group.",
        "SecurityGroupIngress": []
      }
    },

    "TransactionUploadQueue": {
      "Type": "AWS::SQS::Queue"
    },

    "TransactionUploadTopic": {
      "Type": "AWS::SNS::Topic",
      "Properties": {
        "Subscription": [{
          "Endpoint": {
            "Fn::GetAtt": ["TransactionUploadQueue", "Arn"]
          },
          "Protocol": "sqs"
        }]
      }
    },

    "AppBucket2SNSPolicy": {
      "Type": "AWS::SNS::TopicPolicy",
      "DependsOn": ["TransactionUploadTopic"],
      "Properties": {
        "PolicyDocument": {
          "Id": "S3NotificationPolicy",
          "Version": "2012-10-17",
          "Statement": [
            {
              "Sid": "Statement-id",
              "Effect": "Allow",
              "Principal": {"Service": "s3.amazonaws.com"},
              "Action": "sns:Publish",
              "Resource": {"Ref": "TransactionUploadTopic"},
              "Condition": {
                "ArnLike": {
                  "aws:SourceArn": {"Fn::Join": [ "", [ "arn:aws:s3:::", {"Ref": "AWS::StackName"}, "-", {"Ref": "AppBucketNameSuffix"} ]]}
                }
              }
            }
          ],
          "Topics": [ {"Ref": "TransactionUploadTopic"} ]
        }
      }
    },

    "AppBucket": {
      "Type": "AWS::S3::Bucket",
      "DependsOn": ["AppBucket2SNSPolicy"],
      "Properties": {
        "BucketName": {"Fn::Join": ["-", [{"Ref": "AWS::StackName"}, {"Ref": "AppBucketNameSuffix"}]]},
        "NotificationConfiguration": {
          "TopicConfigurations": [
            {
              "Event": "s3:ObjectCreated:*",
              "Topic": {"Ref": "TransactionUploadTopic"}
            }
          ]
        }
      }
    },

    "TransactionUploadTopic2QueuePolicy": {
      "Type": "AWS::SQS::QueuePolicy",
      "Properties": {
        "Queues": [{
          "Ref": "TransactionUploadQueue"
        }],
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Id": "PublicationPolicy",
          "Statement": [{
            "Sid": "Allow-SNS-SendMessage",
            "Effect": "Allow",
            "Principal": {
              "AWS": "*"
            },
            "Action": ["sqs:SendMessage"],
            "Resource": {
              "Fn::GetAtt": ["TransactionUploadQueue", "Arn"]
            },
            "Condition": {
              "ArnEquals": {
                "aws:SourceArn": {
                  "Ref": "TransactionUploadTopic"
                }
              }
            }
          }]
        }
      }
    },

    "TransactionUploadRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "ec2.amazonaws.com"
                ]
              },
              "Action": [
                "sts:AssumeRole"
              ]
            }
          ]
        },
        "Path": "/",
        "Policies": [{
          "PolicyName": "TransactionUploadPolicy",
          "PolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [{
              "Sid": "1",
              "Effect": "Allow",
              "Action": [
                "s3:Get*",
                "s3:ListBucket",
                "s3:Put*",
                "s3:*MultipartUpload*"
              ],
              "Resource": [{
                "Fn::Join": ["", ["arn:aws:s3:::", {
                  "Ref": "AppBucket"
                }, "/*"]]
              }, {
                "Fn::Join": ["", ["arn:aws:s3:::", {
                  "Ref": "AppBucket"
                }]]
              }]
            }, {
              "Sid": "2",
              "Effect": "Allow",
              "Action": "sns:Publish",
              "Resource": {
                "Ref": "TransactionUploadTopic"
              }
            }, {
              "Sid": "3",
              "Effect": "Deny",
              "Action": [
                "sns:*Permission*",
                "sns:*Delete*",
                "sns:*Remove*",
                "s3:*Policy*",
                "s3:*Delete*"
              ],
              "Resource": "*"
            }]
          }
        }]
      }
    }
  },

  "Outputs": {
    "InstanceSecurityGroup": {
      "Value": {"Ref": "InstanceSecurityGroup"}
    },
    "AppBucket": {
      "Value": { "Ref" : "AppBucket"}
    },
    "TransactionUploadTopic": {
      "Value": { "Ref" : "TransactionUploadTopic" }
    },
    "TransactionUploadQueue": {
      "Value": { "Ref" : "TransactionUploadQueue" }
    },
    "TransactionUploadRoleArn": {
      "Value": { "Fn::GetAtt": ["TransactionUploadRole", "Arn"]}
    }
  }
}
1 Antwort
1
Akzeptierte Antwort

Hi, your nesting is a bit out of whack - "Topics" is inside your policy document unstead of being directly under Properties. BTW I strongly advise using YAML instead of JSON. It's far more readable and supports comments! Cheers.

EXPERTE
beantwortet vor 2 Jahren
  • Good eye on the document structure, thank you!

Du bist nicht angemeldet. Anmelden um eine Antwort zu veröffentlichen.

Eine gute Antwort beantwortet die Frage klar, gibt konstruktives Feedback und fördert die berufliche Weiterentwicklung des Fragenstellers.

Richtlinien für die Beantwortung von Fragen