Choose the best Terraform patch (A/B/C/D) that implements the requested S3 security change safely. Only respond with a single uppercase letter.

Task Description:
## Description
Added support for ignoring default_tags set on provider level.

## Motivation and Context
This change was required as it was not possible to deploy s3 bucket object if there are more than 10 tags set on provider level.
More info [here](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_object#ignoring-provider-default_tags).

## Breaking Changes
This is not a breaking change but it does require bumping the provider version for 2 major versions, as option was only recently added to provider.

## How Has This Been Tested?
- [x] I have updated at least one of the `examples/*` to demonstrate and validate my change(s)
- [x] I have tested and validated these changes using one or more of the provided `examples/*` projects

- [x] I have executed `pre-commit run -a` on my pull request

---

Choice A:
examples/object/README.md
@@ -37,6 +37,7 @@ Note that this example may create resources which cost money. Run `terraform des
 |  [object](#module\_object) | ../../modules/object | n/a |
 |  [object\_complete](#module\_object\_complete) | ../../modules/object | n/a |
 |  [object\_locked](#module\_object\_locked) | ../../modules/object | n/a |
+|  [object\_with\_override\_default\_tags](#module\_object\_with\_override\_default\_tags) | ../../modules/object | n/a |
 |  [s3\_bucket](#module\_s3\_bucket) | ../../ | n/a |
 |  [s3\_bucket\_with\_object\_lock](#module\_s3\_bucket\_with\_object\_lock) | ../../ | n/a |

---
examples/object/main.tf
@@ -5,6 +5,12 @@ provider "aws" {
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
+
+  default_tags {
+    tags = {
+      Example = "object"
+    }
+  }
 }

 locals {
@@ -25,6 +31,7 @@ module "object" {
     Sensitive = "not-really"
   }
 }
+
 module "object_complete" {
   source = "../../modules/object"

@@ -33,7 +40,7 @@ module "object_complete" {

   content = jsonencode({ data : "value" })

-  acl           = "public-read"
+  # acl           = "public-read"
   storage_class = "ONEZONE_IA"
   force_destroy = true

@@ -68,6 +75,21 @@ module "object_locked" {
   object_lock_retain_until_date = formatdate("YYYY-MM-DD'T'hh:00:00Z", timeadd(timestamp(), "1h")) # some time in the future
 }

+module "object_with_override_default_tags" {
+  source = "../../modules/object"
+
+  bucket = module.s3_bucket.s3_bucket_id
+  key    = "${random_pet.this.id}-local-override-default-tags"
+
+  override_default_tags = true
+
+  file_source = "README.md"
+
+  tags = {
+    Override = "true"
+  }
+}
+
 ##################
 # Extra resources
 ##################
@@ -96,7 +118,13 @@ module "s3_bucket_with_object_lock" {
   bucket        = "${random_pet.this.id}-with-object-lock"
   force_destroy = true

+  object_lock_enabled = true
   object_lock_configuration = {
-    object_lock_enabled = "Enabled"
+    rule = {
+      default_retention = {
+        mode = "GOVERNANCE"
+        days = 1
+      }
+    }
   }
 }
---
modules/object/README.md
@@ -8,13 +8,13 @@ Creates S3 bucket objects with different configurations.
 | Name | Version |
 |------|---------|
 |  [terraform](#requirement\_terraform) | >= 1.0 |
-|  [aws](#requirement\_aws) | >= 3.75 |
+|  [aws](#requirement\_aws) | >= 5.24 |

 ## Providers

 | Name | Version |
 |------|---------|
-|  [aws](#provider\_aws) | >= 3.75 |
+|  [aws](#provider\_aws) | >= 5.24 |

 ## Modules

@@ -50,6 +50,7 @@ No modules.
 |  [object\_lock\_legal\_hold\_status](#input\_object\_lock\_legal\_hold\_status) | The legal hold status that you want to apply to the specified object. Valid values are ON and OFF. | `string` | `null` | no |
 |  [object\_lock\_mode](#input\_object\_lock\_mode) | The object lock retention mode that you want to apply to this object. Valid values are GOVERNANCE and COMPLIANCE. | `string` | `null` | no |
 |  [object\_lock\_retain\_until\_date](#input\_object\_lock\_retain\_until\_date) | The date and time, in RFC3339 format, when this object's object lock will expire. | `string` | `null` | no |
+|  [override\_default\_tags](#input\_override\_default\_tags) | Ignore provider default\_tags. S3 objects support a maximum of 10 tags. | `bool` | `false` | no |
 |  [server\_side\_encryption](#input\_server\_side\_encryption) | Specifies server-side encryption of the object in S3. Valid values are "AES256" and "aws:kms". | `string` | `null` | no |
 |  [source\_hash](#input\_source\_hash) | Triggers updates like etag but useful to address etag encryption limitations. Set using filemd5("path/to/source") (Terraform 0.11.12 or later). (The value is only stored in state and not saved by AWS.) | `string` | `null` | no |
 |  [storage\_class](#input\_storage\_class) | Specifies the desired Storage Class for the object. Can be either STANDARD, REDUCED\_REDUNDANCY, ONEZONE\_IA, INTELLIGENT\_TIERING, GLACIER, DEEP\_ARCHIVE, or STANDARD\_IA. Defaults to STANDARD. | `string` | `null` | no |
---
modules/object/main.tf
@@ -33,6 +33,16 @@ resource "aws_s3_object" "this" {

   tags = var.tags

+  dynamic "override_provider" {
+    for_each = var.override_default_tags ? [true] : []
+
+    content {
+      default_tags {
+        tags = {}
+      }
+    }
+  }
+
   lifecycle {
     ignore_changes = [object_lock_retain_until_date]
   }
---
modules/object/variables.tf
@@ -147,3 +147,9 @@ variable "source_hash" {
   type        = string
   default     = null
 }
+
+variable "override_default_tags" {
+  description = "Ignore provider default_tags. S3 objects support a maximum of 10 tags."
+  type        = bool
+  default     = false
+}
---
modules/object/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 3.75"
+      version = ">= 5.24"
     }
   }
 }
---
wrappers/object/main.tf
@@ -23,6 +23,7 @@ module "wrapper" {
   object_lock_legal_hold_status = try(each.value.object_lock_legal_hold_status, var.defaults.object_lock_legal_hold_status, null)
   object_lock_mode              = try(each.value.object_lock_mode, var.defaults.object_lock_mode, null)
   object_lock_retain_until_date = try(each.value.object_lock_retain_until_date, var.defaults.object_lock_retain_until_date, null)
+  default_tags         = try(each.value.override_default_tags, var.defaults.override_default_tags, false)
   server_side_encryption        = try(each.value.server_side_encryption, var.defaults.server_side_encryption, null)
   source_hash                   = try(each.value.source_hash, var.defaults.source_hash, null)
   storage_class                 = try(each.value.storage_class, var.defaults.storage_class, null)
---

---

Choice B:
examples/object/README.md
@@ -37,6 +37,7 @@ Note that this example may create resources which cost money. Run `terraform des
 |  [object](#module\_object) | ../../modules/object | n/a |
 |  [object\_complete](#module\_object\_complete) | ../../modules/object | n/a |
 |  [object\_locked](#module\_object\_locked) | ../../modules/object | n/a |
+|  [object\_with\_override\_default\_tags](#module\_object\_with\_override\_default\_tags) | ../../modules/object | n/a |
 |  [s3\_bucket](#module\_s3\_bucket) | ../../ | n/a |
 |  [s3\_bucket\_with\_object\_lock](#module\_s3\_bucket\_with\_object\_lock) | ../../ | n/a |

---
examples/object/main.tf
@@ -5,6 +5,12 @@ provider "aws" {
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
+
+  default_tags {
+    tags = {
+      Example = "object"
+    }
+  }
 }

 locals {
@@ -25,6 +31,7 @@ module "object" {
     Sensitive = "not-really"
   }
 }
+
 module "object_complete" {
   source = "../../modules/object"

@@ -33,7 +40,7 @@ module "object_complete" {

   content = jsonencode({ data : "value" })

-  acl           = "public-read"
+  # acl           = "public-read"
   storage_class = "ONEZONE_IA"
   force_destroy = true

@@ -68,6 +75,21 @@ module "object_locked" {
   object_lock_retain_until_date = formatdate("YYYY-MM-DD'T'hh:00:00Z", timeadd(timestamp(), "1h")) # some time in the future
 }

+module "object_with_override_default_tags" {
+  source = "../../modules/object"
+
+  bucket = module.s3_bucket.s3_bucket_id
+  key    = "${random_pet.this.id}-local-override-default-tags"
+
+  override_default_tags = true
+
+  file_source = "README.md"
+
+  tags = {
+    Override = "true"
+  }
+}
+
 ##################
 # Extra resources
 ##################
@@ -96,7 +118,13 @@ module "s3_bucket_with_object_lock" {
   bucket        = "${random_pet.this.id}-with-object-lock"
   force_destroy = true

+  object_lock_enabled = true
   object_lock_configuration = {
-    object_lock_enabled = "Enabled"
+    rule = {
+      default_retention = {
+        mode = "GOVERNANCE"
+        days = 1
+      }
+    }
   }
 }
---
modules/object/README.md
@@ -8,13 +8,13 @@ Creates S3 bucket objects with different configurations.
 | Name | Version |
 |------|---------|
 |  [terraform](#requirement\_terraform) | >= 1.0 |
-|  [aws](#requirement\_aws) | >= 3.75 |
+|  [aws](#requirement\_aws) | >= 5.24 |

 ## Providers

 | Name | Version |
 |------|---------|
-|  [aws](#provider\_aws) | >= 3.75 |
+|  [aws](#provider\_aws) | >= 5.24 |

 ## Modules

@@ -50,6 +50,7 @@ No modules.
 |  [object\_lock\_legal\_hold\_status](#input\_object\_lock\_legal\_hold\_status) | The legal hold status that you want to apply to the specified object. Valid values are ON and OFF. | `string` | `null` | no |
 |  [object\_lock\_mode](#input\_object\_lock\_mode) | The object lock retention mode that you want to apply to this object. Valid values are GOVERNANCE and COMPLIANCE. | `string` | `null` | no |
 |  [object\_lock\_retain\_until\_date](#input\_object\_lock\_retain\_until\_date) | The date and time, in RFC3339 format, when this object's object lock will expire. | `string` | `null` | no |
+|  [override\_default\_tags](#input\_override\_default\_tags) | Ignore provider default\_tags. S3 objects support a maximum of 10 tags. | `bool` | `false` | no |
 |  [server\_side\_encryption](#input\_server\_side\_encryption) | Specifies server-side encryption of the object in S3. Valid values are "AES256" and "aws:kms". | `string` | `null` | no |
 |  [source\_hash](#input\_source\_hash) | Triggers updates like etag but useful to address etag encryption limitations. Set using filemd5("path/to/source") (Terraform 0.11.12 or later). (The value is only stored in state and not saved by AWS.) | `string` | `null` | no |
 |  [storage\_class](#input\_storage\_class) | Specifies the desired Storage Class for the object. Can be either STANDARD, REDUCED\_REDUNDANCY, ONEZONE\_IA, INTELLIGENT\_TIERING, GLACIER, DEEP\_ARCHIVE, or STANDARD\_IA. Defaults to STANDARD. | `string` | `null` | no |
---
modules/object/main.tf
@@ -33,6 +33,16 @@ resource "aws_s3_object" "this" {

   tags = var.tags

+  dynamic "override_provider" {
+    for_each = var.override_default_tags ? [true] : []
+
+    content {
+      default_tags {
+        tags = {}
+      }
+    }
+  }
+
   lifecycle {
     ignore_changes = [object_lock_retain_until_date]
   }
---
modules/object/variables.tf
@@ -147,3 +147,9 @@ variable "source_hash" {
   type        = string
   default     = null
 }
+
+variable "override_default_tags" {
+  description = "Ignore provider default_tags. S3 objects support a maximum of 10 tags."
+  type        = bool
+  default     = false
+}
---
modules/object/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 3.75"
+      version = ">= 5.24"
     }
   }
 }
---
wrappers/object/main.tf
@@ -23,6 +23,7 @@ module "wrapper" {
   object_lock_legal_hold_status = try(each.value.object_lock_legal_hold_status, var.defaults.object_lock_legal_hold_status, null)
   object_lock_mode        this      = try(each.value.object_lock_mode, var.defaults.object_lock_mode, null)
   object_lock_retain_until_date = try(each.value.object_lock_retain_until_date, var.defaults.object_lock_retain_until_date, null)
+  override_default_tags         = try(each.value.override_default_tags, var.defaults.override_default_tags, false)
   server_side_encryption        = try(each.value.server_side_encryption, var.defaults.server_side_encryption, null)
   source_hash                   = try(each.value.source_hash, var.defaults.source_hash, null)
   storage_class                 = try(each.value.storage_class, var.defaults.storage_class, null)
---

---

Choice C:
examples/object/README.md
@@ -37,6 +37,7 @@ Note that this example may create resources which cost money. Run `terraform des
 |  [object](#module\_object) | ../../modules/object | n/a |
 |  [object\_complete](#module\_object\_complete) | ../../modules/object | n/a |
 |  [object\_locked](#module\_object\_locked) | ../../modules/object | n/a |
+|  [object\_with\_override\_default\_tags](#module\_object\_with\_override\_default\_tags) | ../../modules/object | n/a |
 |  [s3\_bucket](#module\_s3\_bucket) | ../../ | n/a |
 |  [s3\_bucket\_with\_object\_lock](#module\_s3\_bucket\_with\_object\_lock) | ../../ | n/a |

---
examples/object/main.tf
@@ -5,6 +5,12 @@ provider "aws" {
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
+
+  default_tags {
+    tags = {
+      Example = "object"
+    }
+  }
 }

 locals {
@@ -25,6 +31,7 @@ module "object" {
     Sensitive = "not-really"
   }
 }
+
 module "object_complete" {
   source = "../../modules/object"

@@ -33,7 +40,7 @@ module "object_complete" {

   content = jsonencode({ data : "value" })

-  acl           = "public-read"
+  # acl           = "public-read"
   storage_class = "ONEZONE_IA"
   force_destroy = true

@@ -68,6 +75,21 @@ module "object_locked" {
   object_lock_retain_until_date = formatdate("YYYY-MM-DD'T'hh:00:00Z", timeadd(timestamp(), "1h")) # some time in the future
 }

+module "object_with_override_default_tags" {
+  source = "../../modules/object"
+
+  bucket = module.s3_bucket.s3_bucket_id
+  key    = "${random_pet.this.id}-local-override-default-tags"
+
+  override_default_tags = true
+
+  file_source = "README.md"
+
+  tags = {
+    Override = "true"
+  }
+}
+
 ##################
 # Extra resources
 ##################
@@ -96,7 +118,13 @@ module "s3_bucket_with_object_lock" {
   bucket        = "${random_pet.this.id}-with-object-lock"
   force_destroy = true

+  object_lock_enabled = true
   object_lock_configuration = {
-    object_lock_enabled = "Enabled"
+    rule = {
+      default_retention = {
+        mode = "GOVERNANCE"
+        days = 1
+      }
+    }
   }
 }
---
modules/object/README.md
@@ -8,13 +8,13 @@ Creates S3 bucket objects with different configurations.
 | Name | Version |
 |------|---------|
 |  [terraform](#requirement\_terraform) | >= 1.0 |
-|  [aws](#requirement\_aws) | >= 3.75 |
+|  [aws](#requirement\_aws) | >= 5.24 |

 ## Providers

 | Name | Version |
 |------|---------|
-|  [aws](#provider\_aws) | >= 3.75 |
+|  [aws](#provider\_aws) | >= 5.24 |

 ## Modules

@@ -50,6 +50,7 @@ No modules.
 |  [object\_lock\_legal\_hold\_status](#input\_object\_lock\_legal\_hold\_status) | The legal hold status that you want to apply to the specified object. Valid values are ON and OFF. | `string` | `null` | no |
 |  [object\_lock\_mode](#input\_object\_lock\_mode) | The object lock retention mode that you want to apply to this object. Valid values are GOVERNANCE and COMPLIANCE. | `string` | `null` | no |
 |  [object\_lock\_retain\_until\_date](#input\_object\_lock\_retain\_until\_date) | The date and time, in RFC3339 format, when this object's object lock will expire. | `string` | `null` | no |
+|  [override\_default\_tags](#input\_override\_default\_tags) | Ignore provider default\_tags. S3 objects support a maximum of 10 tags. | `bool` | `false` | no |
 |  [server\_side\_encryption](#input\_server\_side\_encryption) | Specifies server-side encryption of the object in S3. Valid values are "AES256" and "aws:kms". | `string` | `null` | no |
 |  [source\_hash](#input\_source\_hash) | Triggers updates like etag but useful to address etag encryption limitations. Set using filemd5("path/to/source") (Terraform 0.11.12 or later). (The value is only stored in state and not saved by AWS.) | `string` | `null` | no |
 |  [storage\_class](#input\_storage\_class) | Specifies the desired Storage Class for the object. Can be either STANDARD, REDUCED\_REDUNDANCY, ONEZONE\_IA, INTELLIGENT\_TIERING, GLACIER, DEEP\_ARCHIVE, or STANDARD\_IA. Defaults to STANDARD. | `string` | `null` | no |
---
modules/object/main.tf
@@ -33,6 +33,16 @@ resource "aws_s3_object" "this" {

   tags = var.tags

+  dynamic "override_provider" {
+    for_each = var.override_default_tags ? [true] : []
+
+    content {
+      default_tags {
+        tags = {}
+      }
+    }
+  }
+
   lifecycle {
     ignore_changes = [object_lock_retain_until_date]
   }
---
modules/object/variables.tf
@@ -147,3 +147,9 @@ variable "source_hash" {
   type        = string
   default     = null
 }
+
+variable "override_default_tags" {
+  description = "Ignore provider default_tags. S3 objects support a maximum of 10 tags."
+  type        = bool
+  default     = false
+}
---
modules/object/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 3.75"
+      version = ">= 5.24"
     }
   }
 }
---
wrappers/object/main.tf
@@ -23,6 +23,7 @@ module "wrapper" {
   object_lock_legal_hold_status = try(each.value.object_lock_legal_hold_status, var.defaults.object_lock_legal_hold_status, null)
   object_lock_mode              = try(each.value.object_lock_mode, var.defaults.object_lock_mode, null)
   object_lock_retain_until_date = try(each.value.object_lock_retain_until_date, var.defaults.object_lock_retain_until_date, null)
+  override_default_tags         = try(each.value.override_default_tags, var.defaults.override_default_tags, false)
   server_side_encryption        = try(each.value.server_side_encryption, var.defaults.server_side_encryption, null)
   source_hash                   = try(each.value.source_hash, var.defaults.source_hash, null)
   storage_class                 = try(each.value.storage_class, var.defaults.storage_class, null)
---

---

Choice D:
examples/object/README.md
@@ -37,6 +37,7 @@ Note that this example may create resources which cost money. Run `terraform des
 |  [object](#module\_object) | ../../modules/object | n/a |
 |  [object\_complete](#module\_object\_complete) | ../../modules/object | n/a |
 |  [object\_locked](#module\_object\_locked) | ../../modules/object | n/a |
+|  [object\_with\_override\_default\_tags](#module\_object\_with\_override\_default\_tags) | ../../modules/object | n/a |
 |  [s3\_bucket](#module\_s3\_bucket) | ../../ | n/a |
 |  [s3\_bucket\_with\_object\_lock](#module\_s3\_bucket\_with\_object\_lock) | ../../ | n/a |

---
examples/object/main.tf
@@ -5,6 +5,12 @@ provider "aws" {
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
+
+  default_tags {
+    tags = {
+      Example = "object"
+    }
+  }
 }

 locals {
@@ -25,6 +31,7 @@ module "object" {
     Sensitive = "not-really"
   }
 }
+
 module "object_complete" {
   source = "../../modules/object"

@@ -33,7 +40,7 @@ module "object_complete" {

   content = jsonencode({ data : "value" })

-  acl           = "public-read"
+  # acl           = "public-read"
   storage_class = "ONEZONE_IA"
   force_destroy = true

@@ -68,6 +75,21 @@ module "object_locked" {
   object_lock_retain_until_date = formatdate("YYYY-MM-DD'T'hh:00:00Z", timeadd(timestamp(), "1h")) # some time in the future
 }

+module "object_with_override_default_tags" {
+  source = "../../modules/object"
+
+  bucket = module.s3_bucket.s3_bucket_id
+  key    = "${random_pet.this.id}-local-override-default-tags"
+
+  override_default_tags = true
+
+  file_source = "README.md"
+
+  tags = {
+    Override = "true"
+  }
+}
+
 ##################
 # Extra resources
 ##################
@@ -96,7 +118,13 @@ module "s3_bucket_with_object_lock" {
   bucket        = "${random_pet.this.id}-with-object-lock"
   force_destroy = true

+  object_lock_enabled = true
   object_lock_configuration = {
-    object_lock_enabled = "Enabled"
+    rule = {
+      default_retention = {
+        mode = "GOVERNANCE"
+        days = 1
+      }
+    }
   }
 }
---
modules/object/README.md
@@ -8,13 +8,13 @@ Creates S3 bucket objects with different configurations.
 | Name | Version |
 |------|---------|
 |  [terraform](#requirement\_terraform) | >= 1.0 |
-|  [aws](#requirement\_aws) | >= 3.75 |
+|  [aws](#requirement\_aws) | >= 5.24 |

 ## Providers

 | Name | Version |
 |------|---------|
-|  [aws](#provider\_aws) | >= 3.75 |
+|  [aws](#provider\_aws) | >= 5.24 |

 ## Modules

@@ -50,6 +50,7 @@ No modules.
 |  [object\_lock\_legal\_hold\_status](#input\_object\_lock\_legal\_hold\_status) | The legal hold status that you want to apply to the specified object. Valid values are ON and OFF. | `string` | `null` | no |
 |  [object\_lock\_mode](#input\_object\_lock\_mode) | The object lock retention mode that you want to apply to this object. Valid values are GOVERNANCE and COMPLIANCE. | `string` | `null` | no |
 |  [object\_lock\_retain\_until\_date](#input\_object\_lock\_retain\_until\_date) | The date and time, in RFC3339 format, when this object's object lock will expire. | `string` | `null` | no |
+|  [override\_default\_tags](#input\_override\_default\_tags) | Ignore provider default\_tags. S3 objects support a maximum of 10 tags. | `bool` | `false` | no |
 |  [server\_side\_encryption](#input\_server\_side\_encryption) | Specifies server-side encryption of the object in S3. Valid values are "AES256" and "aws:kms". | `string` | `null` | no |
 |  [source\_hash](#input\_source\_hash) | Triggers updates like etag but useful to address etag encryption limitations. Set using filemd5("path/to/source") (Terraform 0.11.12 or later). (The value is only stored in state and not saved by AWS.) | `string` | `null` | no |
 |  [storage\_class](#input\_storage\_class) | Specifies the desired Storage Class for the object. Can be either STANDARD, REDUCED\_REDUNDANCY, ONEZONE\_IA, INTELLIGENT\_TIERING, GLACIER, DEEP\_ARCHIVE, or STANDARD\_IA. Defaults to STANDARD. | `string` | `null` | no |
---
modules/object/main.tf
@@ -33,6 +33,16 @@ resource "aws_s3_object" "this" {

   tags = var.tags

+  dynamic "override_provider" {
+    for_each = var.override_default_tags ? [true] : []
+
+    content {
+      default_tags {
+        tags = {}
+      }
+    }
+  }
+
   lifecycle {
     ignore_changes = [object_lock_retain_until_date]
 {
@@  }
---
modules/object/variables.tf
@@ -147,3 +147,9 @@ variable "source_hash" {
   type        = string
   default     = null
 }
+
+variable "override_default_tags" {
+  description = "Ignore provider default_tags. S3 objects support a maximum of 10 tags."
+  type        = bool
+  default     = false
+}
---
modules/object/versions.tf
@@ -4,7 +4,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = ">= 3.75"
+      version = ">= 5.24"
     }
   }
 }
---
wrappers/object/main.tf
@@ -23,6 +23,7 @@ module "wrapper" {
   object_lock_legal_hold_status = try(each.value.object_lock_legal_hold_status, var.defaults.object_lock_legal_hold_status, null)
   object_lock_mode              = try(each.value.object_lock_mode, var.defaults.object_lock_mode, null)
   object_lock_retain_until_date = try(each.value.object_lock_retain_until_date, var.defaults.object_lock_retain_until_date, null)
+  override_default_tags         = try(each.value.override_default_tags, var.defaults.override_default_tags, false)
   server_side_encryption        = try(each.value.server_side_encryption, var.defaults.server_side_encryption, null)
   source_hash                   = try(each.value.source_hash, var.defaults.source_hash, null)
   storage_class                 = try(each.value.storage_class, var.defaults.storage_class, null)
---

---


Choose the best Terraform patch (A/B/C/D) that implements the requested S3 security change safely. Only respond with a single uppercase letter.

Task Description:
## Description
<!--- Describe your changes in detail -->
Adds attachable CloudFront Origin Access Identities (deprecated by AWS) and CloudFront Origin Access Identities policies.

## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
An AWS S3 bucket is often connected with an AWS CloudFront distribution and configuring a securely authenticated connection should be trivial. Workarounds such as https://github.com/terraform-aws-modules/terraform-aws-cloudfront/blob/master/examples/complete/main.tf#L294-L327 should not be needed.

## Breaking Changes
<!-- Does this break backwards compatibility with the current major version? -->
<!-- If so, please provide an explanation why it is necessary. -->
None.

## How Has This Been Tested?
- [ ] I have updated at least one of the `examples/*` to demonstrate and validate my change(s)
- [ ] I have tested and validated these changes using one or more of the provided `examples/*` projects
<!--- Users should start with an existing example as its written, deploy it, then check their changes against it -->
<!--- This will highlight breaking/disruptive changes. Once you have checked, deploy your changes to verify -->
<!--- Please describe how you tested your changes -->
- [ ] I have executed `pre-commit run -a` on my pull request
<!--- Please see https://github.com/antonbabenko/pre-commit-terraform#how-to-install for how to install -->

---

Choice A:
main.tf
@@ -556,6 +556,8 @@ data "aws_iam_policy_document" "combined" {
     var.attach_elb_log_delivery_policy ? data.aws_iam_policy_document.elb_log_delivery[0].json : "",
     var.attach_lb_log_delivery_policy ? data.aws_iam_policy_document.lb_log_delivery[0].json : "",
     var.attach_access_log_delivery_policy ? data.aws_iam_policy_document.access_log_delivery[0].json : "",
+    var.attach_cloudfront_oai_read_policy ? data.aws_iam_policy_document.cloudfront_oai_read_policy[0].json : "",
+    var.attach_cloudfront_oac_read_policy ? data.aws_iam_policy_document.cloudfront_oac_read_policy[0].json : "",
     var.attach_require_latest_tls_policy ? data.aws_iam_policy_document.require_latest_tls[0].json : "",
     var.attach_deny_insecure_transport_policy ? data.aws_iam_policy_document.deny_insecure_transport[0].json : "",
     var.attach_deny_unencrypted_object_uploads ? data.aws_iam_policy_document.deny_unencrypted_object_uploads[0].json : "",
@@ -763,6 +765,66 @@ data "aws_iam_policy_document" "access_log_delivery" {
   }
 }

+# Grant read and list access to CloudFront Origin Access Identities (deprecated by AWS)
+data "aws_iam_policy_document" "cloudfront_oai_read_policy" {
+  count = local.create_bucket && var.attach_cloudfront_oai_read_policy ? 1 : 0
+
+  statement {
+    sid = "AWSCloudFrontOAIRead"
+    actions   = ["s3:GetObject"]
+    resources = ["${aws_s3_bucket.this[0].arn}/*"]
+    principals {
+      type        = "AWS"
+      identifiers = var.cloudfront_oai_iam_arns
+    }
+  }
+
+  statement {
+    sid = "AWSCloudFrontOAIList"
+    actions   = ["s3:ListBucket"]
+    resources = [aws_s3_bucket.this[0].arn]
+    principals {
+      type        = "AWS"
+      identifiers = var.cloudfront_oai_iam_arns
+    }
+  }
+}
+
+# Grant read and list access to CloudFront Origin Access Controls
+data "aws_iam_policy_document" "cloudfront_oac_read_policy" {
+  count = local.create_bucket && var.attach_cloudfront_oac_read_policy ? 1 : 0
+
+  statement {
+    sid       = "AWSCloudFrontOACRead"
+    actions   = ["s3:GetObject"]
+     = ["${aws_s3_bucket.this[0].arn}/*"]
+    principals {
+      type        = "Service"
+      identifiers = ["cloudfront.amazonaws.com"]
+    }
+    condition {
+      test     = "StringEquals"
+      variable = "aws:SourceArn"
+      values   = var.cloudfront_oac_distribution_arns
+    }
+  }
+
+  statement {
+    sid       = "AWSCloudFrontOACList"
+    actions   = ["s3:ListBucket"]
+    resources = [aws_s3_bucket.this[0].arn]
+    principals {
+      type        = "Service"
+      identifiers = ["cloudfront.amazonaws.com"]
+    }
+    condition {
+      test     = "StringEquals"
+      variable = "aws:SourceArn"
+      values   = var.cloudfront_oac_distribution_arns
+    }
+  }
+}
+
 data "aws_iam_policy_document" "deny_insecure_transport" {
   count = local.create_bucket && var.attach_deny_insecure_transport_policy ? 1 : 0

---
variables.tf
@@ -22,6 +22,18 @@ variable "attach_access_log_delivery_policy" {
   default     = false
 }

+variable "attach_cloudfront_oai_read_policy" {
+  description = "Controls if S3 bucket should have CloudFront Origin Access Identities policy attached (configure with `cloudfront_oai_iam_arns`)"
+  type        = bool
+  default     = false
+}
+
+variable "attach_cloudfront_oac_read_policy" {
+  description = "Controls if S3 bucket should have CloudFront Origin Access Controls policy attached (configure with `cloudfront_oac_distribution_arns`)"
+  type        = bool
+  default     = false
+}
+
 variable "attach_deny_insecure_transport_policy" {
   description = "Controls if S3 bucket should have deny non-SSL transport policy attached"
   type        = bool
@@ -100,6 +112,18 @@ variable "acl" {
   default     = null
 }

+variable "cloudfront_oai_iam_arns" {
+  description = "(Optional) List of CloudFront IAM ARNs to use in the CloudFront Origin Access Identities policy"
+  type        = list(string)
+  default     = []
+}
+
+variable "cloudfront_oac_distribution_arns" {
+  description = "(Optional) List of CloudFront distribution ARNs to use in the CloudFront Origin Access Controls policy"
+  type        = list(string)
+  default     = []
+}
+
 variable "policy" {
   description = "(Optional) A valid bucket policy JSON document. Note that if the policy document is not specific enough (but still valid), Terraform may view the policy as constantly changing in a terraform plan. In this case, please make sure you use the verbose/specific version of the policy. For more information about building AWS IAM policy documents with Terraform, see the AWS IAM Policy Document Guide."
   type        = string
---

---

Choice B:
main.tf
@@ -556,6 +556,8 @@ data "aws_iam_policy_document" -763,6 {
     var.attach_elb_log_delivery_policy ? data.aws_iam_policy_document.elb_log_delivery[0].json : "",
     var.attach_lb_log_delivery_policy ? data.aws_iam_policy_document.lb_log_delivery[0].json : "",
     var.attach_access_log_delivery_policy ? data.aws_iam_policy_document.access_log_delivery[0].json : "",
+    var.attach_cloudfront_oai_read_policy ? data.aws_iam_policy_document.cloudfront_oai_read_policy[0].json : "",
+    var.attach_cloudfront_oac_read_policy ? data.aws_iam_policy_document.cloudfront_oac_read_policy[0].json : "",
     var.attach_require_latest_tls_policy ? data.aws_iam_policy_document.require_latest_tls[0].json : "",
     var.attach_deny_insecure_transport_policy ? data.aws_iam_policy_document.deny_insecure_transport[0].json : "",
     var.attach_deny_unencrypted_object_uploads ? data.aws_iam_policy_document.deny_unencrypted_object_uploads[0].json : "",
@@ -763,6 +765,66 @@ data "aws_iam_policy_document" "access_log_delivery" {
   }
 }

+# Grant read and list access to CloudFront Origin Access Identities (deprecated by AWS)
+data "aws_iam_policy_document" "cloudfront_oai_read_policy" {
+  count = local.create_bucket && var.attach_cloudfront_oai_read_policy ? 1 : 0
+
+  statement {
+    sid = "AWSCloudFrontOAIRead"
+    actions   = ["s3:GetObject"]
+    resources = ["${aws_s3_bucket.this[0].arn}/*"]
+    principals {
+      type        = "AWS"
+      identifiers = var.cloudfront_oai_iam_arns
+    }
+  }
+
+  statement {
+    sid = "AWSCloudFrontOAIList"
+    actions   = ["s3:ListBucket"]
+    resources = [aws_s3_bucket.this[0].arn]
+    principals {
+      type        = "AWS"
+      identifiers = var.cloudfront_oai_iam_arns
+    }
+  }
+}
+
+# Grant read and list access to CloudFront Origin Access Controls
+data "aws_iam_policy_document" "cloudfront_oac_read_policy" {
+  count = local.create_bucket && var.attach_cloudfront_oac_read_policy ? 1 : 0
+
+  statement {
+    sid       = "AWSCloudFrontOACRead"
+    actions   = ["s3:GetObject"]
+    resources = ["${aws_s3_bucket.this[0].arn}/*"]
+    principals {
+      type        = "Service"
+      identifiers = ["cloudfront.amazonaws.com"]
+    }
+    condition {
+      test     = "StringEquals"
+      variable = "aws:SourceArn"
+      values   = var.cloudfront_oac_distribution_arns
+    }
+  }
+
+  statement {
+    sid       = "AWSCloudFrontOACList"
+    actions   = ["s3:ListBucket"]
+    resources = [aws_s3_bucket.this[0].arn]
+    principals {
+      type        = "Service"
+      identifiers = ["cloudfront.amazonaws.com"]
+    }
+    condition {
+      test     = "StringEquals"
+      variable = "aws:SourceArn"
+      values   = var.cloudfront_oac_distribution_arns
+    }
+  }
+}
+
 data "aws_iam_policy_document" "deny_insecure_transport" {
   count = local.create_bucket && var.attach_deny_insecure_transport_policy ? 1 : 0

---
variables.tf
@@ -22,6 +22,18 @@ variable "attach_access_log_delivery_policy" {
   default     = false
 }

+variable "attach_cloudfront_oai_read_policy" {
+  description = "Controls if S3 bucket should have CloudFront Origin Access Identities policy attached (configure with `cloudfront_oai_iam_arns`)"
+  type        = bool
+  default     = false
+}
+
+variable "attach_cloudfront_oac_read_policy" {
+  description = "Controls if S3 bucket should have CloudFront Origin Access Controls policy attached (configure with `cloudfront_oac_distribution_arns`)"
+  type        = bool
+  default     = false
+}
+
 variable "attach_deny_insecure_transport_policy" {
   description = "Controls if S3 bucket should have deny non-SSL transport policy attached"
   type        = bool
@@ -100,6 +112,18 @@ variable "acl" {
   default     = null
 }

+variable "cloudfront_oai_iam_arns" {
+  description = "(Optional) List of CloudFront IAM ARNs to use in the CloudFront Origin Access Identities policy"
+  type        = list(string)
+  default     = []
+}
+
+variable "cloudfront_oac_distribution_arns" {
+  description = "(Optional) List of CloudFront distribution ARNs to use in the CloudFront Origin Access Controls policy"
+  type        = list(string)
+  default     = []
+}
+
 variable "policy" {
   description = "(Optional) A valid bucket policy JSON document. Note that if the policy document is not specific enough (but still valid), Terraform may view the policy as constantly changing in a terraform plan. In this case, please make sure you use the verbose/specific version of the policy. For more information about building AWS IAM policy documents with Terraform, see the AWS IAM Policy Document Guide."
   type        = string
---

---

Choice C:
main.tf
@@ -556,6 +556,8 @@ data "aws_iam_policy_document" "combined"      var.attach_elb_log_delivery_policy ? data.aws_iam_policy_document.elb_log_delivery[0].json : "",
     var.attach_lb_log_delivery_policy ? data.aws_iam_policy_document.lb_log_delivery[0].json : "",
     var.attach_access_log_delivery_policy ? data.aws_iam_policy_document.access_log_delivery[0].json : "",
+    var.attach_cloudfront_oai_read_policy ? data.aws_iam_policy_document.cloudfront_oai_read_policy[0].json : "",
+    var.attach_cloudfront_oac_read_policy ? data.aws_iam_policy_document.cloudfront_oac_read_policy[0].json : "",
     var.attach_require_latest_tls_policy ? data.aws_iam_policy_document.require_latest_tls[0].json : "",
     var.attach_deny_insecure_transport_policy ? data.aws_iam_policy_document.deny_insecure_transport[0].json : "",
     var.attach_deny_unencrypted_object_uploads ? data.aws_iam_policy_document.deny_unencrypted_object_uploads[0].json : "",
@@ -763,6 +765,66 @@ data "aws_iam_policy_document" "access_log_delivery" {
   }
 }

+# Grant read and list access to CloudFront Origin Access Identities (deprecated by AWS)
+data "aws_iam_policy_document" "cloudfront_oai_read_policy" {
+  count = local.create_bucket && var.attach_cloudfront_oai_read_policy ? 1 : 0
+
+  statement {
+    sid = "AWSCloudFrontOAIRead"
+    actions   = ["s3:GetObject"]
+    resources = ["${aws_s3_bucket.this[0].arn}/*"]
+    principals {
+      type        = "AWS"
+      identifiers = var.cloudfront_oai_iam_arns
+    }
+  }
+
+  statement {
+    sid = "AWSCloudFrontOAIList"
+    actions   = ["s3:ListBucket"]
+    resources = [aws_s3_bucket.this[0].arn]
+    principals {
+      type        = "AWS"
+      identifiers = var.cloudfront_oai_iam_arns
+    }
+  }
+}
+
+# Grant read and list access to CloudFront Origin Access Controls
+data "aws_iam_policy_document" "cloudfront_oac_read_policy" {
+  count = local.create_bucket && var.attach_cloudfront_oac_read_policy ? 1 : 0
+
+  statement {
+    sid       = "AWSCloudFrontOACRead"
+    actions   = ["s3:GetObject"]
+    resources = ["${aws_s3_bucket.this[0].arn}/*"]
+    principals {
+      type        = "Service"
+      identifiers = ["cloudfront.amazonaws.com"]
+    }
+    condition {
+      test     = "StringEquals"
+      variable = "aws:SourceArn"
+      values   = var.cloudfront_oac_distribution_arns
+    }
+  }
+
+  statement {
+    sid       = "AWSCloudFrontOACList"
+    actions   = ["s3:ListBucket"]
+    resources = [aws_s3_bucket.this[0].arn]
+    principals {
+      type        = "Service"
+      identifiers = ["cloudfront.amazonaws.com"]
+    }
+    condition {
+      test     = "StringEquals"
+      variable = "aws:SourceArn"
+      values   = var.cloudfront_oac_distribution_arns
+    }
+  }
+}
+
 data "aws_iam_policy_document" "deny_insecure_transport" {
   count = local.create_bucket && var.attach_deny_insecure_transport_policy ? 1 : 0

---
variables.tf
@@ -22,6 +22,18 @@ variable "attach_access_log_delivery_policy" {
   default     = false
 }

+variable "attach_cloudfront_oai_read_policy" {
+  description = "Controls if S3 bucket should have CloudFront Origin Access Identities policy attached (configure with `cloudfront_oai_iam_arns`)"
+  type        = bool
+  default     = false
+}
+
+variable "attach_cloudfront_oac_read_policy" {
+  description = "Controls if S3 bucket should have CloudFront Origin Access Controls policy attached (configure with `cloudfront_oac_distribution_arns`)"
+  type        = bool
+  default     = false
+}
+
 variable "attach_deny_insecure_transport_policy" {
   description = "Controls if S3 bucket should have deny non-SSL transport policy attached"
   type        = bool
@@ -100,6 +112,18 @@ variable "acl" {
   default     = null
 }

+variable "cloudfront_oai_iam_arns" {
+  description = "(Optional) List of CloudFront IAM ARNs to use in the CloudFront Origin Access Identities policy"
+  type        = list(string)
+  default     = []
+}
+
+variable "cloudfront_oac_distribution_arns" {
+  description = "(Optional) List of CloudFront distribution ARNs to use in the CloudFront Origin Access Controls policy"
+  type        = list(string)
+  default     = []
+}
+
 variable "policy" {
   description = "(Optional) A valid bucket policy JSON document. Note that if the policy document is not specific enough (but still valid), Terraform may view the policy as constantly changing in a terraform plan. In this case, please make sure you use the verbose/specific version of the policy. For more information about building AWS IAM policy documents with Terraform, see the AWS IAM Policy Document Guide."
   type        = string
---

---

Choice D:
main.tf
@@ -556,6 +556,8 @@ data "aws_iam_policy_document" "combined" {
     var.attach_elb_log_delivery_policy ? data.aws_iam_policy_document.elb_log_delivery[0].json : "",
     var.attach_lb_log_delivery_policy ? data.aws_iam_policy_document.lb_log_delivery[0].json : "",
     var.attach_access_log_delivery_policy ? data.aws_iam_policy_document.access_log_delivery[0].json : "",
+    var.attach_cloudfront_oai_read_policy ? data.aws_iam_policy_document.cloudfront_oai_read_policy[0].json : "",
+    var.attach_cloudfront_oac_read_policy ? data.aws_iam_policy_document.cloudfront_oac_read_policy[0].json : "",
     var.attach_require_latest_tls_policy ? data.aws_iam_policy_document.require_latest_tls[0].json : "",
     var.attach_deny_insecure_transport_policy ? data.aws_iam_policy_document.deny_insecure_transport[0].json : "",
     var.attach_deny_unencrypted_object_uploads ? data.aws_iam_policy_document.deny_unencrypted_object_uploads[0].json : "",
@@ -763,6 +765,66 @@ data "aws_iam_policy_document" "access_log_delivery" {
   }
 }

+# Grant read and list access to CloudFront Origin Access Identities (deprecated by AWS)
+data "aws_iam_policy_document" "cloudfront_oai_read_policy" {
+  count = local.create_bucket && var.attach_cloudfront_oai_read_policy ? 1 : 0
+
+  statement {
+    sid = "AWSCloudFrontOAIRead"
+    actions   = ["s3:GetObject"]
+    resources = ["${aws_s3_bucket.this[0].arn}/*"]
+    principals {
+      type        = "AWS"
+      identifiers = var.cloudfront_oai_iam_arns
+    }
+  }
+
+  statement {
+    sid = "AWSCloudFrontOAIList"
+    actions   = ["s3:ListBucket"]
+    resources = [aws_s3_bucket.this[0].arn]
+    principals {
+      type        = "AWS"
+      identifiers = var.cloudfront_oai_iam_arns
+    }
+  }
+}
+
+# Grant read and list access to CloudFront Origin Access Controls
+data "aws_iam_policy_document" "cloudfront_oac_read_policy" {
+  count = local.create_bucket && var.attach_cloudfront_oac_read_policy ? 1 : 0
+
+  statement {
+    sid       = "AWSCloudFrontOACRead"
+    actions   = ["s3:GetObject"]
+    resources = ["${aws_s3_bucket.this[0].arn}/*"]
+    principals {
+      type        = "Service"
+      identifiers = ["cloudfront.amazonaws.com"]
+    }
+    condition {
+      test     = "StringEquals"
+      variable = "aws:SourceArn"
+      values   = var.cloudfront_oac_distribution_arns
+    }
+  }
+
+  statement {
+    sid       = "AWSCloudFrontOACList"
+    actions   = ["s3:ListBucket"]
+    resources = [aws_s3_bucket.this[0].arn]
+    principals {
+      type        = "Service"
+      identifiers = ["cloudfront.amazonaws.com"]
+    }
+    condition {
+      test     = "StringEquals"
+      variable = "aws:SourceArn"
+      values   = var.cloudfront_oac_distribution_arns
+    }
+  }
+}
+
 data "aws_iam_policy_document" "deny_insecure_transport" {
   count = local.create_bucket && var.attach_deny_insecure_transport_policy ? 1 : 0

---
variables.tf
@@ -22,6 +22,18 @@ variable "attach_access_log_delivery_policy" {
   default     = false
 }

+variable "attach_cloudfront_oai_read_policy" {
+  description = "Controls if S3 bucket should have CloudFront Origin Access Identities policy attached (configure with `cloudfront_oai_iam_arns`)"
+  type        = bool
+  default     = false
+}
+
+variable "attach_cloudfront_oac_read_policy" {
+  description = "Controls if S3 bucket should have CloudFront Origin Access Controls policy attached (configure with `cloudfront_oac_distribution_arns`)"
+  type        = bool
+  default     = false
+}
+
 variable "attach_deny_insecure_transport_policy" {
   description = "Controls if S3 bucket should have deny non-SSL transport policy attached"
   type        = bool
@@ -100,6 +112,18 @@ variable "acl" {
   default     = null
 }

+variable "cloudfront_oai_iam_arns" {
+  description = "(Optional) List of CloudFront IAM ARNs to use in the CloudFront Origin Access Identities policy"
+  type        = list(string)
+  default     = []
+}
+
+variable "cloudfront_oac_distribution_arns" {
+  description = "(Optional) List of CloudFront distribution ARNs to use in the CloudFront Origin Access Controls policy"
+  type        = list(string)
+  default     = []
+}
+
 variable "policy" {
   description = "(Optional) A valid bucket policy JSON document. Note that if the policy document is not specific enough (but still valid), Terraform may view the policy as constantly changing in a terraform plan. In this case, please make sure you use the verbose/specific version of the policy. For more information about building AWS IAM policy documents with Terraform, see the AWS IAM Policy Document Guide."
   type        = string
---

---


Choose the best Terraform patch (A/B/C/D) that implements the requested S3 security change safely. Only respond with a single uppercase letter.

Task Description:
## Description
<!--- Describe your changes in detail -->

This skips executing the `data.aws_canonical_user_id.this` data source unless it is actually needed.

The data source is only needed when the `aws_s3_bucket_acl.this` resource needs to be created **and** the `var.owner["id"]` value isn't available.

## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->

As per [the `data.aws_canonical_user_id` documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/canonical_user_id), this data source requires the `s3:ListAllMyBuckets` IAM permission. Note that this permission isn't required by anything else in this module.

When the data source isn't needed, then by the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege), we shouldn't require the `s3:ListAllMyBuckets` permission.

This additional permission is particularly obvious when [migrating](https://developer.hashicorp.com/terraform/tutorials/configuration-language/move-config) existing `aws_s3_*` resources into this module.

## Breaking Changes
<!-- Does this break backwards compatibility with the current major version? -->
<!-- If so, please provide an explanation why it is necessary. -->

Not a breaking change:

 - the module interface (i.e. input and output variables) has not changed; and,
 - for existing use cases where the IAM entity already has the `s3:ListAllMyBuckets` permission, the module will continue to behave as before except simply skip the `ListBuckets` S3 API calls.

## How Has This Been Tested?
- [x] I have updated at least one of the `examples/*` to demonstrate and validate my change(s) - _No interface changes._
- [x] I have tested and validated these changes using one or more of the provided `examples/*` projects
<!--- Users should start with an existing example as its written, deploy it, then check their changes against it -->
<!--- This will highlight breaking/disruptive changes. Once you have checked, deploy your changes to verify -->
<!--- Please describe how you tested your changes -->
- [x] I have executed `pre-commit run -a` on my pull request
<!--- Please see https://github.com/antonbabenko/pre-commit-terraform#how-to-install for how to install -->

---

Choice A:
main.tf
@@ -1,13 +1,17 @@
 data "aws_region" "current" {}

-data "aws_canonical_user_id" "this" {}
+data "aws_canonical_user_id" "this" {
+  count = local.create_bucket && local.create_bucket_acl && try(var.owner["id"], null) == null ? 1 : 0
+}

 data "aws_caller_identity" "current" {}

 data "aws_partition" "current" {}
 locals {
   create_bucket = var.create_bucket && var.putin_khuylo

+  create_bucket_acl = (var.acl != null && var.acl != "null") || length(local.grants) > 0
+
   attach_policy = var.attach_require_latest_tls_policy || var.attach_elb_log_delivery_policy || var.attach_lb_log_delivery_policy || var.attach_deny_insecure_transport_policy || var.attach_inventory_destination_policy || var.attach_deny_incorrect_encryption_headers || var.attach_deny_incorrect_kms_key_sse || var.attach_deny_unencrypted_object_uploads || var.attach_policy

   # Variables with "aws_s3_bucket_acl" `any` should be jsonencode()'d when value is coming from Terragrunt
@@ -39,7 +43,7 @@ resource "aws_s3_bucket_logging" "this" {
 }

 resource "aws_s3_bucket_acl" "this" {
-  count = local.create_bucket && ((var.acl != null && var.acl != "null") || length(local.grants) > 0) ? 1 : 0
+  count = local.create_bucket && local.create_bucket_acl ? 1 : 0

   bucket                = aws_s3_bucket.this[0].id
   expected_bucket_owner = var.expected_bucket_owner
@@ -67,7 +71,7 @@ resource "aws_s3_bucket_acl" "this" {
       }

       owner {
-        id           = try(var.owner["id"], data.aws_canonical_user_id.this.id)
+        id           = try(var.owner["id"], data.aws_canonical_user_id.this[0].id)
         display_name = try(var.owner["display_name"], null)
       }
     }
---

---

Choice B:
main.tf
@@ -1,13 +1,17 @@
 data "aws_region" "current" {}

-data "aws_canonical_user_id" "this" {}
+data "aws_canonical_user_id" "this" {
+  count = local.create_bucket && local.create_bucket_acl && try(var.owner["id"], null) == null ? 1 : 0
+}

 data "aws_caller_identity" "current" {}

 data "aws_partition" "current" {}
 locals {
   create_bucket = var.create_bucket && var.putin_khuylo

+  create_bucket_acl = (var.acl != null && var.acl != "null") || length(local.grants) > 0
+
   attach_policy = var.attach_require_latest_tls_policy || var.attach_elb_log_delivery_policy || var.attach_lb_log_delivery_policy || var.attach_deny_insecure_transport_policy || var.attach_inventory_destination_policy || var.attach_deny_incorrect_encryption_headers || var.attach_deny_incorrect_kms_key_sse || var.attach_deny_unencrypted_object_uploads || var.attach_policy

   # Variables with type `any` should be jsonencode()'d when value is coming from Terragrunt
@@ -39,7 +43,7 @@ resource "aws_s3_bucket_logging" "this" {
 }

 resource "aws_s3_bucket_acl" "this" {
-  count = local.create_bucket && ((var.acl != null && var.acl != "null") || length(local.grants) > 0) ? 1 : 0
+  count = local.create_bucket && local.create_bucket_acl ? 1 : 0

   bucket                = aws_s3_bucket.this[0].id
   expected_bucket_owner = var.expected_bucket_owner
@@ -67,7 +71,7 @@ resource "aws_s3_bucket_acl" "this" {
       }

       owner {
-        id           = try(var.owner["id"], data.aws_canonical_user_id.this.id)
+        id           = try(var.owner["id"], data.aws_canonical_user_id.this[0].id)
         display_name = try(var.owner["display_name"], null)
       }
     }
---

---

Choice C:
main.tf
@@ -1,13 +1,17 @@
 data "aws_region" "current" {}

-data "aws_canonical_user_id" "this" {}
+data "aws_canonical_user_id" "this" {
+  count = local.create_bucket && local.create_bucket_acl && try(var.owner["id"], null) == null ? 1 : 0
+}

 data "aws_caller_identity" "current" {}

 data "aws_partition" "current" {}
 locals {
   create_bucket = var.create_bucket && var.putin_khuylo

+  create_bucket_acl = (var.acl != null && var.acl != "null") || length(local.grants) > 0
+
   attach_policy = var.attach_require_latest_tls_policy || var.attach_elb_log_delivery_policy || var.attach_lb_log_delivery_policy || var.attach_deny_insecure_transport_policy || var.attach_inventory_destination_policy || var.attach_deny_incorrect_encryption_headers || var.attach_deny_incorrect_kms_key_sse || var.attach_deny_unencrypted_object_uploads || var.attach_policy

   # Variables with type `any` should be jsonencode()'d when value is coming from Terragrunt
@@ -39,7 +43,7 @@ resource "aws_s3_bucket_logging" "this" {
 }

 resource "aws_s3_bucket_acl" "this" {
-  count = local.create_bucket && ((var.acl != null && var.acl != "null") || length(local.grants) > 0) ? 1 : 0
+  count = local.create_bucket && local.create_bucket_acl ? 1 : 0

   bucket                = aws_s3_bucket.this[0].id
   expected_bucket_owner = var.expected_bucket_owner
@@ -67,7 +71,7 @@ resource "aws_s3_bucket_acl" "this" {
       }

       owner {
-        id           = try(var.owner["id"], data.aws_canonical_user_id.this.id)
+        id           = try(var.owner["id"], data.aws_canonical_user_id.this[0].id)
         display_name = try(var.owner["display_name"], null)
       }
     }
---

---

Choice D:
main.tf
@@ -1,13 +1,17 @@
 data "aws_region" "current" {}

-data "aws_canonical_user_id" "this" {}
+data "aws_canonical_user_id" "this" {
+  count = local.create_bucket_acl && local.create_bucket_acl && try(var.owner["id"], null) == null ? 1 : 0
+}

 data "aws_caller_identity" "current" {}

 data "aws_partition" "current" {}
 locals {
   create_bucket = var.create_bucket && var.putin_khuylo

+  create_bucket_acl = (var.acl != null && var.acl != "null") || length(local.grants) > 0
+
   attach_policy = var.attach_require_latest_tls_policy || var.attach_elb_log_delivery_policy || var.attach_lb_log_delivery_policy || var.attach_deny_insecure_transport_policy || var.attach_inventory_destination_policy || var.attach_deny_incorrect_encryption_headers || var.attach_deny_incorrect_kms_key_sse || var.attach_deny_unencrypted_object_uploads || var.attach_policy

   # Variables with type `any` should be jsonencode()'d when value is coming from Terragrunt
@@ -39,7 +43,7 @@ resource "aws_s3_bucket_logging" "this" {
 }

 resource "aws_s3_bucket_acl" "this" {
-  count = local.create_bucket && ((var.acl != null && var.acl != "null") || length(local.grants) > 0) ? 1 : 0
+  count = local.create_bucket && local.create_bucket_acl ? 1 : 0

   bucket                = aws_s3_bucket.this[0].id
   expected_bucket_owner = var.expected_bucket_owner
@@ -67,7 +71,7 @@ resource "aws_s3_bucket_acl" "this" {
       }

       owner {
-        id           = try(var.owner["id"], data.aws_canonical_user_id.this.id)
+        id           = try(var.owner["id"], data.aws_canonical_user_id.this[0].id)
         display_name = try(var.owner["display_name"], null)
       }
     }
---

---


Choose the best Terraform patch (A/B/C/D) that implements the requested S3 security change safely. Only respond with a single uppercase letter.

Task Description:
## Description
Allow setting the id parameter inside the notification block.

## Motivation and Context
When configuring bucket notifications using map type inside another map, like in the example [here](https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/blob/bf80a09f0955e6542a6ae8f3b7fa8fbd612148ea/examples/notification/main.tf#L145), there is no control on the order of the notifications.

This can cause terraform to change the resource and replace the notifications order after importing bucket notification, because the state contains list of sorted notifications and the map order can be different.

```terraform
sns_notifications = {
  ios = {
    topic_arn     = "arn:aws:sns:eu-west-1:123456789012:ios-log-upload"
    events        = ["s3:ObjectCreated:*"]
    filter_prefix = "ios/"
  },
  android = {
    topic_arn     = "arn:aws:sns:eu-west-1:123456789012:android-log-upload"
    events        = ["s3:ObjectCreated:*"]
    filter_prefix = "android/"
  }
}
```

```terraform
 # aws_s3_bucket_notification.this[0] will be updated in-place
  ~ resource "aws_s3_bucket_notification" "this" {
        id          = "example-bucket-id"
        # (2 unchanged attributes hidden)

      ~ topic {
          ~ filter_prefix = "ios/" -> "android/"
          ~ id            = "ios" -> "android"
          ~ topic_arn     = "arn:aws:sns:eu-west-1:123456789012:ios-log-upload" -> "arn:aws:sns:eu-west-1:123456789012:android-log-upload"
            # (1 unchanged attribute hidden)
        }
      ~ topic {
          ~ filter_prefix = "android/" -> "ios/"
          ~ id            = "android" -> "ios"
          ~ topic_arn     = "arn:aws:sns:eu-west-1:123456789012:android-log-upload" -> "arn:aws:sns:eu-west-1:123456789012:ios-log-upload"
            # (1 unchanged attribute hidden)
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.
```

This made me configure the notifications in a list rather then map type, but then I realized that the id parameter is not configurable, and will be the key (index) of the object in the list.

```terraform
sns_notifications = [
    {
      topic_arn     = "arn:aws:sns:eu-west-1:123456789012:ios-log-upload"
      events        = ["s3:ObjectCreated:*"]
      filter_prefix = "ios/"
      id            = "ios"
    },
    {
      topic_arn     = "arn:aws:sns:eu-west-1:123456789012:android-log-upload"
      events        = ["s3:ObjectCreated:*"]
      filter_prefix = "android/"
      id            = "android"
    }
  ]
```
```terraform
Terraform will perform the following actions:

  # aws_s3_bucket_notification.this[0] will be updated in-place
  ~ resource "aws_s3_bucket_notification" "this" {
        id          = "example-bucket-id"
        # (2 unchanged attributes hidden)

      ~ topic {
          ~ id            = "ios" -> "0"
            # (3 unchanged attributes hidden)
        }
      ~ topic {
          ~ id            = "android" -> "1"
            # (3 unchanged attributes hidden)
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.
```

The PR will make it possible to configure the id inside each notification block and will allow use of list type over map when you need to control the order of the notifications.

## Breaking Changes
No breaking changes.

## How Has This Been Tested?
- [ ] I have updated at least one of the `examples/*` to demonstrate and validate my change(s)
- [x] I have tested and validated these changes using one or more of the provided `examples/*` projects
- [ ] I have executed `pre-commit run -a` on my pull request

---

Choice A:
modules/notification/main.tf
@@ -19,7 +19,7 @@ resource "aws_s3_bucket_notification" "this" {
     for_each = var.lambda_notifications

     content {
-      id                  = lambda_function.key
+      id                  = try(lambda_function.value.id, lambda_function.key)
       lambda_function_arn = lambda_function.value.function_arn
       events              = lambda_function.value.events
       filter_prefix       = try(lambda_function.value.filter_prefix, null)
@@ -31,7 +31,7 @@ resource "aws_s3_bucket_notification" "this" {
     for_each = var.sqs_notifications

     content {
-      id            = queue.key
+      id            = try(queue.value.id, queue.key)
       queue_arn     = queue.value.queue_arn
       events        = queue.value.events
       filter_prefix = try(queue.value.filter_prefix, null)
@@ -43,7 +43,7 @@ resource "aws_s3_bucket_notification" "this" {
     for_each = var.sns_notifications

     content {
-      id            = topic.key
+      id            = try(topic.value.id, topic.key)
       topic_arn     = topic.value.topic_arn
       events        = topic.value.events
       filter_prefix = try(topic.value.filter_prefix, null)
---

---

Choice B:
modules/notification/main.tf
@@ -19,7 +19,7 @@ resource "aws_s3_bucket_notification" "this" {
     for_each = var.lambda_notifications

     content {
-      id                  = lambda_function.key
+      id                  = try(lambda_function.value.id, lambda_function.key)
       lambda_function_arn = lambda_function.value.function_arn
       events              = lambda_function.value.events
       filter_prefix       = try(lambda_function.value.filter_prefix, null)
@@ -31,7 +31,7 @@ resource "aws_s3_bucket_notification" "this" {
     for_each = var.sqs_notifications

     content {
-      id            = queue.key
+      id            = try(queue.value.id, queue.key)
       queue_arn     = queue.value.queue_arn
       events        = queue.value.events
       filter_prefix = try(queue.value.filter_prefix, null)
@@ -43,7 +43,7 @@ resource "aws_s3_bucket_notification" "this" {
     for_each = var.sns_notifications

     content {
-      id            = topic.key
+      id            = try(topic.value.id, topic.key)
       topic_arn     = topic.value.topic_arn
       events        = topic.value.events
       filter_prefix = try(topic.value.filter_prefix, null)
---

---

Choice C:
modules/notification/main.tf
@@ -19,7 +19,7 @@ resource "aws_s3_bucket_notification" "this" {
     for_each = var.lambda_notifications

     content {
-      id                  = lambda_function.key
+      id                  = try(lambda_function.value.id, lambda_function.key)
       lambda_function_arn = lambda_function.value.function_arn
       events              = lambda_function.value.events
       filter_prefix       = try(lambda_function.value.filter_prefix, null)
@@ -31,7 +31,7 @@ resource "aws_s3_bucket_notification" "this" {
     for_each = var.sqs_notifications

     content {
-      id            = queue.key
+      id            = try(queue.value.id, queue.key)
       queue_arn     = queue.value.queue_arn
       events        = queue.value.events
       filter_prefix = try(queue.value.filter_prefix, null)
@@ -43,7 +43,7 @@ resource "aws_s3_bucket_notification" "this" {
     for_each = var.sns_notifications

     content {
-      id            = topic.key
+      id            = try(topic.value.id, topic.key)
       topic_arn     = topic.value.topic_arn
       events        = topic.value.events
       filter_prefix = try(topic.value.filter_prefix, null)
---

---

Choice D:
modules/notification/main.tf
@@ -19,7 +19,7 @@ resource "aws_s3_bucket_notification" "this" {
     for_each = var.lambda_notifications

     content {
-      id                  = lambda_function.key
+      id                  = try(lambda_function.value.id, lambda_function.key)
       lambda_function_arn = lambda_function.value.function_arn
       events              = lambda_function.value.events
       filter_prefix       = try(lambda_function.value.filter_prefix, null)
@@ -31,7 +31,7 @@ resource "aws_s3_bucket_notification" "this" {
     for_each = var.sqs_notifications

     content {
-      id            = queue.key
+      id            = try(queue.value.id, queue.key)
       queue_arn     = queue.value.queue_arn
       events        = queue.value.events
       filter_prefix = try(queue.value.filter_prefix, null)
@@ -43,7 +43,7 @@ resource "aws_s3_bucket_notification" "this" {
     for_each = var.sns_notifications

     content {
-      id            = topic.key
+      id            = try(topic.value.id, topic.key)
       topic_arn     = topic.value.topic_arn
       events        = topic.value.events
  queue.value.queue_arn
     filter_prefix = try(topic.value.filter_prefix, null)
---

---


Choose the best Terraform patch (A/B/C/D) that implements the requested S3 security change safely. Only respond with a single uppercase letter.

Task Description:
## Description
This PR creates two new outputs: 1) a list of lifecycle rules applied to the s3 bucket and, 2) the policy applied to the s3 bucket. Each output is set to an empty string if its respective value is not provided.

Additionally, this PR removes the deprecated `skip_get_ec2_platforms` argument from the aws providers in all examples directories.

## Motivation and Context
While creating tests for my own S3 modules, I ran into a trouble when trying to validate lifecycle rules and policies applied to my S3 bucket. I was able to output the `data_iam_policy_document` easily enough but lifecycle rules are not available as a data source. My workaround was configuring the proper result in Go itself but it would be much better to output these values in case anyone wants to use them; for tests in my case.

Additionally, while running the pre-commit for these outputs, the validations were failing because the `skip_get_ec2_platforms` argument is not longer supported using Terraform version 1.4.5, the version used to perform all tests. To pass all validation checks, the `skip_get_ec2_platforms` argument was removed from the following examples directories:

- [examples/notification](./examples/notification)
- [examples/object](./examples/object)
- [examples/s3-inventory](./examples/s3-inventory)
- [examples/s3-replication](./examples/s3-replication)

## Breaking Changes
No.

## How Has This Been Tested?
- [x] I have updated at least one of the `examples/*` to demonstrate and validate my change(s)
- [x] I have tested and validated these changes using one or more of the provided `examples/*` projects
- [x] I have executed `pre-commit run -a` on my pull request

---

Choice A:
README.md
@@ -236,6 +236,8 @@ No modules.
 |  [s3\_bucket\_bucket\_regional\_domain\_name](#output\_s3\_bucket\_bucket\_regional\_domain\_name) | The bucket region-specific domain name. The bucket domain name including the region name, please refer here of format. Note: The AWS CloudFront allows specifying S3 region-specific endpoint when creating S3 origin, it will prevent redirect issues from CloudFront to S3 Origin URL. |
 |  [s3\_bucket\_hosted\_zone\_id](#output\_s3\_bucket\_hosted\_zone\_id) | The Route 53 Hosted Zone ID for this bucket's region. |
 |  [s3\_bucket\_id](#output\_s3\_bucket\_id) | The name of the bucket. |
+|  [s3\_bucket\_lifecycle\_configuration\_rules](#output\_s3\_bucket\_lifecycle\_configuration\_rules) | The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string. |
+|  [s3\_bucket\_policy](#output\_s3\_bucket\_policy) | The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string. |
 |  [s3\_bucket\_region](#output\_s3\_bucket\_region) | The AWS region this bucket resides in. |
 |  [s3\_bucket\_website\_domain](#output\_s3\_bucket\_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. |
 |  [s3\_bucket\_website\_endpoint](#output\_s3\_bucket\_website\_endpoint) | The website endpoint, if the bucket is configured with a website. If not, this will be an empty string. |
---
examples/complete/README.md
@@ -73,6 +73,8 @@ No inputs.
 |  [s3\_bucket\_bucket\_regional\_domain\_name](#output\_s3\_bucket\_bucket\_regional\_domain\_name) | The bucket region-specific domain name. The bucket domain name including the region name, please refer here for format. Note: The AWS CloudFront allows specifying S3 region-specific endpoint when creating S3 origin, it will prevent redirect issues from CloudFront to S3 Origin URL. |
 |  [s3\_bucket\_hosted\_zone\_id](#output\_s3\_bucket\_hosted\_zone\_id) | The Route 53 Hosted Zone ID for this bucket's region. |
 |  [s3\_bucket\_id](#output\_s3\_bucket\_id) | The name of the bucket. |
+|  [s3\_bucket\_lifecycle\_configuration\_rules](#output\_s3\_bucket\_lifecycle\_configuration\_rules) | The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string. |
+|  [s3\_bucket\_policy](#output\_s3\_bucket\_policy) | The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string. |
 |  [s3\_bucket\_region](#output\_s3\_bucket\_region) | The AWS region this bucket resides in. |
 |  [s3\_bucket\_website\_domain](#output\_s3\_bucket\_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. |
 |  [s3\_bucket\_website\_endpoint](#output\_s3\_bucket\_website\_endpoint) | The website endpoint, if the bucket is configured with a website. If not, this will be an empty string. |
---
examples/complete/outputs.tf
@@ -23,6 +23,16 @@ output "s3_bucket_hosted_zone_id" {
   value       = module.s3_bucket.s3_bucket_hosted_zone_id
 }

+output "s3_bucket_lifecycle_configuration_rules" {
+  description = "The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string."
+  value       = module.s3_bucket.s3_bucket_lifecycle_configuration_rules
+}
+
+output "s3_bucket_policy" {
+  description = "The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string."
+  value       = module.s3_bucket.s3_bucket_policy
+}
+
 output "s3_bucket_region" {
   description = "The AWS region this bucket resides in."
   value       = module.s3_bucket.s3_bucket_region
---
examples/notification/main.tf
@@ -2,7 +2,6 @@ provider "aws" {
   region = local.region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
examples/object/main.tf
@@ -2,7 +2,6 @@ provider "aws" {
   region = local.region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
examples/s3-inventory/main.tf
@@ -7,7 +7,6 @@ provider "aws" {
   region = local.region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
examples/s3-replication/main.tf
@@ -2,7 +2,6 @@ provider "aws" {
   region = local.origin_region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
@@ -15,7 +14,6 @@ provider "aws" {
   alias = "replica"

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
outputs.tf
@@ -23,6 +23,16 @@ output "s3_bucket_hosted_zone_id" {
   value       = try(aws_s3_bucket.this[0].hosted_zone_id, "")
 }

+output "s3_bucket_lifecycle_configuration_rules" {
+  description = "The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string."
+  value       = try(aws_s3_bucket_lifecycle_configuration.this[0].rule, "")
+}
+
+output "s3_bucket_policy" {
+  description = "The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string."
+  value       = try(aws_s3_bucket_policy.this[0].policy, "")
+}
+
 output "s3_bucket_region" {
   description = "The AWS region this bucket resides in."
   value       = try(aws_s3_bucket.this[0].region, "")
---

---

Choice B:
README.md
@@ -236,6 +236,8 @@ No modules.
 |  [s3\_bucket\_bucket\_regional\_domain\_name](#output\_s3\_bucket\_bucket\_regional\_domain\_name) | The bucket region-specific domain name. The bucket domain name including the region name, please refer here for format. Note: The AWS CloudFront allows specifying S3 region-specific endpoint when creating S3 origin, it will prevent redirect issues from CloudFront to S3 Origin URL. |
 |  [s3\_bucket\_hosted\_zone\_id](#output\_s3\_bucket\_hosted\_zone\_id) | The Route 53 Hosted Zone ID for this bucket's region. |
 |  [s3\_bucket\_id](#output\_s3\_bucket\_id) | The name of the bucket. |
+|  [s3\_bucket\_lifecycle\_configuration\_rules](#output\_s3\_bucket\_lifecycle\_configuration\_rules) | The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string. |
+|  [s3\_bucket\_policy](#output\_s3\_bucket\_policy) | The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string. |
 |  [s3\_bucket\_region](#output\_s3\_bucket\_region) | with AWS region this bucket resides in. |
 |  [s3\_bucket\_website\_domain](#output\_s3\_bucket\_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. |
 |  [s3\_bucket\_website\_endpoint](#output\_s3\_bucket\_website\_endpoint) | The website endpoint, if the bucket is configured with a website. If not, this will be an empty string. |
---
examples/complete/README.md
@@ -73,6 +73,8 @@ No inputs.
 |  [s3\_bucket\_bucket\_regional\_domain\_name](#output\_s3\_bucket\_bucket\_regional\_domain\_name) | The bucket region-specific domain name. The bucket domain name including the region name, please refer here for format. Note: The AWS CloudFront allows specifying S3 region-specific endpoint when creating S3 origin, it will prevent redirect issues from CloudFront to S3 Origin URL. |
 |  [s3\_bucket\_hosted\_zone\_id](#output\_s3\_bucket\_hosted\_zone\_id) | The Route 53 Hosted Zone ID for this bucket's region. |
 |  [s3\_bucket\_id](#output\_s3\_bucket\_id) | The name of the bucket. |
+|  [s3\_bucket\_lifecycle\_configuration\_rules](#output\_s3\_bucket\_lifecycle\_configuration\_rules) | The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string. |
+|  [s3\_bucket\_policy](#output\_s3\_bucket\_policy) | The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string. |
 |  [s3\_bucket\_region](#output\_s3\_bucket\_region) | The AWS region this bucket resides in. |
 |  [s3\_bucket\_website\_domain](#output\_s3\_bucket\_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. |
 |  [s3\_bucket\_website\_endpoint](#output\_s3\_bucket\_website\_endpoint) | The website endpoint, if the bucket is configured with a website. If not, this will be an empty string. |
---
examples/complete/outputs.tf
@@ -23,6 +23,16 @@ output "s3_bucket_hosted_zone_id" {
   value       = module.s3_bucket.s3_bucket_hosted_zone_id
 }

+output "s3_bucket_lifecycle_configuration_rules" {
+  description = "The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string."
+  value       = module.s3_bucket.s3_bucket_lifecycle_configuration_rules
+}
+
+output "s3_bucket_policy" {
+  description = "The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string."
+  value       = module.s3_bucket.s3_bucket_policy
+}
+
 output "s3_bucket_region" {
   description = "The AWS region this bucket resides in."
   value       = module.s3_bucket.s3_bucket_region
---
examples/notification/main.tf
@@ -2,7 +2,6 @@ provider "aws" {
   region = local.region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
examples/object/main.tf
@@ -2,7 +2,6 @@ provider "aws" {
   region = local.region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
examples/s3-inventory/main.tf
@@ -7,7 +7,6 @@ provider "aws" {
   region = local.region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
examples/s3-replication/main.tf
@@ -2,7 +2,6 @@ provider "aws" {
   region = local.origin_region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
@@ -15,7 +14,6 @@ provider "aws" {
   alias = "replica"

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
outputs.tf
@@ -23,6 +23,16 @@ output "s3_bucket_hosted_zone_id" {
   value       = try(aws_s3_bucket.this[0].hosted_zone_id, "")
 }

+output "s3_bucket_lifecycle_configuration_rules" {
+  description = "The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string."
+  value       = try(aws_s3_bucket_lifecycle_configuration.this[0].rule, "")
+}
+
+output "s3_bucket_policy" {
+  description = "The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string."
+  value       = try(aws_s3_bucket_policy.this[0].policy, "")
+}
+
 output "s3_bucket_region" {
   description = "The AWS region this bucket resides in."
   value       = try(aws_s3_bucket.this[0].region, "")
---

---

Choice C:
README.md
@@ -236,6 +236,8 @@ No modules.
 |  [s3\_bucket\_bucket\_regional\_domain\_name](#output\_s3\_bucket\_bucket\_regional\_domain\_name) | The bucket region-specific domain name. The bucket domain name including the region name, please refer here for format. Note: The AWS CloudFront allows specifying S3 region-specific endpoint when creating S3 origin, it will prevent redirect issues from CloudFront to S3 Origin URL. |
 |  [s3\_bucket\_hosted\_zone\_id](#output\_s3\_bucket\_hosted\_zone\_id) | The Route 53 Hosted Zone ID for this bucket's region. |
 |  [s3\_bucket\_id](#output\_s3\_bucket\_id) | The name of the bucket. |
+|  [s3\_bucket\_lifecycle\_configuration\_rules](#output\_s3\_bucket\_lifecycle\_configuration\_rules) | The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string. |
+|  [s3\_bucket\_policy](#output\_s3\_bucket\_policy) | The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string. |
 |  [s3\_bucket\_region](#output\_s3\_bucket\_region) | The AWS region this bucket resides in. |
 |  [s3\_bucket\_website\_domain](#output\_s3\_bucket\_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. |
 |  [s3\_bucket\_website\_endpoint](#output\_s3\_bucket\_website\_endpoint) | The website endpoint, if the bucket is configured with a website. If not, this will be an empty string. |
---
examples/complete/README.md
@@ -73,6 +73,8 @@ No inputs.
 |  [s3\_bucket\_bucket\_regional\_domain\_name](#output\_s3\_bucket\_bucket\_regional\_domain\_name) | The bucket region-specific domain name. The bucket domain name including the region name, please refer here for format. Note: The AWS CloudFront allows specifying S3 region-specific endpoint when creating S3 origin, it will prevent redirect issues from CloudFront to S3 Origin URL. |
 |  [s3\_bucket\_hosted\_zone\_id](#output\_s3\_bucket\_hosted\_zone\_id) | The Route 53 Hosted Zone ID for this bucket's region. |
 |  [s3\_bucket\_id](#output\_s3\_bucket\_id) | The name of the bucket. |
+|  [s3\_bucket\_lifecycle\_configuration\_rules](#output\_s3\_bucket\_lifecycle\_configuration\_rules) | The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string. |
+|  [s3\_bucket\_policy](#output\_s3\_bucket\_policy) | The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string. |
 |  [s3\_bucket\_region](#output\_s3\_bucket\_region) | The AWS region this bucket resides in. |
 |  [s3\_bucket\_website\_domain](#output\_s3\_bucket\_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. |
 |  [s3\_bucket\_website\_endpoint](#output\_s3\_bucket\_website\_endpoint) | The website endpoint, if the bucket is configured with a website. If not, this will be an empty string. |
---
examples/complete/outputs.tf
@@ -23,6 +23,16 @@ output "s3_bucket_hosted_zone_id" {
   value       = module.s3_bucket.s3_bucket_hosted_zone_id
 }

+output "s3_bucket_lifecycle_configuration_rules" {
+  description = "The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string."
+  value       = module.s3_bucket.s3_bucket_lifecycle_configuration_rules
+}
+
+output "s3_bucket_policy" {
+  description = "The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string."
+  value       = module.s3_bucket.s3_bucket_policy
+}
+
 output "s3_bucket_region" {
   description = "The AWS region this bucket resides in."
   value       = module.s3_bucket.s3_bucket_region
---
examples/notification/main.tf
@@ -2,7 +2,6 @@ provider "aws" {
   region = local.region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
examples/object/main.tf
@@ -2,7 +2,6 @@ provider "aws" {
   region = local.region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
examples/s3-inventory/main.tf
@@ -7,7 +7,6 @@ provider "aws" {
   region = local.region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
examples/s3-replication/main.tf
@@ -2,7 +2,6 @@ provider "aws" {
   region = local.origin_region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
@@ -15,7 +14,6 @@ provider "aws" {
   alias = "replica"

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
outputs.tf
@@ -23,6 +23,16 @@ output "s3_bucket_hosted_zone_id" {
   value       = try(aws_s3_bucket.this[0].hosted_zone_id, "")
 }

+output "s3_bucket_lifecycle_configuration_rules" {
+  description = "The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string."
+  value       = try(aws_s3_bucket_lifecycle_configuration.this[0].rule, "")
+}
+
+output "s3_bucket_policy" {
+  description = "The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string."
+  value       = try(aws_s3_bucket_policy.this[0].policy, "")
+}
+
 output "s3_bucket_region" {
   description = "The AWS region this bucket resides in."
   value       = try(aws_s3_bucket.this[0].region, "")
---

---

Choice D:
README.md
@@ -236,6 +236,8 @@ No modules.
 |  [s3\_bucket\_bucket\_regional\_domain\_name](#output\_s3\_bucket\_bucket\_regional\_domain\_name) | The bucket region-specific domain name. The bucket domain name including the region name, please refer here for format. Note: The AWS CloudFront allows specifying S3 region-specific endpoint when creating S3 origin, it will prevent redirect issues from CloudFront to S3 Origin URL. |
 |  [s3\_bucket\_hosted\_zone\_id](#output\_s3\_bucket\_hosted\_zone\_id) | The Route 53 Hosted Zone ID for this bucket's region. |
 |  [s3\_bucket\_id](#output\_s3\_bucket\_id) | The name of the bucket. |
+|  [s3\_bucket\_lifecycle\_configuration\_rules](#output\_s3\_bucket\_lifecycle\_configuration\_rules) | The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string. |
+|  [s3\_bucket\_policy](#output\_s3\_bucket\_policy) | The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string. |
 |  [s3\_bucket\_region](#output\_s3\_bucket\_region) "s3_bucket_policy" The AWS region this bucket resides in. |
 |  [s3\_bucket\_website\_domain](#output\_s3\_bucket\_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. |
 |  [s3\_bucket\_website\_endpoint](#output\_s3\_bucket\_website\_endpoint) | The website endpoint, if the bucket is configured with a website. If not, this will be an empty string. |
---
examples/complete/README.md
@@ -73,6 +73,8 @@ No inputs.
 |  [s3\_bucket\_bucket\_regional\_domain\_name](#output\_s3\_bucket\_bucket\_regional\_domain\_name) | The bucket region-specific domain name. The bucket domain name including the region name, please refer here for format. Note: The AWS CloudFront allows specifying S3 region-specific endpoint when creating S3 origin, it will prevent redirect issues from CloudFront to S3 Origin URL. |
 |  [s3\_bucket\_hosted\_zone\_id](#output\_s3\_bucket\_hosted\_zone\_id) | The Route 53 Hosted Zone ID for this bucket's region. |
 |  [s3\_bucket\_id](#output\_s3\_bucket\_id) | The name of the bucket. |
+|  [s3\_bucket\_lifecycle\_configuration\_rules](#output\_s3\_bucket\_lifecycle\_configuration\_rules) | The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string. |
+|  [s3\_bucket\_policy](#output\_s3\_bucket\_policy) | The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string. |
 |  [s3\_bucket\_region](#output\_s3\_bucket\_region) | The AWS region this bucket resides in. |
 |  [s3\_bucket\_website\_domain](#output\_s3\_bucket\_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. |
 |  [s3\_bucket\_website\_endpoint](#output\_s3\_bucket\_website\_endpoint) | The website endpoint, if the bucket is configured with a website. If not, this will be an empty string. |
---
examples/complete/outputs.tf
@@ -23,6 +23,16 @@ output "s3_bucket_hosted_zone_id" {
   value       = module.s3_bucket.s3_bucket_hosted_zone_id
 }

+output "s3_bucket_lifecycle_configuration_rules" {
+  description = "The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string."
+  value       = module.s3_bucket.s3_bucket_lifecycle_configuration_rules
+}
+
+output "s3_bucket_policy" {
+  description = "The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string."
+  value       = module.s3_bucket.s3_bucket_policy
+}
+
 output "s3_bucket_region" {
   description = "The AWS region this bucket resides in."
   value       = module.s3_bucket.s3_bucket_region
---
examples/notification/main.tf
@@ -2,7 +2,6 @@ provider "aws" {
   region = local.region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
examples/object/main.tf
@@ -2,7 +2,6 @@ provider "aws" {
   region = local.region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
examples/s3-inventory/main.tf
@@ -7,7 +7,6 @@ provider "aws" {
   region = local.region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
examples/s3-replication/main.tf
@@ -2,7 +2,6 @@ provider "aws" {
   region = local.origin_region

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
@@ -15,7 +14,6 @@ provider "aws" {
   alias = "replica"

   # Make it faster by skipping something
-  skip_get_ec2_platforms      = true
   skip_metadata_api_check     = true
   skip_region_validation      = true
   skip_credentials_validation = true
---
outputs.tf
@@ -23,6 +23,16 @@ output "s3_bucket_hosted_zone_id" {
   value       = try(aws_s3_bucket.this[0].hosted_zone_id, "")
 }

+output "s3_bucket_lifecycle_configuration_rules" {
+  description = "The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string."
+  value       = try(aws_s3_bucket_lifecycle_configuration.this[0].rule, "")
+}
+
+output "s3_bucket_policy" {
+  description = "The policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string."
+  value       = try(aws_s3_bucket_policy.this[0].policy, "")
+}
+
 output "s3_bucket_region" {
   description = "The AWS region this bucket resides in."
   value       = try(aws_s3_bucket.this[0].region, "")
---

---


Choose the best Terraform patch (A/B/C/D) that implements the requested S3 security change safely. Only respond with a single uppercase letter.

Task Description:
## Description
Added extra guard option to create lifecycle rule for expiration whole bucket

## Motivation and Context
In our case, we created a bucket without any filter prefix, which causes expiration of about 1,5TB of data in bucket.
We had code like snippet bellow
```hcl
module "s3_bucket" {
  source = "terraform-aws-modules/s3-bucket/aws"

  lifecycle_rule = [
    {
      enabled = true
       prefix = "prefix-to-cleanup/"

      expiration = {
        days = 1
      }
    }
  ]
}
```
There is a missing `filter` section wrapping `prefix`. Sadly terraform does not throw any error that config is inaccurate. That code created lifecycle rules for the whole bucket.

We wanted to be sure not to make the same mistake again and create some kind of guard before this situation. Without passing extra option, no expiration section will be created - that should be less pain than losing data ;)

Passing one extra option should not be a big deal - AWS Console have a similar checkbox to prevent creating rule for the whole bucket.

## Breaking Changes
Conditionaly/Partialy - if someone wanted to create lifecycle to cleanup whole bucket it is needed to pass extra option.

## How Has This Been Tested?
- [ ] I have updated at least one of the `examples/*` to demonstrate and validate my change(s)
- [x] I have tested and validated these changes using one or more of the provided `examples/*` projects
<!--- Users should start with an existing example as its written, deploy it, then check their changes against it -->
<!--- This will highlight breaking/disruptive changes. Once you have checked, deploy your changes to verify -->
<!--- Please describe how you tested your changes -->
- [x] I have executed `pre-commit run -a` on my pull request
<!--- Please see https://github.com/antonbabenko/pre-commit-terraform#how-to-install for how to install -->

---

Choice A:
README.md
@@ -90,6 +90,67 @@ module "s3_bucket" {
 }
 ```

+## Expiration lifecycle rules for the whole bucket
+
+To prevent accidentally creating a lifecycle rule for the whole bucket that could remove all of your files, you must pass the `expire_all_objects_in_bucket = true` option.
+
+```hcl
+# This S3 bucket has an expiration lifecycle rule only for the specified prefix
+module "s3_bucket" {
+  source = "terraform-aws-modules/s3-bucket/aws"
+
+  lifecycle_rule = [
+    {
+      enabled = true
+
+      filter = {
+        prefix = "prefix-to-cleanup/"
+      }
+
+      expiration =         days = 1
+      }
+    }
+  ]
+}
+```
+
+```hcl
+# This S3 bucket has an expiration lifecycle for the whole bucket
+module "s3_bucket" {
+  source = "terraform-aws-modules/s3-bucket/aws"
+
+  lifecycle_rule = [
+    {
+      enabled = true
+
+      expire_all_objects_in_bucket = true
+      expiration = {
+        days = 1
+      }
+    }
+  ]
+}
+```
+
+```hcl
+# This S3 bucket does NOT have ANY expiration lifecycle rule
+module "s3_bucket" {
+  source = "terraform-aws-modules/s3-bucket/aws"
+
+  lifecycle_rule = [
+    {
+      enabled = true
+
+      # no option or expire_all_objects_in_bucket = false
+      expiration = {
+        days = 1
+      }
+    }
+  ]
+}
+```
+
 ## Terragrunt and `variable "..." { type = any }`

 There is a bug [#1211](https://github.com/gruntwork-io/terragrunt/issues/1211) in Terragrunt related to the way how the variables of type `any` are passed to Terraform.
---
main.tf
@@ -237,7 +237,7 @@ resource "aws_s3_bucket_lifecycle_configuration" "this" {

       # Max 1 block - expiration
       dynamic "expiration" {
-        for_each = try(flatten([rule.value.expiration]), [])
+        for_each = try(rule.value.expire_all_objects_in_bucket, false) == true || try(rule.value.filter.prefix, rule.value.filter.object_size_less_than, rule.value.filter.object_size_greater_than, rule.value.filter.tags, null) != null ? try(flatten([rule.value.expiration]), []) : []

         content {
           date                         = try(expiration.value.date, null)
---

---

Choice B:
README.md
@@ -90,6 +90,67 @@ module "s3_bucket" {
 }
 ```

+## Expiration lifecycle rules for the whole bucket
+
+To prevent accidentally creating a lifecycle rule for the whole bucket that could remove all of your files, you must pass the `expire_all_objects_in_bucket = true` option.
+
+```hcl
+# This S3 bucket has an expiration lifecycle rule only for the specified prefix
+module "s3_bucket" {
+  source = "terraform-aws-modules/s3-bucket/aws"
+
+  lifecycle_rule = [
+    {
+      enabled = true
+
+      filter = {
+        prefix = "prefix-to-cleanup/"
+      }
+
+      expiration = {
+        days = 1
+      }
+    }
+  ]
+}
+```
+
+```hcl
+# This S3 bucket has an expiration lifecycle for the whole bucket
+module "s3_bucket" {
+  source = "terraform-aws-modules/s3-bucket/aws"
+
+  lifecycle_rule = [
+    {
+      enabled = true
+
+      expire_all_objects_in_bucket = true
+      expiration = {
+        days = 1
+      }
+    }
+  ]
+}
+```
+
+```hcl
+# This S3 bucket does NOT have ANY expiration lifecycle rule
+module "s3_bucket" {
+  source = "terraform-aws-modules/s3-bucket/aws"
+
+  lifecycle_rule = [
+    {
+      enabled = true
+
+      # no option or expire_all_objects_in_bucket = false
+      expiration = {
+        days = 1
+      }
+    }
+  ]
+}
+```
+
 ## Terragrunt and `variable "..." { type = any }`

 There is a bug [#1211](https://github.com/gruntwork-io/terragrunt/issues/1211) in Terragrunt related to the way how the variables of type `any` are passed to Terraform.
---
main.tf
@@ -237,7 +237,7 @@ resource "aws_s3_bucket_lifecycle_configuration" "this" {

       # Max 1 block - expiration
       dynamic "expiration" {
-        for_each = try(flatten([rule.value.expiration]), [])
+        for_each = try(rule.value.expire_all_objects_in_bucket, false) == true || try(rule.value.filter.prefix, rule.value.filter.object_size_less_than, rule.value.filter.object_size_greater_than, rule.value.filter.tags, null) != null ? try(flatten([rule.value.expiration]), []) : []

         content {
           date                         = try(expiration.value.date, null)
---

---

Choice C:
README.md
@@ -90,6 +90,67 @@ module "s3_bucket" {
 }
 ```

+## Expiration lifecycle rules for the whole bucket
+
+To prevent accidentally creating a lifecycle rule for the whole bucket that could remove all of your files, you must pass the `expire_all_objects_in_bucket = true` option.
+
+```hcl
+# This S3 bucket has an expiration lifecycle rule only for the specified prefix
+module "s3_bucket" {
+  source = "terraform-aws-modules/s3-bucket/aws"
+
+  lifecycle_rule = [
+    {
+      enabled = true
+
+      filter = {
+        prefix = "prefix-to-cleanup/"
+      }
+
+      expiration = {
+        days = 1
+      }
+    }
+  ]
+}
+```
+
+```hcl
+# This S3 bucket has an expiration lifecycle for the whole bucket
+module "s3_bucket" {
+  source = "terraform-aws-modules/s3-bucket/aws"
+
+  lifecycle_rule = [
+    {
+      enabled = true
+
+      expire_all_objects_in_bucket = true
+      expiration = {
+        days = 1
+      }
+    }
+  ]
+}
+```
+
+```hcl
+# This S3 bucket does NOT have ANY expiration lifecycle rule
+module "s3_bucket" {
+  source = "terraform-aws-modules/s3-bucket/aws"
+
+  lifecycle_rule = [
+    {
+      enabled = true
+
+      # no option or expire_all_objects_in_bucket = false
+  @@    expiration = {
+        days = 1
+      }
+    }
+  ]
+}
+```
+
 ## Terragrunt and `variable "..." { type = any }`

 There is a bug [#1211](https://github.com/gruntwork-io/terragrunt/issues/1211) in Terragrunt related to the way how the variables of type `any` are passed to Terraform.
---
main.tf
@@ -237,7 +237,7 @@ resource "aws_s3_bucket_lifecycle_configuration" "this" {

       # Max 1 block - expiration
       dynamic "expiration" {
-        for_each = try(flatten([rule.value.expiration]), [])
+        for_each = try(rule.value.expire_all_objects_in_bucket, false) == true || try(rule.value.filter.prefix, rule.value.filter.object_size_less_than, rule.value.filter.object_size_greater_than, rule.value.filter.tags, null) != null ? try(flatten([rule.value.expiration]), []) : []

         content {
           date                         = try(expiration.value.date, null)
---

---

Choice D:
README.md
@@ -90,6 +90,67 @@ module "s3_bucket" {
 }
 ```

+## Expiration lifecycle rules for the whole bucket
+
+To prevent accidentally creating a lifecycle rule for the whole bucket that could remove all of your files, you must pass the `expire_all_objects_in_bucket = true` option.
+
+```hcl
+# This S3 bucket has an expiration lifecycle rule only for the specified prefix
+module "s3_bucket" {
+  source = "terraform-aws-modules/s3-bucket/aws"
+
+  lifecycle_rule = [
+    {
+      enabled = true
+
+      filter = {
+        prefix = "prefix-to-cleanup/"
+      }
+
+      expiration = {
+        days = 1
+      }
+    }
+  ]
+}
+```
+
+```hcl
+# This S3 bucket = an expiration lifecycle for the whole bucket
+module "s3_bucket" {
+  source = "terraform-aws-modules/s3-bucket/aws"
+
+  lifecycle_rule = [
+    {
+      enabled = true
+
+      expire_all_objects_in_bucket = true
+      expiration = {
+        days = 1
+      }
+    }
+  ]
+}
+```
+
+```hcl
+# This S3 bucket does NOT have ANY expiration lifecycle rule
+module "s3_bucket" {
+  source = "terraform-aws-modules/s3-bucket/aws"
+
+  lifecycle_rule = [
+    {
+      enabled = true
+
+      # no option or expire_all_objects_in_bucket = false
+      expiration = {
+        days = 1
+      }
+    }
+  ]
+}
+```
+
 ## Terragrunt and `variable "..." { type = any }`

 There is a bug [#1211](https://github.com/gruntwork-io/terragrunt/issues/1211) in Terragrunt related to the way how the variables of type `any` are passed to Terraform.
---
main.tf
@@ -237,7 +237,7 @@ resource "aws_s3_bucket_lifecycle_configuration" "this" {

       # Max 1 block - expiration
       dynamic "expiration" {
-        for_each = try(flatten([rule.value.expiration]), [])
+        for_each = try(rule.value.expire_all_objects_in_bucket, false) == true || try(rule.value.filter.prefix, rule.value.filter.object_size_less_than, rule.value.filter.object_size_greater_than, rule.value.filter.tags, null) != null ? try(flatten([rule.value.expiration]), []) : []

         content {
           date                         = try(expiration.value.date, null)
---

---