Merge pull request #8654 from TimeIncOSS/f-aws-sns-policy
provider/aws: Add aws_sns_topic_policy
This commit is contained in:
commit
04c16b8ff1
|
@ -326,6 +326,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"aws_spot_fleet_request": resourceAwsSpotFleetRequest(),
|
||||
"aws_sqs_queue": resourceAwsSqsQueue(),
|
||||
"aws_sns_topic": resourceAwsSnsTopic(),
|
||||
"aws_sns_topic_policy": resourceAwsSnsTopicPolicy(),
|
||||
"aws_sns_topic_subscription": resourceAwsSnsTopicSubscription(),
|
||||
"aws_subnet": resourceAwsSubnet(),
|
||||
"aws_volume_attachment": resourceAwsVolumeAttachment(),
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/service/sns"
|
||||
)
|
||||
|
||||
func resourceAwsSnsTopicPolicy() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsSnsTopicPolicyUpsert,
|
||||
Read: resourceAwsSnsTopicPolicyRead,
|
||||
Update: resourceAwsSnsTopicPolicyUpsert,
|
||||
Delete: resourceAwsSnsTopicPolicyDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"arn": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"policy": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsSnsTopicPolicyUpsert(d *schema.ResourceData, meta interface{}) error {
|
||||
arn := d.Get("arn").(string)
|
||||
req := sns.SetTopicAttributesInput{
|
||||
TopicArn: aws.String(arn),
|
||||
AttributeName: aws.String("Policy"),
|
||||
AttributeValue: aws.String(d.Get("policy").(string)),
|
||||
}
|
||||
|
||||
d.SetId(arn)
|
||||
|
||||
// Retry the update in the event of an eventually consistent style of
|
||||
// error, where say an IAM resource is successfully created but not
|
||||
// actually available. See https://github.com/hashicorp/terraform/issues/3660
|
||||
log.Printf("[DEBUG] Updating SNS Topic Policy: %s", req)
|
||||
stateConf := &resource.StateChangeConf{
|
||||
Pending: []string{"retrying"},
|
||||
Target: []string{"success"},
|
||||
Refresh: resourceAwsSNSUpdateRefreshFunc(meta, req),
|
||||
Timeout: 3 * time.Minute,
|
||||
MinTimeout: 3 * time.Second,
|
||||
}
|
||||
_, err := stateConf.WaitForState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return resourceAwsSnsTopicPolicyRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceAwsSnsTopicPolicyRead(d *schema.ResourceData, meta interface{}) error {
|
||||
snsconn := meta.(*AWSClient).snsconn
|
||||
|
||||
attributeOutput, err := snsconn.GetTopicAttributes(&sns.GetTopicAttributesInput{
|
||||
TopicArn: aws.String(d.Id()),
|
||||
})
|
||||
if err != nil {
|
||||
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NotFound" {
|
||||
log.Printf("[WARN] SNS Topic (%s) not found, error code (404)", d.Id())
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if attributeOutput.Attributes == nil {
|
||||
log.Printf("[WARN] SNS Topic (%q) attributes not found (nil)", d.Id())
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
attrmap := attributeOutput.Attributes
|
||||
|
||||
policy, ok := attrmap["Policy"]
|
||||
if !ok {
|
||||
log.Printf("[WARN] SNS Topic (%q) policy not found in attributes", d.Id())
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
d.Set("policy", policy)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsSnsTopicPolicyDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
accountId, err := getAccountIdFromSnsTopicArn(d.Id())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := sns.SetTopicAttributesInput{
|
||||
TopicArn: aws.String(d.Id()),
|
||||
AttributeName: aws.String("Policy"),
|
||||
// It is impossible to delete a policy or set to empty
|
||||
// (confirmed by AWS Support representative)
|
||||
// so we instead set it back to the default one
|
||||
AttributeValue: aws.String(buildDefaultSnsTopicPolicy(d.Id(), accountId)),
|
||||
}
|
||||
|
||||
// Retry the update in the event of an eventually consistent style of
|
||||
// error, where say an IAM resource is successfully created but not
|
||||
// actually available. See https://github.com/hashicorp/terraform/issues/3660
|
||||
log.Printf("[DEBUG] Resetting SNS Topic Policy to default: %s", req)
|
||||
stateConf := &resource.StateChangeConf{
|
||||
Pending: []string{"retrying"},
|
||||
Target: []string{"success"},
|
||||
Refresh: resourceAwsSNSUpdateRefreshFunc(meta, req),
|
||||
Timeout: 3 * time.Minute,
|
||||
MinTimeout: 3 * time.Second,
|
||||
}
|
||||
_, err = stateConf.WaitForState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAccountIdFromSnsTopicArn(arn string) (string, error) {
|
||||
// arn:aws:sns:us-west-2:123456789012:test-new
|
||||
re := regexp.MustCompile("^arn:aws:sns:[^:]+:([0-9]{12}):.+")
|
||||
matches := re.FindStringSubmatch(arn)
|
||||
if len(matches) != 2 {
|
||||
return "", fmt.Errorf("Unable to get account ID from ARN (%q)", arn)
|
||||
}
|
||||
return matches[1], nil
|
||||
}
|
||||
|
||||
func buildDefaultSnsTopicPolicy(topicArn, accountId string) string {
|
||||
return fmt.Sprintf(`{
|
||||
"Version": "2008-10-17",
|
||||
"Id": "__default_policy_ID",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "__default_statement_ID",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "*"
|
||||
},
|
||||
"Action": [
|
||||
"SNS:GetTopicAttributes",
|
||||
"SNS:SetTopicAttributes",
|
||||
"SNS:AddPermission",
|
||||
"SNS:RemovePermission",
|
||||
"SNS:DeleteTopic",
|
||||
"SNS:Subscribe",
|
||||
"SNS:ListSubscriptionsByTopic",
|
||||
"SNS:Publish",
|
||||
"SNS:Receive"
|
||||
],
|
||||
"Resource": "%s",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"AWS:SourceOwner": "%s"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}`, topicArn, accountId)
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
func TestAccAWSSNSTopicPolicy_basic(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSSNSTopicDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAWSSNSTopicConfig_withPolicy,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSSNSTopicExists("aws_sns_topic.test"),
|
||||
resource.TestMatchResourceAttr("aws_sns_topic_policy.custom", "policy",
|
||||
regexp.MustCompile("^{\"Version\":\"2012-10-17\".+")),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const testAccAWSSNSTopicConfig_withPolicy = `
|
||||
resource "aws_sns_topic" "test" {
|
||||
name = "tf-acc-test-topic-with-policy"
|
||||
}
|
||||
|
||||
resource "aws_sns_topic_policy" "custom" {
|
||||
arn = "${aws_sns_topic.test.arn}"
|
||||
policy = <<POLICY
|
||||
{
|
||||
"Version":"2012-10-17",
|
||||
"Id": "default",
|
||||
"Statement":[{
|
||||
"Sid":"default",
|
||||
"Effect":"Allow",
|
||||
"Principal":{"AWS":"*"},
|
||||
"Action":["SNS:GetTopicAttributes","SNS:SetTopicAttributes","SNS:AddPermission","SNS:RemovePermission","SNS:DeleteTopic"],
|
||||
"Resource":"${aws_sns_topic.test.arn}"
|
||||
}]
|
||||
}
|
||||
POLICY
|
||||
}
|
||||
`
|
|
@ -0,0 +1,49 @@
|
|||
---
|
||||
layout: "aws"
|
||||
page_title: "AWS: sns_topic_policy"
|
||||
sidebar_current: "docs-aws-resource-sns-topic-policy"
|
||||
description: |-
|
||||
Provides an SNS topic policy resource.
|
||||
---
|
||||
|
||||
# aws\_sns\_topic\_policy
|
||||
|
||||
Provides an SNS topic policy resource
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "aws_sns_topic" "test" {
|
||||
name = "my-topic-with-policy"
|
||||
}
|
||||
|
||||
resource "aws_sns_topic_policy" "custom" {
|
||||
arn = "${aws_sns_topic.test.arn}"
|
||||
policy = <<POLICY
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Id": "default",
|
||||
"Statement":[{
|
||||
"Sid": "default",
|
||||
"Effect": "Allow",
|
||||
"Principal": {"AWS":"*"},
|
||||
"Action": [
|
||||
"SNS:GetTopicAttributes",
|
||||
"SNS:SetTopicAttributes",
|
||||
"SNS:AddPermission",
|
||||
"SNS:RemovePermission",
|
||||
"SNS:DeleteTopic"
|
||||
],
|
||||
"Resource": "${aws_sns_topic.test.arn}"
|
||||
}]
|
||||
}
|
||||
POLICY
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `arn` - (Required) The ARN of the SNS topic
|
||||
* `policy` - (Required) The fully-formed AWS policy as JSON
|
|
@ -850,6 +850,10 @@
|
|||
<a href="/docs/providers/aws/r/sns_topic.html">aws_sns_topic</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-sns-topic-policy") %>>
|
||||
<a href="/docs/providers/aws/r/sns_topic_policy.html">aws_sns_topic_policy</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-sns-topic-subscription") %>>
|
||||
<a href="/docs/providers/aws/r/sns_topic_subscription.html">aws_sns_topic_subscription</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue