Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNS Data Protection Policy #30008

Merged
merged 19 commits into from
Mar 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/30008.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_sns_topic_data_protection_policy
```
4 changes: 4 additions & 0 deletions internal/service/sns/service_package_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

126 changes: 126 additions & 0 deletions internal/service/sns/topic_data_protection_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package sns

import (
"context"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/sns"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
)

// @SDKResource("aws_sns_topic_data_protection_policy")
func ResourceTopicDataProtectionPolicy() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceTopicDataProtectionPolicyUpsert,
ReadWithoutTimeout: resourceTopicDataProtectionPolicyRead,
UpdateWithoutTimeout: resourceTopicDataProtectionPolicyUpsert,
DeleteWithoutTimeout: resourceTopicDataProtectionPolicyDelete,

Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: verify.ValidARN,
},
"policy": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringIsJSON,
DiffSuppressFunc: verify.SuppressEquivalentPolicyDiffs,
DiffSuppressOnRefresh: true,
StateFunc: func(v interface{}) string {
json, _ := structure.NormalizeJsonString(v)
return json
},
},
},
}
}

func resourceTopicDataProtectionPolicyUpsert(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).SNSConn()

topicArn := d.Get("arn").(string)
policy, err := structure.NormalizeJsonString(d.Get("policy").(string))

if err != nil {
return sdkdiag.AppendErrorf(diags, "policy (%s) is invalid JSON: %s", d.Get("policy").(string), err)
}

input := &sns.PutDataProtectionPolicyInput{
DataProtectionPolicy: aws.String(policy),
ResourceArn: aws.String(topicArn),
}

_, err = conn.PutDataProtectionPolicyWithContext(ctx, input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "creating SNS Data Protection Policy (%s): %s", d.Id(), err)
}

if d.IsNewResource() {
d.SetId(topicArn)
}

return resourceTopicDataProtectionPolicyRead(ctx, d, meta)
}

func resourceTopicDataProtectionPolicyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).SNSConn()

output, err := conn.GetDataProtectionPolicyWithContext(ctx, &sns.GetDataProtectionPolicyInput{
ResourceArn: aws.String(d.Id()),
})

if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, sns.ErrCodeResourceNotFoundException) {
log.Printf("[WARN] SNS Data Protection Policy (%s) not found, removing from state", d.Id())
d.SetId("")
return diags
}

if err != nil {
return sdkdiag.AppendErrorf(diags, "reading SNS Data Protection Policy: %s", err)
}

if output == nil || output.DataProtectionPolicy == nil {
return sdkdiag.AppendErrorf(diags, "reading SNS Data Protection Policy (%s): empty output", d.Id())
}

dataProtectionPolicy := output.DataProtectionPolicy

d.Set("arn", d.Id())
d.Set("policy", dataProtectionPolicy)

return diags
}

func resourceTopicDataProtectionPolicyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).SNSConn()

_, err := conn.PutDataProtectionPolicyWithContext(ctx, &sns.PutDataProtectionPolicyInput{
DataProtectionPolicy: aws.String(""),
ResourceArn: aws.String(d.Get("arn").(string)),
})

if err != nil {
return sdkdiag.AppendErrorf(diags, "deleting SNS Data Protection Policy (%s): %s", d.Id(), err)
}

return diags
}
132 changes: 132 additions & 0 deletions internal/service/sns/topic_data_protection_policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package sns_test

import (
"context"
"fmt"
"regexp"
"testing"

"github.com/aws/aws-sdk-go/service/sns"
sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
tfsns "github.com/hashicorp/terraform-provider-aws/internal/service/sns"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
)

func TestAccSNSTopicDataProtectionPolicy_basic(t *testing.T) {
ctx := acctest.Context(t)
var attributes map[string]string
resourceName := "aws_sns_topic_data_protection_policy.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, sns.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckTopicDataProtectionPolicyDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccTopicDataProtectionPolicyConfig_basic(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckTopicExists(ctx, "aws_sns_topic.test", &attributes),
resource.TestCheckResourceAttrPair(resourceName, "arn", "aws_sns_topic.test", "arn"),
resource.TestMatchResourceAttr(resourceName, "policy", regexp.MustCompile(fmt.Sprintf("\"Sid\":\"%[1]s\"", rName))),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccSNSTopicDataProtectionPolicy_disappears(t *testing.T) {
ctx := acctest.Context(t)
var attributes map[string]string
resourceName := "aws_sns_topic_data_protection_policy.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, sns.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckTopicDataProtectionPolicyDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccTopicDataProtectionPolicyConfig_basic(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckTopicExists(ctx, "aws_sns_topic.test", &attributes),
acctest.CheckResourceDisappears(ctx, acctest.Provider, tfsns.ResourceTopicDataProtectionPolicy(), resourceName),
),
ExpectNonEmptyPlan: true,
},
},
})
}

func testAccCheckTopicDataProtectionPolicyDestroy(ctx context.Context) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := acctest.Provider.Meta().(*conns.AWSClient).SNSConn()

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_sns_topic_data_protection_policy" {
continue
}

_, err := tfsns.GetTopicAttributesByARN(ctx, conn, rs.Primary.ID)

if tfresource.NotFound(err) {
continue
}

if err != nil {
return err
}

return fmt.Errorf("SNS Data Protection Topic Policy %s still exists", rs.Primary.ID)
}

return nil
}
}

func testAccTopicDataProtectionPolicyConfig_basic(rName string) string {
return fmt.Sprintf(`
data "aws_partition" "current" {}

