Skip to content

Commit

Permalink
Merge pull request #39366 from hashicorp/f-veyron-sse-kms
Browse files Browse the repository at this point in the history
r/aws_s3_bucket_server_side_encryption_configuration: S3 directory buckets now support SSE-KMS
  • Loading branch information
ewbankkit committed Sep 18, 2024
2 parents 9f19ad7 + 54567d0 commit 95ba1f0
Show file tree
Hide file tree
Showing 12 changed files with 107 additions and 28 deletions.
3 changes: 3 additions & 0 deletions .changelog/39366.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_s3_bucket_server_side_encryption_configuration: S3 directory buckets now support SSE-KMS
```
2 changes: 1 addition & 1 deletion internal/service/s3/bucket_lifecycle_configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1061,7 +1061,7 @@ func TestAccS3BucketLifecycleConfiguration_directoryBucket(t *testing.T) {
Steps: []resource.TestStep{
{
Config: testAccBucketLifecycleConfigurationConfig_directoryBucket(rName),
ExpectError: regexache.MustCompile(`directory buckets are not supported`),
ExpectError: regexache.MustCompile(`MethodNotAllowed: The specified method is not allowed against this resource`),
},
},
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,6 @@ func resourceBucketServerSideEncryptionConfigurationCreate(ctx context.Context,
return conn.PutBucketEncryption(ctx, input)
}, errCodeNoSuchBucket, errCodeOperationAborted)

if tfawserr.ErrMessageContains(err, errCodeInvalidArgument, "ServerSideEncryptionConfiguration is not valid, expected CreateBucketConfiguration") {
err = errDirectoryBucket(err)
}

if err != nil {
return sdkdiag.AppendErrorf(diags, "creating S3 Bucket (%s) Server-side Encryption Configuration: %s", bucket, err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"fmt"
"testing"

"github.com/YakDriver/regexache"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
Expand All @@ -32,7 +31,7 @@ func TestAccS3BucketServerSideEncryptionConfiguration_basic(t *testing.T) {
Steps: []resource.TestStep{
{
Config: testAccBucketServerSideEncryptionConfigurationConfig_basic(rName),
Check: resource.ComposeTestCheckFunc(
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckBucketServerSideEncryptionConfigurationExists(ctx, resourceName),
resource.TestCheckResourceAttrPair(resourceName, names.AttrBucket, "aws_s3_bucket.test", names.AttrBucket),
resource.TestCheckResourceAttr(resourceName, acctest.CtRulePound, acctest.Ct1),
Expand Down Expand Up @@ -446,6 +445,7 @@ func TestAccS3BucketServerSideEncryptionConfiguration_migrate_withChange(t *test
func TestAccS3BucketServerSideEncryptionConfiguration_directoryBucket(t *testing.T) {
ctx := acctest.Context(t)
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_s3_bucket_server_side_encryption_configuration.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
Expand All @@ -454,8 +454,24 @@ func TestAccS3BucketServerSideEncryptionConfiguration_directoryBucket(t *testing
CheckDestroy: acctest.CheckDestroyNoop,
Steps: []resource.TestStep{
{
Config: testAccBucketServerSideEncryptionConfigurationConfig_directoryBucket(rName),
ExpectError: regexache.MustCompile(`directory buckets are not supported`),
Config: testAccBucketServerSideEncryptionConfigurationConfig_directoryBucket(rName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckBucketServerSideEncryptionConfigurationExists(ctx, resourceName),
resource.TestCheckResourceAttrPair(resourceName, names.AttrBucket, "aws_s3_directory_bucket.test", names.AttrBucket),
resource.TestCheckResourceAttr(resourceName, acctest.CtRulePound, acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "rule.0.apply_server_side_encryption_by_default.#", acctest.Ct1),
resource.TestCheckResourceAttrPair(resourceName, "rule.0.apply_server_side_encryption_by_default.0.kms_master_key_id", "aws_kms_key.test", names.AttrARN),
resource.TestCheckResourceAttr(resourceName, "rule.0.apply_server_side_encryption_by_default.0.sse_algorithm", string(types.ServerSideEncryptionAwsKms)),
resource.TestCheckResourceAttr(resourceName, "rule.0.bucket_key_enabled", acctest.CtTrue),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{
"rule.0.bucket_key_enabled",
},
},
},
})
Expand Down Expand Up @@ -631,7 +647,7 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "test" {
}

func testAccBucketServerSideEncryptionConfigurationConfig_directoryBucket(rName string) string {
return acctest.ConfigCompose(testAccDirectoryBucketConfig_base(rName), `
return acctest.ConfigCompose(testAccDirectoryBucketConfig_base(rName), fmt.Sprintf(`
resource "aws_s3_directory_bucket" "test" {
bucket = local.bucket
Expand All @@ -640,15 +656,21 @@ resource "aws_s3_directory_bucket" "test" {
}
}
resource "aws_kms_key" "test" {
description = %[1]q
deletion_window_in_days = 7
}
resource "aws_s3_bucket_server_side_encryption_configuration" "test" {
bucket = aws_s3_directory_bucket.test.bucket
rule {
# This is Amazon S3 bucket default encryption.
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
kms_master_key_id = aws_kms_key.test.arn
sse_algorithm = "aws:kms"
}
bucket_key_enabled = true
}
}
`)
`, rName))
}
50 changes: 50 additions & 0 deletions internal/service/s3/object_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1769,6 +1769,40 @@ func TestAccS3Object_DirectoryBucket_DefaultTags_providerOnly(t *testing.T) {
})
}

func TestAccS3Object_DirectoryBucket_kmsSSE(t *testing.T) {
ctx := acctest.Context(t)
var obj s3.GetObjectOutput
resourceName := "aws_s3_object.object"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

source := testAccObjectCreateTempFile(t, "{anything will do }")
defer os.Remove(source)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.S3ServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckObjectDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccObjectConfig_directoryBucketKMSSSE(rName, source),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckObjectExists(ctx, resourceName, &obj),
testAccCheckObjectSSE(ctx, resourceName, "aws:kms"),
testAccCheckObjectBody(&obj, "{anything will do }"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{names.AttrForceDestroy, "override_provider", names.AttrSource},
ImportStateIdFunc: testAccObjectImportStateIdFunc(resourceName),
},
},
})
}

// https://github.com/hashicorp/terraform-provider-aws/issues/32385.
func TestAccS3Object_prefix(t *testing.T) {
ctx := acctest.Context(t)
Expand Down Expand Up @@ -2945,6 +2979,22 @@ resource "aws_s3_object" "object" {
`)
}

