Skip to content

Commit acf865a

Browse files
authored
r/aws_s3_bucket(test): add tagging fallback acceptance test (#45339)
With `TF_ACC_ASSUME_ROLE_ARN` set: ```console % TF_ACC_ASSUME_ROLE_ARN=arn:aws:iam::<redacted>:role/tfacctest-s3-bucket-no-tag-perms make testacc K=s3 T=TestAccS3Bucket_tags_fallbackS3API make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: 🌿 td-s3-tagging-fallback 🌿... TF_ACC=1 go1.24.10 test ./internal/service/s3/... -v -count 1 -parallel 20 -run='TestAccS3Bucket_tags_fallbackS3API' -timeout 360m -vet=off 2025/12/01 11:30:48 Creating Terraform AWS Provider (SDKv2-style)... 2025/12/01 11:30:48 Initializing Terraform AWS Provider (SDKv2-style)... === RUN TestAccS3Bucket_tags_fallbackS3API === PAUSE TestAccS3Bucket_tags_fallbackS3API === CONT TestAccS3Bucket_tags_fallbackS3API --- PASS: TestAccS3Bucket_tags_fallbackS3API (48.24s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/s3 54.701s ``` Otherwise: ```console % make testacc K=s3 T=TestAccS3Bucket_tags_fallbackS3API make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: 🌿 td-s3-tagging-fallback 🌿... TF_ACC=1 go1.24.10 test ./internal/service/s3/... -v -count 1 -parallel 20 -run='TestAccS3Bucket_tags_fallbackS3API' -timeout 360m -vet=off 2025/12/01 11:37:32 Creating Terraform AWS Provider (SDKv2-style)... 2025/12/01 11:37:32 Initializing Terraform AWS Provider (SDKv2-style)... === RUN TestAccS3Bucket_tags_fallbackS3API === PAUSE TestAccS3Bucket_tags_fallbackS3API === CONT TestAccS3Bucket_tags_fallbackS3API bucket_test.go:856: skipping test; environment variable TF_ACC_ASSUME_ROLE_ARN must be set. Usage: Amazon Resource Name (ARN) of existing IAM Role to assume for testing restricted permissions --- SKIP: TestAccS3Bucket_tags_fallbackS3API (0.36s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/s3 6.807s ```
1 parent b1feb50 commit acf865a

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed

internal/acctest/configs.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,17 @@ provider "aws" {
295295
`, tag1, value1, tag2, value2))
296296
}
297297

298+
func ConfigAssumeRole() string {
299+
//lintignore:AT004
300+
return fmt.Sprintf(`
301+
provider "aws" {
302+
assume_role {
303+
role_arn = %[1]q
304+
}
305+
}
306+
`, os.Getenv(envvar.AccAssumeRoleARN))
307+
}
308+
298309
func ConfigAssumeRolePolicy(policy string) string {
299310
//lintignore:AT004
300311
return fmt.Sprintf(`

internal/service/s3/bucket_test.go

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,175 @@ func TestAccS3Bucket_tags_ignoreTags(t *testing.T) {
734734
})
735735
}
736736