resource "aws_sns_topic" "test" {
name = %[1]q
}

resource "aws_sns_topic_data_protection_policy" "test" {
arn = aws_sns_topic.test.arn
policy = jsonencode(
{
"Description" = "Default data protection policy"
"Name" = "__default_data_protection_policy"
"Statement" = [
{
"DataDirection" = "Inbound"
"DataIdentifier" = [
"arn:${data.aws_partition.current.partition}:dataprotection::aws:data-identifier/EmailAddress",
]
"Operation" = {
"Deny" = {}
}
"Principal" = [
"*",
]
"Sid" = %[1]q
},
]
"Version" = "2021-06-01"
}
)
}
`, rName)
}
64 changes: 64 additions & 0 deletions website/docs/r/sns_topic_data_protection_policy.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
subcategory: "SNS (Simple Notification)"
layout: "aws"
page_title: "AWS: aws_sns_topic_data_protection_policy"
description: |-
Provides an SNS data protection topic policy resource.
---

# Resource: aws_sns_topic_data_protection_policy

Provides an SNS data protection topic policy resource

## Example Usage

```terraform
resource "aws_sns_topic" "example" {
name = "example"
}

resource "aws_sns_topic_data_protection_policy" "example" {
arn = aws_sns_topic.example.arn
policy = jsonencode(
{
"Description" = "Example data protection policy"
"Name" = "__example_data_protection_policy"
"Statement" = [
{
"DataDirection" = "Inbound"
"DataIdentifier" = [
"arn:aws:dataprotection::aws:data-identifier/EmailAddress",
]
"Operation" = {
"Deny" = {}
}
"Principal" = [
"*",
]
"Sid" = "__deny_statement_11ba9d96"
},
]
"Version" = "2021-06-01"
}
)
}
```

## Argument Reference

The following arguments are supported:

* `arn` - (Required) The ARN of the SNS topic
* `policy` - (Required) The fully-formed AWS policy as JSON. For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy).

## Attributes Reference

In addition to all arguments above, the following attributes are exported:

## Import

SNS Data Protection Topic Policy can be imported using the topic ARN, e.g.,

```
$ terraform import aws_sns_topic_data_protection_policy.example arn:aws:sns:us-west-2:0123456789012:example
```