diff --git a/README.md b/README.md index dafd08c1..8d0ec745 100644 --- a/README.md +++ b/README.md @@ -177,13 +177,13 @@ Available targets: | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 0.13.0 | -| [aws](#requirement\_aws) | >= 2.0 | +| [aws](#requirement\_aws) | >= 2.33 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 2.0 | +| [aws](#provider\_aws) | >= 2.33 | ## Modules @@ -250,6 +250,7 @@ Available targets: | [noncurrent\_version\_deeparchive\_transition\_days](#input\_noncurrent\_version\_deeparchive\_transition\_days) | Number of days to persist in the standard storage tier before moving to the glacier deeparchive access tier | `number` | `60` | no | | [noncurrent\_version\_expiration\_days](#input\_noncurrent\_version\_expiration\_days) | Specifies when noncurrent object versions expire | `number` | `90` | no | | [noncurrent\_version\_glacier\_transition\_days](#input\_noncurrent\_version\_glacier\_transition\_days) | Number of days to persist in the standard storage tier before moving to the glacier infrequent access tier | `number` | `30` | no | +| [object\_lock\_configuration](#input\_object\_lock\_configuration) | A configuration for S3 object locking. With S3 Object Lock, you can store objects using a `write once, read many` (WORM) model. Object Lock can help prevent objects from being deleted or overwritten for a fixed amount of time or indefinitely. |
object({
mode = string # Valid values are GOVERNANCE and COMPLIANCE.
days = number
years = number
})
| `null` | no | | [policy](#input\_policy) | 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 | `string` | `""` | no | | [prefix](#input\_prefix) | Prefix identifying one or more objects to which the rule applies | `string` | `""` | no | | [regex\_replace\_chars](#input\_regex\_replace\_chars) | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | diff --git a/docs/terraform.md b/docs/terraform.md index 9c1ad688..6da65e76 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -4,13 +4,13 @@ | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 0.13.0 | -| [aws](#requirement\_aws) | >= 2.0 | +| [aws](#requirement\_aws) | >= 2.33 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 2.0 | +| [aws](#provider\_aws) | >= 2.33 | ## Modules @@ -77,6 +77,7 @@ | [noncurrent\_version\_deeparchive\_transition\_days](#input\_noncurrent\_version\_deeparchive\_transition\_days) | Number of days to persist in the standard storage tier before moving to the glacier deeparchive access tier | `number` | `60` | no | | [noncurrent\_version\_expiration\_days](#input\_noncurrent\_version\_expiration\_days) | Specifies when noncurrent object versions expire | `number` | `90` | no | | [noncurrent\_version\_glacier\_transition\_days](#input\_noncurrent\_version\_glacier\_transition\_days) | Number of days to persist in the standard storage tier before moving to the glacier infrequent access tier | `number` | `30` | no | +| [object\_lock\_configuration](#input\_object\_lock\_configuration) | A configuration for S3 object locking. With S3 Object Lock, you can store objects using a `write once, read many` (WORM) model. Object Lock can help prevent objects from being deleted or overwritten for a fixed amount of time or indefinitely. |
object({
mode = string # Valid values are GOVERNANCE and COMPLIANCE.
days = number
years = number
})
| `null` | no | | [policy](#input\_policy) | 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 | `string` | `""` | no | | [prefix](#input\_prefix) | Prefix identifying one or more objects to which the rule applies | `string` | `""` | no | | [regex\_replace\_chars](#input\_regex\_replace\_chars) | Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | diff --git a/examples/complete/main.tf b/examples/complete/main.tf index a949d680..59e99856 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -13,6 +13,7 @@ module "s3_bucket" { allow_encrypted_uploads_only = var.allow_encrypted_uploads_only allowed_bucket_actions = var.allowed_bucket_actions bucket_name = var.bucket_name + object_lock_configuration = var.object_lock_configuration context = module.this.context } diff --git a/examples/complete/object-lock.us-west-1.tfvars b/examples/complete/object-lock.us-west-1.tfvars new file mode 100644 index 00000000..791bd2d2 --- /dev/null +++ b/examples/complete/object-lock.us-west-1.tfvars @@ -0,0 +1,30 @@ +region = "us-west-1" + +namespace = "eg" + +stage = "test" + +name = "s3-object-lock-test" + +acl = "private" + +force_destroy = false + +versioning_enabled = true + +allowed_bucket_actions = [ + "s3:PutObject", + "s3:PutObjectAcl", + "s3:GetObject", + "s3:DeleteObject", + "s3:ListBucket", + "s3:ListBucketMultipartUploads", + "s3:GetBucketLocation", + "s3:AbortMultipartUpload" +] + +object_lock_configuration = { + mode = "GOVERNANCE" + days = 366 + years = null +} \ No newline at end of file diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf index 7f4de972..4748cf74 100644 --- a/examples/complete/variables.tf +++ b/examples/complete/variables.tf @@ -178,3 +178,13 @@ variable "bucket_name" { default = null description = "Bucket name. If provided, the bucket will be created with this name instead of generating the name from the context" } + +variable "object_lock_configuration" { + type = object({ + mode = string # Valid values are GOVERNANCE and COMPLIANCE. + days = number + years = number + }) + default = null + description = "A configuration for S3 object locking. With S3 Object Lock, you can store objects using a `write once, read many` (WORM) model. Object Lock can help prevent objects from being deleted or overwritten for a fixed amount of time or indefinitely." +} \ No newline at end of file diff --git a/main.tf b/main.tf index 4a2f99fb..130a4a74 100644 --- a/main.tf +++ b/main.tf @@ -177,6 +177,20 @@ resource "aws_s3_bucket" "default" { } } } + + dynamic "object_lock_configuration" { + for_each = var.object_lock_configuration != null ? [1] : [] + content { + object_lock_enabled = "Enabled" + rule { + default_retention { + mode = var.object_lock_configuration.mode + days = var.object_lock_configuration.days + years = var.object_lock_configuration.years + } + } + } + } } module "s3_user" { diff --git a/test/src/examples_complete_test.go b/test/src/examples_complete_test.go index f280c545..da3c9ede 100644 --- a/test/src/examples_complete_test.go +++ b/test/src/examples_complete_test.go @@ -96,3 +96,46 @@ func TestExamplesCompleteWithGrants(t *testing.T) { // Verify we're getting back the outputs we expect assert.Equal(t, expectedS3BucketId, s3BucketId) } + +// Test the Terraform module in examples/complete using Terratest for grants. +func TestExamplesCompleteWithObjectLock(t *testing.T) { + rand.Seed(time.Now().UnixNano()) + + attributes := []string{strconv.Itoa(rand.Intn(100000))} + rootFolder := "../../" + terraformFolderRelativeToRoot := "examples/complete" + varFiles := []string{"object-lock.us-west-1.tfvars"} + + tempTestFolder := test_structure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot) + + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: tempTestFolder, + Upgrade: true, + // Variables to pass to our Terraform code using -var-file options + VarFiles: varFiles, + Vars: map[string]interface{}{ + "attributes": attributes, + }, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + // Run `terraform output` to get the value of an output variable + userName := terraform.Output(t, terraformOptions, "user_name") + + expectedUserName := "eg-test-s3-object-lock-test-" + attributes[0] + // Verify we're getting back the outputs we expect + assert.Equal(t, expectedUserName, userName) + + // Run `terraform output` to get the value of an output variable + s3BucketId := terraform.Output(t, terraformOptions, "bucket_id") + + expectedS3BucketId := "eg-test-s3-object-lock-test-" + attributes[0] + // Verify we're getting back the outputs we expect + assert.Equal(t, expectedS3BucketId, s3BucketId) +} diff --git a/variables.tf b/variables.tf index f3589b0b..9ff8ed53 100644 --- a/variables.tf +++ b/variables.tf @@ -252,3 +252,13 @@ variable "bucket_name" { default = null description = "Bucket name. If provided, the bucket will be created with this name instead of generating the name from the context" } + +variable "object_lock_configuration" { + type = object({ + mode = string # Valid values are GOVERNANCE and COMPLIANCE. + days = number + years = number + }) + default = null + description = "A configuration for S3 object locking. With S3 Object Lock, you can store objects using a `write once, read many` (WORM) model. Object Lock can help prevent objects from being deleted or overwritten for a fixed amount of time or indefinitely." +} \ No newline at end of file diff --git a/versions.tf b/versions.tf index 5b2c49b9..9d8788f2 100644 --- a/versions.tf +++ b/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 2.0" + version = ">= 2.33" } } }