Search code examples
terraformamazon-sns

AWS related questions with terraform: unable to create s3 bucket notification to AWS SNS


I am getting the following error when performing terraform apply:

Error: creating S3 Bucket (aws-solution-associate) Notification: operation error S3: PutBucketNotificationConfiguration, https response error StatusCode: 400, RequestID: VPV6DW8AMS2NS31S, HostID: QavFpP5mW+8RR8nexKcwwsytg+2gXe3cwAuyQqv9GzpD8OMIXZT8Y9EDHMtN+WZwC8lhAqFwkcA=, api error InvalidArgument: Unable to validate the following destination configurations
with aws_s3_bucket_notification.s3_sns_notification,
on main.tf line 249, in resource "aws_s3_bucket_notification" "s3_sns_notification":
249: resource "aws_s3_bucket_notification" "s3_sns_notification" {

I am not sure what went wrong and the error message is not helpful at all. Need someone advise please

Please refer to my terraform script below:

terraform{
    backend "s3" {
      bucket = "aws-solution-associate"
      key = "lab4-create_sns_sqs"
      region = "us-east-1"
    }
}


provider "aws" {
    region = "us-east-1"
}

# Inject caller ID for being able to use the account ID
data "aws_caller_identity" "current" {}


resource "aws_sns_topic" "resize-image-topic" {
  name = "resize-image-topic-1451"
  policy = data.aws_iam_policy_document.sns-topic-policy.json
  
}


resource "aws_sqs_queue" "thumbnail-queue" {
  name = "thumbnail-queue"
  policy = data.aws_iam_policy_document.sqs-queue-policy-thumbnail-queue.json
}

resource "aws_sns_topic_subscription" "resize-image-topic-sub-1" {
  topic_arn = aws_sns_topic.resize-image-topic.arn
  protocol  = "sqs"
  endpoint = aws_sqs_queue.thumbnail-queue.arn
}

resource "aws_sqs_queue" "web-queue" {
  name = "web-queue"
  policy = data.aws_iam_policy_document.sqs-queue-policy-web-queue.json
}


resource "aws_sns_topic_subscription" "resize-image-topic-sub-2" {
  topic_arn = aws_sns_topic.resize-image-topic.arn
  protocol  = "sqs"
  endpoint = aws_sqs_queue.web-queue.arn
}

resource "aws_sqs_queue" "mobile-queue" {
  name = "mobile-queue"
  policy = data.aws_iam_policy_document.sqs-queue-policy-mobile-queue.json
}


resource "aws_sns_topic_subscription" "resize-image-topic-sub-3" {
  topic_arn = aws_sns_topic.resize-image-topic.arn
  protocol  = "sqs"
  endpoint = aws_sqs_queue.mobile-queue.arn
}

# Create a topic policy. This will allow for the SQS queue to be able to subscribe to the topic
data "aws_iam_policy_document" "sns-topic-policy" {
  
  statement {

    sid = "lab4-sns-topic-policy-sqs"
    effect = "Allow"
    principals {
      type        = "AWS"
      identifiers = ["*"]
    }

    actions = [
      "SNS:GetTopicAttributes",
      "SNS:SetTopicAttributes",
      "SNS:AddPermission",
      "SNS:RemovePermission",
      "SNS:DeleteTopic",
      "SNS:Subscribe",
      "SNS:ListSubscriptionsByTopic",
      "SNS:Publish",
      "SNS:Receive"
    ]

    condition {
      test     = "StringLike"
      variable = "SNS:Endpoint"

      # In order to avoid circular dependencies, we must create the ARN ourselves
      values = [
        "arn:aws:sqs:${var.region}:${data.aws_caller_identity.current.account_id}:mobile-queue",
        "arn:aws:sqs:${var.region}:${data.aws_caller_identity.current.account_id}:thumbnail-queue",
        "arn:aws:sqs:${var.region}:${data.aws_caller_identity.current.account_id}:web-queue",
      ]
    }

    resources = [
      "arn:aws:sns:${var.region}:${data.aws_caller_identity.current.account_id}:resize-image-topic-1451"
    ]

  }

 statement {

    sid = "lab4-sns-topic-policy-s3"
    effect = "Allow"
    principals {
      type = "Service"
      identifiers = ["s3.amazonaws.com"]
    }

    actions = [
      "SNS:Publish",
    ]

    condition {
      test     = "StringEquals"
      variable = "AWS:SourceAccount"
      values   = ["arn:aws:sns:${var.region}:${data.aws_caller_identity.current.account_id}:resize-image-topic-1451"]
    }

    resources = [
      "arn:aws:sns:${var.region}:${data.aws_caller_identity.current.account_id}:resize-image-topic-1451"
    ]

  }

}

# Create a queue policy. This allows for the SNS topic to be able to publish messages to the SQS queue
data "aws_iam_policy_document" "sqs-queue-policy-mobile-queue" {
  policy_id = "arn:aws:sqs:${var.region}:${data.aws_caller_identity.current.account_id}:mobile-queue/SQSDefaultPolicy"

  statement {
    sid    = "example-sns-topic"
    effect = "Allow"

    principals {
      type        = "AWS"
      identifiers = ["*"]
    }

    actions = [
      "SQS:SendMessage",
    ]

    resources = [
        "arn:aws:sqs:${var.region}:${data.aws_caller_identity.current.account_id}:mobile-queue",
    ]

    condition {
      test     = "ArnEquals"
      variable = "aws:SourceArn"

      values = [
        "arn:aws:sns:${var.region}:${data.aws_caller_identity.current.account_id}:resize-image-topic-1451"
      ]
    }
  }
}

# Create a queue policy. This allows for the SNS topic to be able to publish messages to the SQS queue
data "aws_iam_policy_document" "sqs-queue-policy-thumbnail-queue" {
  policy_id = "arn:aws:sqs:${var.region}:${data.aws_caller_identity.current.account_id}:thumbnail-queue/SQSDefaultPolicy"

  statement {
    sid    = "example-sns-topic"
    effect = "Allow"

    principals {
      type        = "AWS"
      identifiers = ["*"]
    }

    actions = [
      "SQS:SendMessage",
    ]

    resources = [
        "arn:aws:sqs:${var.region}:${data.aws_caller_identity.current.account_id}:thumbnail-queue",
    ]

    condition {
      test     = "ArnEquals"
      variable = "aws:SourceArn"

      values = [
        "arn:aws:sns:${var.region}:${data.aws_caller_identity.current.account_id}:resize-image-topic-1451"
      ]
    }
  }
}

# Create a queue policy. This allows for the SNS topic to be able to publish messages to the SQS queue
data "aws_iam_policy_document" "sqs-queue-policy-web-queue" {
  policy_id = "arn:aws:sqs:${var.region}:${data.aws_caller_identity.current.account_id}:web-queue/SQSDefaultPolicy"

  statement {
    sid    = "example-sns-topic"
    effect = "Allow"

    principals {
      type        = "AWS"
      identifiers = ["*"]
    }

    actions = [
      "SQS:SendMessage",
    ]

    resources = [
        "arn:aws:sqs:${var.region}:${data.aws_caller_identity.current.account_id}:web-queue",
    ]

    condition {
      test     = "ArnEquals"
      variable = "aws:SourceArn"

      values = [
        "arn:aws:sns:${var.region}:${data.aws_caller_identity.current.account_id}:resize-image-topic-1451"
      ]
    }
  }
}

data "aws_s3_bucket" "s3_sns" {
  bucket = "aws-solution-associate"
}

data "aws_iam_policy_document" "s3_bucket_to_sns_topic_policy" {
  statement {
    sid       = "AllowSNSPublish"
    effect    = "Allow"
    actions   = ["s3:PutObject"]
    resources = ["arn:aws:s3:::aws-solution-associate/*"]

    condition {
      test     = "StringEquals"
      variable = "aws:SourceArn"
      values   = ["arn:aws:sns:${var.region}:${data.aws_caller_identity.current.account_id}:resize-image-topic-1451"]
    }
  }
}

resource "aws_s3_bucket_policy" "bucket_policy" {
  bucket = data.aws_s3_bucket.s3_sns.id
  policy = data.aws_iam_policy_document.s3_bucket_to_sns_topic_policy.json
}

resource "aws_s3_bucket_notification" "s3_sns_notification" {
  bucket = data.aws_s3_bucket.s3_sns.id

  topic {
    topic_arn = "arn:aws:sns:${var.region}:${data.aws_caller_identity.current.account_id}:resize-image-topic-1451"
    events    = ["s3:ObjectCreated:*"]
    filter_suffix = ".jpg"
    filter_prefix = "ingest/"
  }
  depends_on = [ data.aws_s3_bucket.s3_sns ]
}

I initially thought that the access policy was not granted to the S3 bucket and only to realise the error still persist after I granted S3 bucket to access the SNS


Solution

  • I am not sure why the dependencies was overly focused. I realise that the issue was because the S3 arn is not being specified in the statement with the action as publish.

    # Create a topic policy. This will allow for the SQS queue to be able to subscribe to the topic
    data "aws_iam_policy_document" "sns-topic-policy" {
      
      statement {
    
        sid = "lab4-sns-topic-policy-sqs"
        effect = "Allow"
        principals {
          type        = "AWS"
          identifiers = ["*"]
        }
    
        actions = [
          "SNS:GetTopicAttributes",
          "SNS:SetTopicAttributes",
          "SNS:AddPermission",
          "SNS:RemovePermission",
          "SNS:DeleteTopic",
          "SNS:Subscribe",
          "SNS:ListSubscriptionsByTopic",
          "SNS:Publish",
          "SNS:Receive"
        ]
    
        condition {
          test     = "StringLike"
          variable = "SNS:Endpoint"
    
          # In order to avoid circular dependencies, we must create the ARN ourselves
          values = [
            "arn:aws:sqs:${var.region}:${data.aws_caller_identity.current.account_id}:mobile-queue",
            "arn:aws:sqs:${var.region}:${data.aws_caller_identity.current.account_id}:thumbnail-queue",
            "arn:aws:sqs:${var.region}:${data.aws_caller_identity.current.account_id}:web-queue",
          ]
        }
    
        resources = [
          "arn:aws:sns:${var.region}:${data.aws_caller_identity.current.account_id}:resize-image-topic-1451"
        ]
    
      }
    
     statement {
    
        sid = "lab4-sns-topic-policy-s3"
        effect = "Allow"
        principals {
          type = "Service"
          identifiers = ["s3.amazonaws.com"]
        }
    
        actions = [
          "SNS:Publish",
        ]
    
        condition {
          test     = "StringEquals"
          variable = "AWS:SourceAccount"
          values   = ["arn:aws:sns:${var.region}:${data.aws_caller_identity.current.account_id}:resize-image-topic-1451"] #This should be changed to refer to the S3 bucket
        }
    
        resources = [
          "arn:aws:sns:${var.region}:${data.aws_caller_identity.current.account_id}:resize-image-topic-1451"
        ]
    
      }
    
    }