737+
// TestAccS3Bucket_tags_fallbackS3API exercises the bucket tagging "fallback" workflow
738+
//
739+
// To support ABAC (attribute based access control) in general purpose buckets,
740+
// the provider attempts using the S3 Control tagging APIs first. When a permissions
741+
// error is encountered, tag operations will fall back to the pre-existing S3 tagging
742+
// APIs instead.
743+
//
744+
// Ref: https://github.com/hashicorp/terraform-provider-aws/pull/45251
745+
//
746+
// This test expects the TF_ACC_ASSUME_ROLE_ARN to be set to a role ARN
747+
// which is missing permissions the S3 Control tagging APIs (s3:TagResource,
748+
// s3:UntagResource, and s3:ListTagsForResource), forcing the tag operations
749+
// to fall back to the S3 tagging APIs (s3:PutBucketTagging, s3:GetBucketTagging,
750+
// and s3:DeleteBucketTagging) instead.
751+
//
752+
// Use the following configuration to create the role to assume:
753+
//
754+
// ```
755+
//
756+
// terraform {
757+
// required_providers {
758+
// aws = {
759+
// source = "hashicorp/aws"
760+
// version = "~> 6.0"
761+
// }
762+
// }
763+
// }
764+
//
765+
// # Configure the AWS Provider
766+
// provider "aws" {}
767+
//
768+
// data "aws_caller_identity" "current" {}
769+
//
770+
// data "aws_iam_session_context" "current" {
771+
// arn = data.aws_caller_identity.current.arn
772+
// }
773+
//
774+
// data "aws_iam_policy_document" "test_assume_role" {
775+
// statement {
776+
// effect = "Allow"
777+
// actions = [
778+
// "sts:AssumeRole",
779+
// "sts:SetSourceIdentity",
780+
// ]
781+
// principals {
782+
// type = "AWS"
783+
// identifiers = [
784+
// data.aws_iam_session_context.current.issuer_arn,
785+
// ]
786+
// }
787+
// }
788+
// }
789+
//
790+
// data "aws_iam_policy_document" "test" {
791+
// statement {
792+
// sid = "AllowAllS3"
793+
// effect = "Allow"
794+
// actions = [
795+
// "s3:*",
796+
// ]
797+
// resources = [
798+
// "arn:aws:s3:::*",
799+
// ]
800+
// }
801+
// statement {
802+
// sid = "ForceTaggingFallback"
803+
// effect = "Deny"
804+
// actions = [
805+
// "s3:TagResource",
806+
// "s3:UntagResource",
807+
// "s3:ListTagsForResource",
808+
// ]
809+
// resources = [
810+
// "arn:aws:s3:::*",
811+
// ]
812+
// }
813+
//
814+
// statement {
815+
// actions = [
816+
// "sts:GetCallerIdentity",
817+
// ]
818+
// resources = [
819+
// "*",
820+
// ]
821+
// }
822+
// }
823+
//
824+
// resource "aws_iam_policy" "test" {
825+
// name = "tfacctest-s3-bucket-no-tag-perms"
826+
// policy = data.aws_iam_policy_document.test.json
827+
// }
828+
//
829+
// resource "aws_iam_role" "test" {
830+
// name = "tfacctest-s3-bucket-no-tag-perms"
831+
// assume_role_policy = data.aws_iam_policy_document.test_assume_role.json
832+
// }
833+
//
834+
// resource "aws_iam_role_policy_attachment" "test" {
835+
// role = aws_iam_role.test.name
836+
// policy_arn = aws_iam_policy.test.arn
837+
// }
838+
//
839+
// output "role_arn" {
840+
// value = aws_iam_role.test.arn
841+
// }
842+
//
843+
// ```
844+
//
845+
// Once provisioned, use the role_arn output and run this test as follows:
846+
//
847+
// TF_ACC_ASSUME_ROLE_ARN=<output> make t K=s3 T=TestAccS3Bucket_tags_fallbackS3API
848+
func TestAccS3Bucket_tags_fallbackS3API(t *testing.T) {
849+
ctx := acctest.Context(t)
850+
rName := sdkacctest.RandomWithPrefix("tf-test-bucket")
851+
resourceName := "aws_s3_bucket.test"
852+
853+
resource.ParallelTest(t, resource.TestCase{
854+
PreCheck: func() {
855+
acctest.PreCheck(ctx, t)
856+
acctest.PreCheckAssumeRoleARN(t)
857+
},
858+
ErrorCheck: acctest.ErrorCheck(t, names.S3ServiceID),
859+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
860+
CheckDestroy: testAccCheckBucketDestroy(ctx),
861+
Steps: []resource.TestStep{
862+
{
863+
Config: acctest.ConfigCompose(
864+
acctest.ConfigAssumeRole(),
865+
testAccBucketConfig_tags(rName),
866+
),
867+
Check: resource.ComposeAggregateTestCheckFunc(
868+
testAccCheckBucketExists(ctx, resourceName),
869+
resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "3"),
870+
resource.TestCheckResourceAttr(resourceName, "tags.Key1", "AAA"),
871+
resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"),
872+
resource.TestCheckResourceAttr(resourceName, "tags.Key3", "CCC"),
873+
),
874+
},
875+
{
876+
Config: acctest.ConfigCompose(
877+
acctest.ConfigAssumeRole(),
878+
testAccBucketConfig_updatedTags(rName),
879+
),
880+
Check: resource.ComposeAggregateTestCheckFunc(
881+
testAccCheckBucketExists(ctx, resourceName),
882+
resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "4"),
883+
resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"),
884+
resource.TestCheckResourceAttr(resourceName, "tags.Key3", "XXX"),
885+
resource.TestCheckResourceAttr(resourceName, "tags.Key4", "DDD"),
886+
resource.TestCheckResourceAttr(resourceName, "tags.Key5", "EEE"),
887+
),
888+
},
889+
{
890+
Config: acctest.ConfigCompose(
891+
acctest.ConfigAssumeRole(),
892+
testAccBucketConfig_tags(rName),
893+
),
894+
Check: resource.ComposeAggregateTestCheckFunc(
895+
testAccCheckBucketExists(ctx, resourceName),
896+
resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "3"),
897+
resource.TestCheckResourceAttr(resourceName, "tags.Key1", "AAA"),
898+
resource.TestCheckResourceAttr(resourceName, "tags.Key2", "BBB"),
899+
resource.TestCheckResourceAttr(resourceName, "tags.Key3", "CCC"),
900+
),
901+
},
902+
},
903+
})
904+
}
905+
737906
func TestAccS3Bucket_Manage_lifecycleBasic(t *testing.T) {
738907
ctx := acctest.Context(t)
739908
bucketName := sdkacctest.RandomWithPrefix("tf-test-bucket")

0 commit comments

Comments
 (0)