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

New Resource: aws_s3control_bucket_policy #15575

Merged
merged 5 commits into from
Oct 27, 2020
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,7 @@ func Provider() *schema.Provider {
"aws_s3_bucket_metric": resourceAwsS3BucketMetric(),
"aws_s3_bucket_inventory": resourceAwsS3BucketInventory(),
"aws_s3control_bucket": resourceAwsS3ControlBucket(),
"aws_s3control_bucket_policy": resourceAwsS3ControlBucketPolicy(),
"aws_security_group": resourceAwsSecurityGroup(),
"aws_network_interface_sg_attachment": resourceAwsNetworkInterfaceSGAttachment(),
"aws_default_security_group": resourceAwsDefaultSecurityGroup(),
Expand Down
166 changes: 166 additions & 0 deletions aws/resource_aws_s3control_bucket_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package aws

import (
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/service/s3control"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func resourceAwsS3ControlBucketPolicy() *schema.Resource {
return &schema.Resource{
Create: resourceAwsS3ControlBucketPolicyCreate,
Read: resourceAwsS3ControlBucketPolicyRead,
Update: resourceAwsS3ControlBucketPolicyUpdate,
Delete: resourceAwsS3ControlBucketPolicyDelete,

Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"bucket": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validateArn,
},
"policy": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringIsJSON,
DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs,
},
},
}
}

func resourceAwsS3ControlBucketPolicyCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).s3controlconn

bucket := d.Get("bucket").(string)

input := &s3control.PutBucketPolicyInput{
Bucket: aws.String(bucket),
Policy: aws.String(d.Get("policy").(string)),
}

_, err := conn.PutBucketPolicy(input)

if err != nil {
return fmt.Errorf("error creating S3 Control Bucket Policy (%s): %w", bucket, err)
}

d.SetId(bucket)

return resourceAwsS3ControlBucketPolicyRead(d, meta)
}

func resourceAwsS3ControlBucketPolicyRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).s3controlconn

parsedArn, err := arn.Parse(d.Id())

if err != nil {
return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): %w", d.Id(), err)
}

if parsedArn.AccountID == "" {
return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): unknown format", d.Id())
}

input := &s3control.GetBucketPolicyInput{
AccountId: aws.String(parsedArn.AccountID),
Bucket: aws.String(d.Id()),
}

output, err := conn.GetBucketPolicy(input)

if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, "NoSuchBucket") {
log.Printf("[WARN] S3 Control Bucket Policy (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, "NoSuchBucketPolicy") {
log.Printf("[WARN] S3 Control Bucket Policy (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, "NoSuchOutpost") {
log.Printf("[WARN] S3 Control Bucket Policy (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("error reading S3 Control Bucket Policy (%s): %w", d.Id(), err)
}

if output == nil {
return fmt.Errorf("error reading S3 Control Bucket Policy (%s): empty response", d.Id())
}

d.Set("bucket", d.Id())
d.Set("policy", output.Policy)

return nil
}

func resourceAwsS3ControlBucketPolicyUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).s3controlconn

input := &s3control.PutBucketPolicyInput{
Bucket: aws.String(d.Id()),
Policy: aws.String(d.Get("policy").(string)),
}

_, err := conn.PutBucketPolicy(input)

if err != nil {
return fmt.Errorf("error updating S3 Control Bucket Policy (%s): %w", d.Id(), err)
}

return resourceAwsS3ControlBucketPolicyRead(d, meta)
}

func resourceAwsS3ControlBucketPolicyDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).s3controlconn

parsedArn, err := arn.Parse(d.Id())

if err != nil {
return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): %w", d.Id(), err)
}

input := &s3control.DeleteBucketPolicyInput{
AccountId: aws.String(parsedArn.AccountID),
Bucket: aws.String(d.Id()),
}

_, err = conn.DeleteBucketPolicy(input)

if tfawserr.ErrCodeEquals(err, "NoSuchBucket") {
return nil
}

if tfawserr.ErrCodeEquals(err, "NoSuchBucketPolicy") {
return nil
}

if tfawserr.ErrCodeEquals(err, "NoSuchOutpost") {
return nil
}

if err != nil {
return fmt.Errorf("error deleting S3 Control Bucket Policy (%s): %w", d.Id(), err)
}

return nil
}
205 changes: 205 additions & 0 deletions aws/resource_aws_s3control_bucket_policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
package aws

import (
"fmt"
"regexp"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/service/s3control"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"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"
)

