Search code examples
amazon-web-servicesamazon-s3aws-cloudformationamazon-sns

Create an S3 bucket that sends notification to SNS topic


I am trying to create a s3 bucket that sends notification to a SNS topic every time an object is dropped in the s3 bucket. My S3 bucket is called foo-bucket and my SNS topic is called foo-topic. I know how to setup this in aws console but i am having trouble when trying to do this via cloudformation.

This is the code i currently have

Resources:
  SNSTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: foo-topic
  SNSTopicPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties:
      PolicyDocument:
        Id: MyTopicPolicy
        Version: '2012-10-17'
        Statement:
        - Sid: Statement-id
          Effect: Allow
          Principal:
            Service: s3.amazonaws.com
          Action: sns:Publish
          Resource:
            Ref: SNSTopic
          Condition:
            ArnLike:
              aws:SourceArn:
                Fn::Join:
                - ''
                - - 'arn:aws:s3:::'
                  - Ref: S3Bucket
      Topics:
      - Ref: SNSTopic
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: foo-bucket 
      AccessControl: BucketOwnerFullControl
      NotificationConfiguration:
        TopicConfigurations:
        - Topic:
            Ref: SNSTopic
          Event: s3:ObjectCreated:Put

I try to deploy the above and cfn rollsback due to the following error

Unable to validate the following destination configurations (Service: Amazon S3; Status Code: 400; Error Code: InvalidArgument; Request ID: fooooo; S3 Extended Request ID: foooid; Proxy: null)


Solution

  • I have an example cloudformation creating a bucket, sns topic and a notification configuration. As already mentioned, you need to ensure proper dependency order.

    The notification configuration doesn't check for the resource existence, so we need to use the DependsOn property to do so

    As well be aware of potential circular reference, when creating an SNS Topic Policy. I defined the bucket name as a string, not reference. It allows to create an SNS with its policy before the notification config of the bucket.

      IngestionBucketDev:
        Type: AWS::S3::Bucket
        DependsOn:
         - IngestionTopicDev
         - IngestionTopicPolicy
        Properties: 
          BucketName: "ingestion-codebucket-7832df8b-dev"
          NotificationConfiguration:
            TopicConfigurations:
             -  Topic: !Ref IngestionTopicDev
                Event: 's3:ObjectCreated:*'
                Filter:
                  S3Key:
                    Rules:
                     - Name: suffix
                       Value: ".json"
          PublicAccessBlockConfiguration:
            RestrictPublicBuckets: true
            BlockPublicPolicy: true
               
                   
      IngestionTopicDev:
        Type: AWS::SNS::Topic
        Properties: 
          TopicName: "elearn-ingest-topic"
          DisplayName: "elearn-ingest-topic"
          
      IngestionTopicPolicy:
        Type: AWS::SNS::TopicPolicy
        Properties: 
          Topics:
           - !Ref IngestionTopicDev
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Action:
                  - 'sns:Publish'
                Effect: Allow
                Resource: !Ref IngestionTopicDev
                Principal: 
                  Service: "s3.amazonaws.com"
                Condition:
                  ArnEquals:
                   "aws:SourceArn": "arn:aws:s3:::ingestion-codebucket-7832df8a-dev"