func testAccObjectConfig_directoryBucketKMSSSE(rName, source string) string {
return acctest.ConfigCompose(testAccBucketServerSideEncryptionConfigurationConfig_directoryBucket(rName), fmt.Sprintf(`
resource "aws_s3_object" "object" {
bucket = aws_s3_directory_bucket.test.bucket
key = "test-key"
source = %[1]q
override_provider {
default_tags {
tags = {}
}
}
}
`, source))
}

func testAccObjectConfig_prefix(rName string) string {
return fmt.Sprintf(`
resource "aws_s3_bucket" "test" {
Expand Down
2 changes: 1 addition & 1 deletion internal/service/s3control/access_grant.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func (r *accessGrantResource) Create(ctx context.Context, request resource.Creat
input.Tags = getTagsIn(ctx)

// "InvalidRequest: Invalid Grantee in the request".
outputRaw, err := tfresource.RetryWhenAWSErrMessageContains(ctx, propagationTimeout, func() (interface{}, error) {
outputRaw, err := tfresource.RetryWhenAWSErrMessageContains(ctx, s3PropagationTimeout, func() (interface{}, error) {
return conn.CreateAccessGrant(ctx, input)
}, errCodeInvalidRequest, "Invalid Grantee in the request")

Expand Down
6 changes: 3 additions & 3 deletions internal/service/s3control/access_grants_location.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (r *accessGrantsLocationResource) Create(ctx context.Context, request resou

input.Tags = getTagsIn(ctx)

outputRaw, err := tfresource.RetryWhenAWSErrCodeEquals(ctx, propagationTimeout, func() (interface{}, error) {
outputRaw, err := tfresource.RetryWhenAWSErrCodeEquals(ctx, s3PropagationTimeout, func() (interface{}, error) {
return conn.CreateAccessGrantsLocation(ctx, input)
}, errCodeInvalidIAMRole)

Expand Down Expand Up @@ -205,7 +205,7 @@ func (r *accessGrantsLocationResource) Update(ctx context.Context, request resou
return
}

_, err := tfresource.RetryWhenAWSErrCodeEquals(ctx, propagationTimeout, func() (interface{}, error) {
_, err := tfresource.RetryWhenAWSErrCodeEquals(ctx, s3PropagationTimeout, func() (interface{}, error) {
return conn.UpdateAccessGrantsLocation(ctx, input)
}, errCodeInvalidIAMRole)

Expand Down Expand Up @@ -244,7 +244,7 @@ func (r *accessGrantsLocationResource) Delete(ctx context.Context, request resou
}

// "AccessGrantsLocationNotEmptyError: Please delete access grants before deleting access grants location".
_, err := tfresource.RetryWhenAWSErrCodeEquals(ctx, propagationTimeout, func() (interface{}, error) {
_, err := tfresource.RetryWhenAWSErrCodeEquals(ctx, s3PropagationTimeout, func() (interface{}, error) {
return conn.DeleteAccessGrantsLocation(ctx, input)
}, errCodeAccessGrantsLocationNotEmptyError)

Expand Down
12 changes: 10 additions & 2 deletions internal/service/s3control/account_public_access_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func resourceAccountPublicAccessBlockCreate(ctx context.Context, d *schema.Resou

d.SetId(accountID)

_, err = tfresource.RetryWhenNotFound(ctx, propagationTimeout, func() (interface{}, error) {
_, err = tfresource.RetryWhenNotFound(ctx, s3PropagationTimeout, func() (interface{}, error) {
return findPublicAccessBlockByAccountID(ctx, conn, d.Id())
})

Expand Down Expand Up @@ -176,6 +176,14 @@ func resourceAccountPublicAccessBlockDelete(ctx context.Context, d *schema.Resou
return sdkdiag.AppendErrorf(diags, "deleting S3 Account Public Access Block (%s): %s", d.Id(), err)
}

_, err = tfresource.RetryUntilNotFound(ctx, s3PropagationTimeout, func() (interface{}, error) {
return findPublicAccessBlockByAccountID(ctx, conn, d.Id())
})

if err != nil {
return sdkdiag.AppendErrorf(diags, "waiting for S3 Account Public Access Block (%s) delete: %s", d.Id(), err)
}

return diags
}

Expand Down Expand Up @@ -225,7 +233,7 @@ func waitPublicAccessBlockEqual(ctx context.Context, conn *s3control.Client, acc
Pending: []string{strconv.FormatBool(false)},
Target: []string{strconv.FormatBool(true)},
Refresh: statusPublicAccessBlockEqual(ctx, conn, accountID, target),
Timeout: propagationTimeout,
Timeout: s3PropagationTimeout,
MinTimeout: 5 * time.Second,
ContinuousTargetOccurence: 2,
}
Expand Down
4 changes: 3 additions & 1 deletion internal/service/s3control/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ import (
)

const (
propagationTimeout = 2 * time.Minute
// General timeout for S3 changes to propagate.
// See https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html#ConsistencyModel.
s3PropagationTimeout = 2 * time.Minute
)
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func testAccCheckObjectLambdaAccessPointPolicyExists(ctx context.Context, n stri
}

func testAccObjectLambdaAccessPointPolicyConfig_basic(rName string) string {
return acctest.ConfigCompose(testAccObjectLambdaAccessPointBaseConfig(rName), fmt.Sprintf(`
return acctest.ConfigCompose(testAccObjectLambdaAccessPointConfig_base(rName), fmt.Sprintf(`
data "aws_caller_identity" "current" {}
resource "aws_s3_bucket" "test" {
Expand Down Expand Up @@ -236,7 +236,7 @@ resource "aws_s3control_object_lambda_access_point_policy" "test" {
}

func testAccObjectLambdaAccessPointPolicyConfig_updated(rName string) string {
return acctest.ConfigCompose(testAccObjectLambdaAccessPointBaseConfig(rName), fmt.Sprintf(`
return acctest.ConfigCompose(testAccObjectLambdaAccessPointConfig_base(rName), fmt.Sprintf(`
data "aws_caller_identity" "current" {}
resource "aws_s3_bucket" "test" {
Expand Down
8 changes: 4 additions & 4 deletions internal/service/s3control/object_lambda_access_point_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,20 +213,20 @@ func testAccCheckObjectLambdaAccessPointExists(ctx context.Context, n string, v
}
}

func testAccObjectLambdaAccessPointBaseConfig(rName string) string {
func testAccObjectLambdaAccessPointConfig_base(rName string) string {
return acctest.ConfigCompose(acctest.ConfigLambdaBase(rName, rName, rName), fmt.Sprintf(`
resource "aws_lambda_function" "test" {
filename = "test-fixtures/lambdatest.zip"
function_name = %[1]q
role = aws_iam_role.iam_for_lambda.arn
handler = "index.handler"
runtime = "nodejs14.x"
runtime = "nodejs20.x"
}
`, rName))
}

func testAccObjectLambdaAccessPointConfig_basic(rName string) string {
return acctest.ConfigCompose(testAccObjectLambdaAccessPointBaseConfig(rName), fmt.Sprintf(`
return acctest.ConfigCompose(testAccObjectLambdaAccessPointConfig_base(rName), fmt.Sprintf(`
resource "aws_s3_bucket" "test" {
bucket = %[1]q
}
Expand Down Expand Up @@ -257,7 +257,7 @@ resource "aws_s3control_object_lambda_access_point" "test" {
}

func testAccObjectLambdaAccessPointConfig_optionals(rName string) string {
return acctest.ConfigCompose(testAccObjectLambdaAccessPointBaseConfig(rName), fmt.Sprintf(`
return acctest.ConfigCompose(testAccObjectLambdaAccessPointConfig_base(rName), fmt.Sprintf(`
resource "aws_s3_bucket" "test" {
bucket = %[1]q
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ Provides a S3 bucket server-side encryption configuration resource.

~> **NOTE:** Destroying an `aws_s3_bucket_server_side_encryption_configuration` resource resets the bucket to [Amazon S3 bucket default encryption](https://docs.aws.amazon.com/AmazonS3/latest/userguide/default-encryption-faq.html).

-> This resource cannot be used with S3 directory buckets.

## Example Usage

```terraform
Expand Down

0 comments on commit 95ba1f0

Please sign in to comment.