func TestAccAWSS3ControlBucketPolicy_basic(t *testing.T) {
rName := acctest.RandomWithPrefix("tf-acc-test")
resourceName := "aws_s3control_bucket_policy.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSOutpostsOutposts(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSS3ControlBucketPolicyDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSS3ControlBucketPolicyConfig_Policy(rName, "s3-outposts:*"),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSS3ControlBucketPolicyExists(resourceName),
resource.TestCheckResourceAttrPair(resourceName, "bucket", "aws_s3control_bucket.test", "arn"),
resource.TestMatchResourceAttr(resourceName, "policy", regexp.MustCompile(`s3-outposts:\*`)),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccAWSS3ControlBucketPolicy_disappears(t *testing.T) {
rName := acctest.RandomWithPrefix("tf-acc-test")
resourceName := "aws_s3control_bucket_policy.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSOutpostsOutposts(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSS3ControlBucketPolicyDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSS3ControlBucketPolicyConfig_Policy(rName, "s3-outposts:*"),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSS3ControlBucketPolicyExists(resourceName),
testAccCheckResourceDisappears(testAccProvider, resourceAwsS3ControlBucketPolicy(), resourceName),
),
ExpectNonEmptyPlan: true,
},
},
})
}

func TestAccAWSS3ControlBucketPolicy_Policy(t *testing.T) {
rName := acctest.RandomWithPrefix("tf-acc-test")
resourceName := "aws_s3control_bucket_policy.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSOutpostsOutposts(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSS3ControlBucketPolicyDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSS3ControlBucketPolicyConfig_Policy(rName, "s3-outposts:GetObject"),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSS3ControlBucketPolicyExists(resourceName),
resource.TestMatchResourceAttr(resourceName, "policy", regexp.MustCompile(`s3-outposts:GetObject`)),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccAWSS3ControlBucketPolicyConfig_Policy(rName, "s3-outposts:PutObject"),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSS3ControlBucketPolicyExists(resourceName),
resource.TestMatchResourceAttr(resourceName, "policy", regexp.MustCompile(`s3-outposts:PutObject`)),
),
},
},
})
}

func testAccCheckAWSS3ControlBucketPolicyDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).s3controlconn

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

parsedArn, err := arn.Parse(rs.Primary.ID)

if err != nil {
return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): %w", rs.Primary.ID, err)
}

input := &s3control.GetBucketPolicyInput{
AccountId: aws.String(parsedArn.AccountID),
Bucket: aws.String(rs.Primary.ID),
}

_, err = conn.GetBucketPolicy(input)

if tfawserr.ErrCodeEquals(err, "NoSuchBucket") {
return nil
}

if tfawserr.ErrCodeEquals(err, "NoSuchBucketPolicy") {
return nil
}

if tfawserr.ErrCodeEquals(err, "NoSuchOutpost") {
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar comment here as in #15510 to continue through the loop

bflad marked this conversation as resolved.
Show resolved Hide resolved

if err != nil {
return err
}

return fmt.Errorf("S3 Control Bucket Policy (%s) still exists", rs.Primary.ID)
}

return nil
}

func testAccCheckAWSS3ControlBucketPolicyExists(resourceName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return fmt.Errorf("not found: %s", resourceName)
}

if rs.Primary.ID == "" {
return fmt.Errorf("no resource ID is set")
}

conn := testAccProvider.Meta().(*AWSClient).s3controlconn

parsedArn, err := arn.Parse(rs.Primary.ID)

if err != nil {
return fmt.Errorf("error parsing S3 Control Bucket ARN (%s): %w", rs.Primary.ID, err)
}

input := &s3control.GetBucketPolicyInput{
AccountId: aws.String(parsedArn.AccountID),
Bucket: aws.String(rs.Primary.ID),
}

_, err = conn.GetBucketPolicy(input)

if err != nil {
return err
}

return nil
}
}

func testAccAWSS3ControlBucketPolicyConfig_Policy(rName, action string) string {
return fmt.Sprintf(`
data "aws_outposts_outposts" "test" {}

data "aws_outposts_outpost" "test" {
id = tolist(data.aws_outposts_outposts.test.ids)[0]
}

resource "aws_s3control_bucket" "test" {
bucket = %[1]q
outpost_id = data.aws_outposts_outpost.test.id
}

resource "aws_s3control_bucket_policy" "test" {
bucket = aws_s3control_bucket.test.arn
policy = jsonencode({
Id = "testBucketPolicy"
Statement = [
{
Action = %[2]q
Effect = "Deny"
Principal = {
AWS = "*"
}
Resource = "${aws_s3control_bucket.test.arn}/object/test"
Sid = "st1"
}
]
Version = "2012-10-17"
})
}
`, rName, action)
}
Loading