diff --git a/aws/resource_aws_sns_topic_subscription.go b/aws/resource_aws_sns_topic_subscription.go index 6be9990e225..9e72d5dde4e 100644 --- a/aws/resource_aws_sns_topic_subscription.go +++ b/aws/resource_aws_sns_topic_subscription.go @@ -31,15 +31,45 @@ func resourceAwsSnsTopicSubscription() *schema.Resource { State: schema.ImportStatePassthrough, }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(5 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "protocol": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + "application", + "http", + "https", + "lambda", + "sms", + "sqs", + "email", + "email-json", + }, true), + }, + "endpoint": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "endpoint_auto_confirms": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Deprecated: "endpoint_auto_confirms exists for historical compatibility and should not be used.", "arn": { Type: schema.TypeString, Computed: true, }, "confirmation_timeout_in_minutes": { - Type: schema.TypeInt, - Optional: true, - Default: 1, + Type: schema.TypeInt, + Optional: true, + Default: 1, + Deprecated: "confirmation_timeout_in_minutes exists for historical compatibility and should not be used.", }, "confirmation_was_authenticated": { Type: schema.TypeBool, @@ -239,6 +269,14 @@ func resourceAwsSnsTopicSubscriptionRead(d *schema.ResourceData, meta interface{ return nil } +func subscribeToSNSTopic(d *schema.ResourceData, snsconn *sns.SNS) (output *sns.SubscribeOutput, err error) { + protocol := d.Get("protocol").(string) + endpoint := d.Get("endpoint").(string) + topic_arn := d.Get("topic_arn").(string) + attributes := getResourceAttributes(d) + + log.Printf("[DEBUG] SNS create topic subscription: %s (%s) @ '%s'", endpoint, protocol, topic_arn) + func resourceAwsSnsTopicSubscriptionUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).snsconn @@ -261,6 +299,27 @@ func resourceAwsSnsTopicSubscriptionUpdate(d *schema.ResourceData, meta interfac } } + log.Printf("[DEBUG] Finished subscribing to topic %s with subscription arn %s", topic_arn, *output.SubscriptionArn) + + if subscriptionHasPendingConfirmation(output.SubscriptionArn) { + + log.Printf("[DEBUG] SNS create topic subscription is pending so fetching the subscription list for topic : %s (%s) @ '%s'", endpoint, protocol, topic_arn) + + err = resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { + + subscription, err := findSubscriptionByNonID(d, snsconn) + + if err != nil { + return resource.NonRetryableError(err) + } + + if subscription == nil { + return resource.RetryableError(fmt.Errorf("Endpoint (%s) did not confirm the subscription for topic %s", endpoint, topic_arn)) + } + + output.SubscriptionArn = subscription.SubscriptionArn + return nil + }) if d.HasChange("delivery_policy") { if err := snsSubscriptionAttributeUpdate(conn, d.Id(), "DeliveryPolicy", d.Get("delivery_policy").(string)); err != nil { return err diff --git a/website/docs/r/sns_topic_subscription.html.markdown b/website/docs/r/sns_topic_subscription.html.markdown index e7bb4a6885e..b046aa2de6b 100644 --- a/website/docs/r/sns_topic_subscription.html.markdown +++ b/website/docs/r/sns_topic_subscription.html.markdown @@ -20,6 +20,7 @@ Provides a resource for subscribing to SNS topics. Requires that an SNS topic ex ~> **NOTE:** You cannot unsubscribe to a subscription that is pending confirmation. If you use `email`, `email-json`, or `http`/`https` (without auto-confirmation enabled), until the subscription is confirmed (e.g., outside of Terraform), AWS does not allow Terraform to delete / unsubscribe the subscription. If you `destroy` an unconfirmed subscription, Terraform will remove the subscription from its state but the subscription will still exist in AWS. However, if you delete an SNS topic, SNS [deletes all the subscriptions](https://docs.aws.amazon.com/sns/latest/dg/sns-delete-subscription-topic.html) associated with the topic. Also, you can import a subscription after confirmation and then have the capability to delete it. + ## Example Usage You can directly supply a topic and ARN by hand in the `topic_arn` property along with the queue ARN: @@ -52,6 +53,11 @@ resource "aws_sns_topic_subscription" "user_updates_sqs_target" { You can subscribe SNS topics to SQS queues in different Amazon accounts and regions: +-> NOTE: +Terraform must be run on each account individually. +SQS in account `222222222222` and region `us-east-1` +SNS topic and Subscription in account `111111111111` and region `us-west-1` + ```terraform variable "sns" { default = { @@ -91,57 +97,15 @@ data "aws_iam_policy_document" "sns-topic-policy" { test = "StringEquals" variable = "AWS:SourceOwner" - values = [ - var.sns["account-id"], - ] - } - - effect = "Allow" - - principals { - type = "AWS" - identifiers = ["*"] - } +### SQS Queue (Account Id: 222222222222 / Region: us-east-1) - resources = [ - "arn:aws:sns:${var.sns["region"]}:${var.sns["account-id"]}:${var.sns["name"]}", - ] - - sid = "__default_statement_ID" - } - - statement { - actions = [ - "SNS:Subscribe", - "SNS:Receive", - ] - - condition { - test = "StringLike" - variable = "SNS:Endpoint" - - values = [ - "arn:aws:sqs:${var.sqs["region"]}:${var.sqs["account-id"]}:${var.sqs["name"]}", - ] - } - - effect = "Allow" - - principals { - type = "AWS" - identifiers = ["*"] - } - - resources = [ - "arn:aws:sns:${var.sns["region"]}:${var.sns["account-id"]}:${var.sns["name"]}", - ] - - sid = "__console_sub_0" - } +```hcl +resource "aws_sqs_queue" "this" { + name = "example-sqs-queue" } data "aws_iam_policy_document" "sqs-queue-policy" { - policy_id = "arn:aws:sqs:${var.sqs["region"]}:${var.sqs["account-id"]}:${var.sqs["name"]}/SQSDefaultPolicy" + policy_id = "${aws_sqs_queue.this.arn}/SQSDefaultPolicy" statement { sid = "example-sns-topic" @@ -157,7 +121,7 @@ data "aws_iam_policy_document" "sqs-queue-policy" { ] resources = [ - "arn:aws:sqs:${var.sqs["region"]}:${var.sqs["account-id"]}:${var.sqs["name"]}", + aws_sqs_queue.this.arn ] condition { @@ -165,94 +129,70 @@ data "aws_iam_policy_document" "sqs-queue-policy" { variable = "aws:SourceArn" values = [ - "arn:aws:sns:${var.sns["region"]}:${var.sns["account-id"]}:${var.sns["name"]}", + "arn:aws:sns:us-west-1:111111111111:example-sns-topic", ] } } } -# provider to manage SNS topics -provider "aws" { - alias = "sns" - region = var.sns["region"] - - assume_role { - role_arn = "arn:aws:iam::${var.sns["account-id"]}:role/${var.sns["role-name"]}" - session_name = "sns-${var.sns["region"]}" - } -} - -# provider to manage SQS queues -provider "aws" { - alias = "sqs" - region = var.sqs["region"] - - assume_role { - role_arn = "arn:aws:iam::${var.sqs["account-id"]}:role/${var.sqs["role-name"]}" - session_name = "sqs-${var.sqs["region"]}" - } -} - -# provider to subscribe SQS to SNS (using the SQS account but the SNS region) -provider "aws" { - alias = "sns2sqs" - region = var.sns["region"] - - assume_role { - role_arn = "arn:aws:iam::${var.sqs["account-id"]}:role/${var.sqs["role-name"]}" - session_name = "sns2sqs-${var.sns["region"]}" - } +resource "aws_sqs_queue_policy" "this" { + queue_url = aws_sqs_queue.this.id + policy = data.aws_iam_policy_document.sqs-queue-policy.json } +``` -resource "aws_sns_topic" "sns-topic" { - provider = "aws.sns" - name = var.sns["name"] - display_name = var.sns["display_name"] - policy = data.aws_iam_policy_document.sns-topic-policy.json -} +### SNS Topic and Subscription (Account Id: 111111111111 / Region: us-west-1) -resource "aws_sqs_queue" "sqs-queue" { - provider = "aws.sqs" - name = var.sqs["name"] - policy = data.aws_iam_policy_document.sqs-queue-policy.json +```hcl +resource "aws_sns_topic" "this" { + name = "example-sns-topic" } -resource "aws_sns_topic_subscription" "sns-topic" { - provider = "aws.sns2sqs" - topic_arn = aws_sns_topic.sns-topic.arn +resource "aws_sns_topic_subscription" "this" { + topic_arn = aws_sns_topic.this.arn protocol = "sqs" - endpoint = aws_sqs_queue.sqs-queue.arn + endpoint = "arn:aws:sqs:us-east-1:222222222222:example-sqs-queue" } ``` ## Argument Reference -The following arguments are required: +The following arguments are supported: -* `endpoint` - (Required) Endpoint to send data to. The contents vary with the protocol. See details below. -* `protocol` - (Required) Protocol to use. Valid values are: `sqs`, `sms`, `lambda`, `firehose`, and `application`. Protocols `email`, `email-json`, `http` and `https` are also valid but partially supported. See details below. +* `topic_arn` - (Required) The ARN of the SNS topic to subscribe to +* `protocol` - (Required) The protocol to use, see below. Refer to the [SNS API docs](https://docs.aws.amazon.com/sns/latest/api/API_Subscribe.html) for more details. +* `endpoint` - (Required) The endpoint to send data to, the contents will vary with the protocol. (see below for more information) * `subscription_role_arn` - (Required if `protocol` is `firehose`) ARN of the IAM role to publish to Kinesis Data Firehose delivery stream. Refer to [SNS docs](https://docs.aws.amazon.com/sns/latest/dg/sns-firehose-as-subscriber.html). -* `topic_arn` - (Required) ARN of the SNS topic to subscribe to. - -The following arguments are optional: - -* `confirmation_timeout_in_minutes` - (Optional) Integer indicating number of minutes to wait in retrying mode for fetching subscription arn before marking it as failure. Only applicable for http and https protocols. Default is `1`. -* `delivery_policy` - (Optional) JSON String with the delivery policy (retries, backoff, etc.) that will be used in the subscription - this only applies to HTTP/S subscriptions. Refer to the [SNS docs](https://docs.aws.amazon.com/sns/latest/dg/DeliveryPolicies.html) for more details. -* `endpoint_auto_confirms` - (Optional) Whether the endpoint is capable of [auto confirming subscription](http://docs.aws.amazon.com/sns/latest/dg/SendMessageToHttp.html#SendMessageToHttp.prepare) (e.g., PagerDuty). Default is `false`. +* `endpoint_auto_confirms` - (Optional, **DEPRECATED**) Boolean indicating whether the end point is capable of [auto confirming subscription](http://docs.aws.amazon.com/sns/latest/dg/SendMessageToHttp.html#SendMessageToHttp.prepare) e.g., PagerDuty (default is false) +* `confirmation_timeout_in_minutes` - (Optional, **DEPRECATED**) Integer indicating number of minutes to wait in retying mode for fetching subscription arn before marking it as failure. Only applicable for http and https protocols (default is 1 minute). +* `raw_message_delivery` - (Optional) Boolean indicating whether or not to enable raw message delivery (the original message is directly passed, not wrapped in JSON with the original message in the message property) (default is false). * `filter_policy` - (Optional) JSON String with the filter policy that will be used in the subscription to filter messages seen by the target resource. Refer to the [SNS docs](https://docs.aws.amazon.com/sns/latest/dg/message-filtering.html) for more details. -* `raw_message_delivery` - (Optional) Whether to enable raw message delivery (the original message is directly passed, not wrapped in JSON with the original message in the message property). Default is `false`. +* `delivery_policy` - (Optional) JSON String with the delivery policy (retries, backoff, etc.) that will be used in the subscription - this only applies to HTTP/S subscriptions. Refer to the [SNS docs](https://docs.aws.amazon.com/sns/latest/dg/DeliveryPolicies.html) for more details. * `redrive_policy` - (Optional) JSON String with the redrive policy that will be used in the subscription. Refer to the [SNS docs](https://docs.aws.amazon.com/sns/latest/dg/sns-dead-letter-queues.html#how-messages-moved-into-dead-letter-queue) for more details. -### Protocol support +### Timeouts + +Refer to the [AWS SNS docs](https://docs.aws.amazon.com/sns/latest/dg/sns-send-message-to-sqs-cross-account.html) for more details. + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 5 mins) - You should receive a confirmation message at the configured endpoint and validate the subscription. -Supported values for `protocol` include: -* `application` - Delivers JSON-encoded messages. `endpoint` is the endpoint ARN of a mobile app and device. +### Protocols supported + +Supported SNS protocols include: + +* `lambda` -- delivery of JSON-encoded message to a lambda function +* `sqs` -- delivery of JSON-encoded message to an Amazon SQS queue +* `application` -- delivery of JSON-encoded message to an EndpointArn for a mobile app and device * `firehose` - Delivers JSON-encoded messages. `endpoint` is the ARN of an Amazon Kinesis Data Firehose delivery stream (e.g., `arn:aws:firehose:us-east-1:123456789012:deliverystream/ticketUploadStream`). -* `lambda` - Delivers JSON-encoded messages. `endpoint` is the ARN of an AWS Lambda function. -* `sms` - Delivers text messages via SMS. `endpoint` is the phone number of an SMS-enabled device. -* `sqs` - Delivers JSON-encoded messages. `endpoint` is the ARN of an Amazon SQS queue (e.g., `arn:aws:sqs:us-west-2:123456789012:terraform-queue-too`). +* `sms` -- delivery text message +* `http` -- delivery of JSON-encoded messages via HTTP. +* `https` -- delivery of JSON-encoded messages via HTTPS. +* `email` -- delivery of message via SMTP +* `email-json` -- delivery of JSON-encoded message via SMTP Partially supported values for `protocol` include: @@ -280,3 +220,4 @@ SNS Topic Subscriptions can be imported using the `subscription arn`, e.g. ``` $ terraform import aws_sns_topic_subscription.user_updates_sqs_target arn:aws:sns:us-west-2:0123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f ``` +