-
Notifications
You must be signed in to change notification settings - Fork 9.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8615 from hashicorp/f-aws-s3-bucket-policy
provider/aws: Add aws_s3_bucket_policy resource
- Loading branch information
Showing
10 changed files
with
695 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package aws | ||
|
||
import ( | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/jen20/awspolicyequivalence" | ||
) | ||
|
||
func suppressEquivalentAwsPolicyDiffs(k, old, new string, d *schema.ResourceData) bool { | ||
equivalent, err := awspolicy.PoliciesAreEquivalent(old, new) | ||
if err != nil { | ||
return false | ||
} | ||
|
||
return equivalent | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"time" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/aws/awserr" | ||
"github.com/aws/aws-sdk-go/service/s3" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
) | ||
|
||
func resourceAwsS3BucketPolicy() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceAwsS3BucketPolicyPut, | ||
Read: resourceAwsS3BucketPolicyRead, | ||
Update: resourceAwsS3BucketPolicyPut, | ||
Delete: resourceAwsS3BucketPolicyDelete, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"bucket": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"policy": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceAwsS3BucketPolicyPut(d *schema.ResourceData, meta interface{}) error { | ||
s3conn := meta.(*AWSClient).s3conn | ||
|
||
bucket := d.Get("bucket").(string) | ||
policy := d.Get("policy").(string) | ||
|
||
d.SetId(bucket) | ||
|
||
log.Printf("[DEBUG] S3 bucket: %s, put policy: %s", bucket, policy) | ||
|
||
params := &s3.PutBucketPolicyInput{ | ||
Bucket: aws.String(bucket), | ||
Policy: aws.String(policy), | ||
} | ||
|
||
err := resource.Retry(1*time.Minute, func() *resource.RetryError { | ||
if _, err := s3conn.PutBucketPolicy(params); err != nil { | ||
if awserr, ok := err.(awserr.Error); ok { | ||
if awserr.Code() == "MalformedPolicy" { | ||
return resource.RetryableError(awserr) | ||
} | ||
} | ||
return resource.NonRetryableError(err) | ||
} | ||
return nil | ||
}) | ||
|
||
if err != nil { | ||
return fmt.Errorf("Error putting S3 policy: %s", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceAwsS3BucketPolicyRead(d *schema.ResourceData, meta interface{}) error { | ||
s3conn := meta.(*AWSClient).s3conn | ||
|
||
log.Printf("[DEBUG] S3 bucket policy, read for bucket: %s", d.Id()) | ||
pol, err := s3conn.GetBucketPolicy(&s3.GetBucketPolicyInput{ | ||
Bucket: aws.String(d.Id()), | ||
}) | ||
|
||
v := "" | ||
if err == nil && pol.Policy != nil { | ||
v = *pol.Policy | ||
} | ||
if err := d.Set("policy", v); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceAwsS3BucketPolicyDelete(d *schema.ResourceData, meta interface{}) error { | ||
s3conn := meta.(*AWSClient).s3conn | ||
|
||
bucket := d.Get("bucket").(string) | ||
|
||
log.Printf("[DEBUG] S3 bucket: %s, delete policy", bucket) | ||
_, err := s3conn.DeleteBucketPolicy(&s3.DeleteBucketPolicyInput{ | ||
Bucket: aws.String(bucket), | ||
}) | ||
|
||
if err != nil { | ||
return fmt.Errorf("Error deleting S3 policy: %s", err) | ||
} | ||
|
||
return nil | ||
} |
180 changes: 180 additions & 0 deletions
180
builtin/providers/aws/resource_aws_s3_bucket_policy_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/s3" | ||
"github.com/hashicorp/terraform/helper/acctest" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
"github.com/jen20/awspolicyequivalence" | ||
) | ||
|
||
func TestAccAWSS3BucketPolicy_basic(t *testing.T) { | ||
name := fmt.Sprintf("tf-test-bucket-%d", acctest.RandInt()) | ||
|
||
expectedPolicyText := fmt.Sprintf( | ||
`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"s3:*","Resource":["arn:aws:s3:::%s","arn:aws:s3:::%s/*"]}]}`, | ||
name, name) | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckAWSS3BucketDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccAWSS3BucketPolicyConfig(name), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), | ||
testAccCheckAWSS3BucketHasPolicy("aws_s3_bucket.bucket", expectedPolicyText), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccAWSS3BucketPolicy_policyUpdate(t *testing.T) { | ||
name := fmt.Sprintf("tf-test-bucket-%d", acctest.RandInt()) | ||
|
||
expectedPolicyText1 := fmt.Sprintf( | ||
`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"s3:*","Resource":["arn:aws:s3:::%s","arn:aws:s3:::%s/*"]}]}`, | ||
name, name) | ||
|
||
expectedPolicyText2 := fmt.Sprintf( | ||
`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":["s3:DeleteBucket", "s3:ListBucket", "s3:ListBucketVersions"], "Resource":["arn:aws:s3:::%s","arn:aws:s3:::%s/*"]}]}`, | ||
name, name) | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckAWSS3BucketDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccAWSS3BucketPolicyConfig(name), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), | ||
testAccCheckAWSS3BucketHasPolicy("aws_s3_bucket.bucket", expectedPolicyText1), | ||
), | ||
}, | ||
|
||
{ | ||
Config: testAccAWSS3BucketPolicyConfig_updated(name), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), | ||
testAccCheckAWSS3BucketHasPolicy("aws_s3_bucket.bucket", expectedPolicyText2), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckAWSS3BucketHasPolicy(n string, expectedPolicyText string) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
rs, ok := s.RootModule().Resources[n] | ||
if !ok { | ||
return fmt.Errorf("Not found: %s", n) | ||
} | ||
|
||
if rs.Primary.ID == "" { | ||
return fmt.Errorf("No S3 Bucket ID is set") | ||
} | ||
|
||
conn := testAccProvider.Meta().(*AWSClient).s3conn | ||
|
||
policy, err := conn.GetBucketPolicy(&s3.GetBucketPolicyInput{ | ||
Bucket: aws.String(rs.Primary.ID), | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("GetBucketPolicy error: %v", err) | ||
} | ||
|
||
actualPolicyText := *policy.Policy | ||
|
||
equivalent, err := awspolicy.PoliciesAreEquivalent(actualPolicyText, expectedPolicyText) | ||
if err != nil { | ||
return fmt.Errorf("Error testing policy equivalence: %s", err) | ||
} | ||
if !equivalent { | ||
return fmt.Errorf("Non-equivalent policy error:\n\nexpected: %s\n\n got: %s\n", | ||
expectedPolicyText, actualPolicyText) | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
func testAccAWSS3BucketPolicyConfig(bucketName string) string { | ||
return fmt.Sprintf(` | ||
resource "aws_s3_bucket" "bucket" { | ||
bucket = "%s" | ||
tags { | ||
TestName = "TestAccAWSS3BucketPolicy_basic" | ||
} | ||
} | ||
resource "aws_s3_bucket_policy" "bucket" { | ||
bucket = "${aws_s3_bucket.bucket.bucket}" | ||
policy = "${data.aws_iam_policy_document.policy.json}" | ||
} | ||
data "aws_iam_policy_document" "policy" { | ||
statement { | ||
effect = "Allow" | ||
actions = [ | ||
"s3:*", | ||
] | ||
resources = [ | ||
"${aws_s3_bucket.bucket.arn}", | ||
"${aws_s3_bucket.bucket.arn}/*", | ||
] | ||
principals { | ||
type = "AWS" | ||
identifiers = ["*"] | ||
} | ||
} | ||
} | ||
`, bucketName) | ||
} | ||
|
||
func testAccAWSS3BucketPolicyConfig_updated(bucketName string) string { | ||
return fmt.Sprintf(` | ||
resource "aws_s3_bucket" "bucket" { | ||
bucket = "%s" | ||
tags { | ||
TestName = "TestAccAWSS3BucketPolicy_basic" | ||
} | ||
} | ||
resource "aws_s3_bucket_policy" "bucket" { | ||
bucket = "${aws_s3_bucket.bucket.bucket}" | ||
policy = "${data.aws_iam_policy_document.policy.json}" | ||
} | ||
data "aws_iam_policy_document" "policy" { | ||
statement { | ||
effect = "Allow" | ||
actions = [ | ||
"s3:DeleteBucket", | ||
"s3:ListBucket", | ||
"s3:ListBucketVersions" | ||
] | ||
resources = [ | ||
"${aws_s3_bucket.bucket.arn}", | ||
"${aws_s3_bucket.bucket.arn}/*", | ||
] | ||
principals { | ||
type = "AWS" | ||
identifiers = ["*"] | ||
} | ||
} | ||
} | ||
`, bucketName) | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.