diff --git a/aws/data_source_aws_s3_bucket.go b/aws/data_source_aws_s3_bucket.go index 6a62841f125..e625fd1252c 100644 --- a/aws/data_source_aws_s3_bucket.go +++ b/aws/data_source_aws_s3_bucket.go @@ -18,6 +18,45 @@ func dataSourceAwsS3Bucket() *schema.Resource { Type: schema.TypeString, Required: true, }, + "server_side_encryption_configuration": { + Type: schema.TypeList, + MaxItems: 1, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "rule": { + Type: schema.TypeList, + MaxItems: 1, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "apply_server_side_encryption_by_default": { + Type: schema.TypeList, + MaxItems: 1, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "kms_master_key_id": { + Type: schema.TypeString, + Computed: true, + }, + "sse_algorithm": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, "arn": { Type: schema.TypeString, Computed: true, @@ -70,6 +109,53 @@ func dataSourceAwsS3BucketRead(d *schema.ResourceData, meta interface{}) error { return err } + if err := bucketEncryption(d, bucket, conn); err != nil { + return err + } + + return nil +} + +func bucketEncryption(data *schema.ResourceData, bucket string, conn *s3.S3) error { + input := &s3.GetBucketEncryptionInput{ + Bucket: aws.String(bucket), + } + output, err := conn.GetBucketEncryption(input) + if err != nil { + if isAWSErr(err, "ServerSideEncryptionConfigurationNotFoundError", "encryption configuration was not found") { + log.Printf("[DEBUG] Default encryption is not enabled for %s", bucket) + data.Set("server_side_encryption_configuration", []map[string]interface{}{ + { + "enabled": false, + }, + }) + return nil + } else { + return err + } + } + if ruleCount := len(output.ServerSideEncryptionConfiguration.Rules); ruleCount != 1 { + return fmt.Errorf("expect one rule returned but there are %d rules. Changes required in the data source to support this", ruleCount) + } + defaultRuleConfiguration := output.ServerSideEncryptionConfiguration.Rules[0].ApplyServerSideEncryptionByDefault + defaultRule := make([]map[string]interface{}, 1) + defaultRule[0] = make(map[string]interface{}) + masterKmsKeyId := "" + if defaultRuleConfiguration.KMSMasterKeyID != nil { + masterKmsKeyId = aws.StringValue(defaultRuleConfiguration.KMSMasterKeyID) + } + defaultRule[0]["kms_master_key_id"] = masterKmsKeyId + defaultRule[0]["sse_algorithm"] = aws.StringValue(defaultRuleConfiguration.SSEAlgorithm) + + encryptionConfiguration := make([]map[string]interface{}, 1) + encryptionConfiguration[0] = make(map[string]interface{}) + encryptionConfiguration[0]["enabled"] = true + rule := make([]map[string]interface{}, 1) + encryptionConfiguration[0]["rule"] = rule + rule[0] = make(map[string]interface{}) + rule[0]["apply_server_side_encryption_by_default"] = defaultRule + + data.Set("server_side_encryption_configuration", encryptionConfiguration) return nil } diff --git a/aws/data_source_aws_s3_bucket_test.go b/aws/data_source_aws_s3_bucket_test.go index 9acc9a24051..eb7f73513e4 100644 --- a/aws/data_source_aws_s3_bucket_test.go +++ b/aws/data_source_aws_s3_bucket_test.go @@ -56,6 +56,125 @@ func TestAccDataSourceS3Bucket_website(t *testing.T) { }) } +func TestAccDataSourceS3Bucket_whenDefaultEncryptionNotEnabled(t *testing.T) { + rInt := acctest.RandInt() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAWSDataSourceS3BucketConfig_basic(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSS3BucketExists("data.aws_s3_bucket.bucket"), + resource.TestCheckResourceAttr( + "data.aws_s3_bucket.bucket", "server_side_encryption_configuration.0.enabled", "false"), + resource.TestCheckResourceAttr( + "data.aws_s3_bucket.bucket", "server_side_encryption_configuration.0.rule.#", "0"), + ), + }, + }, + }) +} + +func TestAccDataSourceS3Bucket_whenDefaultEncryptionEnabledWithAES256(t *testing.T) { + rInt := acctest.RandInt() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAWSDataSourceS3BucketConfigWithDefaultEncryptionAES256(rInt), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "data.aws_s3_bucket.bucket", "server_side_encryption_configuration.#", "1"), + resource.TestCheckResourceAttr( + "data.aws_s3_bucket.bucket", "server_side_encryption_configuration.0.enabled", "true"), + resource.TestCheckResourceAttr( + "data.aws_s3_bucket.bucket", "server_side_encryption_configuration.0.rule.#", "1"), + resource.TestCheckResourceAttr( + "data.aws_s3_bucket.bucket", "server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.#", "1"), + resource.TestCheckResourceAttr( + "data.aws_s3_bucket.bucket", "server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.sse_algorithm", "AES256"), + resource.TestCheckResourceAttr( + "data.aws_s3_bucket.bucket", "server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.kms_master_key_id", ""), + ), + }, + }, + }) +} + +func TestAccDataSourceS3Bucket_whenDefaultEncryptionEnabledWithAWSKMS(t *testing.T) { + rInt := acctest.RandInt() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAWSDataSourceS3BucketConfigWithDefaultEncryptionAWSKMS(rInt), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "data.aws_s3_bucket.bucket", "server_side_encryption_configuration.#", "1"), + resource.TestCheckResourceAttr( + "data.aws_s3_bucket.bucket", "server_side_encryption_configuration.0.enabled", "true"), + resource.TestCheckResourceAttr( + "data.aws_s3_bucket.bucket", "server_side_encryption_configuration.0.rule.#", "1"), + resource.TestCheckResourceAttr( + "data.aws_s3_bucket.bucket", "server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.#", "1"), + resource.TestCheckResourceAttr( + "data.aws_s3_bucket.bucket", "server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.sse_algorithm", "aws:kms"), + resource.TestMatchResourceAttr( + "data.aws_s3_bucket.bucket", "server_side_encryption_configuration.0.rule.0.apply_server_side_encryption_by_default.0.kms_master_key_id", regexp.MustCompile("^arn")), + ), + }, + }, + }) +} + +func testAccAWSDataSourceS3BucketConfigWithDefaultEncryptionAWSKMS(randInt int) string { + return fmt.Sprintf(` +resource "aws_kms_key" "arbitrary" { + description = "KMS Key for Bucket Testing %d" + deletion_window_in_days = 10 +} + +resource "aws_s3_bucket" "arbitrary" { + bucket = "tf-test-bucket-%d" + server_side_encryption_configuration { + rule { + apply_server_side_encryption_by_default { + kms_master_key_id = "${aws_kms_key.arbitrary.arn}" + sse_algorithm = "aws:kms" + } + } + } +} + +data "aws_s3_bucket" "bucket" { + bucket = "${aws_s3_bucket.arbitrary.id}" +}`, randInt, randInt) +} + +func testAccAWSDataSourceS3BucketConfigWithDefaultEncryptionAES256(randInt int) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "bucket" { + bucket = "tf-test-bucket-%d" + server_side_encryption_configuration { + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } + } +} + +data "aws_s3_bucket" "bucket" { + bucket = "${aws_s3_bucket.bucket.id}" +}`, randInt) +} + func testAccAWSDataSourceS3BucketConfig_basic(randInt int) string { return fmt.Sprintf(` resource "aws_s3_bucket" "bucket" { diff --git a/website/docs/d/s3_bucket.html.markdown b/website/docs/d/s3_bucket.html.markdown index 1d5301c0b7a..3b6ed12602a 100644 --- a/website/docs/d/s3_bucket.html.markdown +++ b/website/docs/d/s3_bucket.html.markdown @@ -70,3 +70,9 @@ The following attributes are exported: * `region` - The AWS region this bucket resides in. * `website_endpoint` - The website endpoint, if the bucket is configured with a website. If not, this will be an empty string. * `website_domain` - The domain of the website endpoint, if the bucket is configured with a website. If not, this will be an empty string. This is used to create Route 53 alias records. +* `server_side_encryption_configuration` - The encryption configuration for the bucket + * `enabled` - True if default encryption is enabled, false otherwise + * `rule` - Only available if `enabled` is true + * `apply_server_side_encryption_by_default` - Details about the default encryption + * `kms_master_key_id` - AWS KMS Key Id that is used to encrypt in server side + * `sse_algorithm` - Encryption algorithm used. Possible values are `AES256` and `aws:kms` \ No newline at end of file