From e21d08e23f156d4fa21165c76abbd9b035d20879 Mon Sep 17 00:00:00 2001 From: Anton Babenko Date: Fri, 20 Dec 2024 19:54:37 +0100 Subject: [PATCH 1/6] Added default value for versioning as fallback --- main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.tf b/main.tf index 4bffeb08..cc2a9612 100644 --- a/main.tf +++ b/main.tf @@ -166,7 +166,7 @@ resource "aws_s3_bucket_versioning" "this" { versioning_configuration { # Valid values: "Enabled" or "Suspended" - status = try(var.versioning["enabled"] ? "Enabled" : "Suspended", tobool(var.versioning["status"]) ? "Enabled" : "Suspended", title(lower(var.versioning["status"]))) + status = try(var.versioning["enabled"] ? "Enabled" : "Suspended", tobool(var.versioning["status"]) ? "Enabled" : "Suspended", title(lower(var.versioning["status"])), "Enabled") # Valid values: "Enabled" or "Disabled" mfa_delete = try(tobool(var.versioning["mfa_delete"]) ? "Enabled" : "Disabled", title(lower(var.versioning["mfa_delete"])), null) From a8237502ed131f39b6c1418e31d35785892f4570 Mon Sep 17 00:00:00 2001 From: Anton Babenko Date: Sat, 21 Dec 2024 00:02:45 +0100 Subject: [PATCH 2/6] Fixed simple_prefix expression --- main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.tf b/main.tf index cc2a9612..1601eb57 100644 --- a/main.tf +++ b/main.tf @@ -55,7 +55,7 @@ resource "aws_s3_bucket_logging" "this" { } dynamic "simple_prefix" { - for_each = contains(keys(target_object_key_format.value), "simple_prefix") ? [true] : [] + for_each = can(target_object_key_format.value["simple_prefix"]) ? [true] : [] content {} } From 7ac088d3501d5dd9f90727318466505368c2eac2 Mon Sep 17 00:00:00 2001 From: Anton Babenko Date: Sat, 21 Dec 2024 00:13:47 +0100 Subject: [PATCH 3/6] Make simple_prefix default option for logging --- main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.tf b/main.tf index 1601eb57..cf050254 100644 --- a/main.tf +++ b/main.tf @@ -55,7 +55,7 @@ resource "aws_s3_bucket_logging" "this" { } dynamic "simple_prefix" { - for_each = can(target_object_key_format.value["simple_prefix"]) ? [true] : [] + for_each = length(try(target_object_key_format.value["partitioned_prefix"], [])) == 0 || can(target_object_key_format.value["simple_prefix"]) ? [true] : [] content {} } From 549a3a2510c9acc6a9bf21ab62ebe3cdffe5fd06 Mon Sep 17 00:00:00 2001 From: Anton Babenko Date: Sat, 21 Dec 2024 00:15:22 +0100 Subject: [PATCH 4/6] target_prefix is actually required --- main.tf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/main.tf b/main.tf index cf050254..9b770021 100644 --- a/main.tf +++ b/main.tf @@ -39,8 +39,7 @@ resource "aws_s3_bucket_logging" "this" { bucket = aws_s3_bucket.this[0].id target_bucket = var.logging["target_bucket"] - target_prefix = try(var.logging["target_prefix"], null) - + target_prefix = var.logging["target_prefix"] dynamic "target_object_key_format" { for_each = try([var.logging["target_object_key_format"]], []) From 5518b15be672c5e2ac3ddeb346b3aba8f43b4b27 Mon Sep 17 00:00:00 2001 From: Anton Babenko Date: Sat, 21 Dec 2024 13:23:33 +0100 Subject: [PATCH 5/6] Removed deprecated prefix from aws_s3_bucket_replication_configuration --- main.tf | 1 - 1 file changed, 1 deletion(-) diff --git a/main.tf b/main.tf index 9b770021..6554c26c 100644 --- a/main.tf +++ b/main.tf @@ -380,7 +380,6 @@ resource "aws_s3_bucket_replication_configuration" "this" { content { id = try(rule.value.id, null) priority = try(rule.value.priority, null) - prefix = try(rule.value.prefix, null) status = try(tobool(rule.value.status) ? "Enabled" : "Disabled", title(lower(rule.value.status)), "Enabled") dynamic "delete_marker_replication" { From 51e7d270c05c9aa04b79b8411f146ad91ee8677a Mon Sep 17 00:00:00 2001 From: Anton Babenko Date: Sat, 21 Dec 2024 15:03:13 +0100 Subject: [PATCH 6/6] Added module for S3 Account-level Public Access Block --- README.md | 8 +- examples/account-public-access/README.md | 49 ++++++++++ examples/account-public-access/main.tf | 21 ++++ examples/account-public-access/outputs.tf | 4 + examples/account-public-access/variables.tf | 0 examples/account-public-access/versions.tf | 14 +++ modules/account-public-access/README.md | 49 ++++++++++ modules/account-public-access/main.tf | 10 ++ modules/account-public-access/outputs.tf | 4 + modules/account-public-access/variables.tf | 35 +++++++ modules/account-public-access/versions.tf | 10 ++ wrappers/account-public-access/README.md | 100 ++++++++++++++++++++ wrappers/account-public-access/main.tf | 12 +++ wrappers/account-public-access/outputs.tf | 5 + wrappers/account-public-access/variables.tf | 11 +++ wrappers/account-public-access/versions.tf | 10 ++ 16 files changed, 340 insertions(+), 2 deletions(-) create mode 100644 examples/account-public-access/README.md create mode 100644 examples/account-public-access/main.tf create mode 100644 examples/account-public-access/outputs.tf create mode 100644 examples/account-public-access/variables.tf create mode 100644 examples/account-public-access/versions.tf create mode 100644 modules/account-public-access/README.md create mode 100644 modules/account-public-access/main.tf create mode 100644 modules/account-public-access/outputs.tf create mode 100644 modules/account-public-access/variables.tf create mode 100644 modules/account-public-access/versions.tf create mode 100644 wrappers/account-public-access/README.md create mode 100644 wrappers/account-public-access/main.tf create mode 100644 wrappers/account-public-access/outputs.tf create mode 100644 wrappers/account-public-access/variables.tf create mode 100644 wrappers/account-public-access/versions.tf diff --git a/README.md b/README.md index 179ed856..b6eba6c0 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ These features of S3 bucket configurations are supported: - Cross-Region Replication (CRR) - ELB log delivery bucket policy - ALB/NLB log delivery bucket policy +- Account-level Public Access Block ## Usage @@ -117,8 +118,11 @@ Users of Terragrunt can achieve similar results by using modules provided in the - [Complete](https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/tree/master/examples/complete) - Complete S3 bucket with most of supported features enabled - [Cross-Region Replication](https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/tree/master/examples/s3-replication) - S3 bucket with Cross-Region Replication (CRR) enabled -- [S3 Bucket Notifications](https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/tree/master/examples/notification) - S3 bucket notifications to Lambda functions, SQS queues, and SNS topics. -- [S3 Bucket Object](https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/tree/master/examples/object) - Manage S3 bucket objects. +- [S3 Notifications](https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/tree/master/examples/notification) - S3 bucket notifications to Lambda functions, SQS queues, and SNS topics. +- [S3 Object](https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/tree/master/examples/object) - Manage S3 bucket objects. +- [S3 Analytics](https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/tree/master/examples/s3-analytics) - S3 bucket Analytics Configurations. +- [S3 Inventory](https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/tree/master/examples/s3-inventory) - S3 bucket Inventory configuration. +- [S3 Account-level Public Access Block](https://github.com/terraform-aws-modules/terraform-aws-s3-bucket/tree/master/examples/account-public-access) - Manage S3 account-level Public Access Block. ## Requirements diff --git a/examples/account-public-access/README.md b/examples/account-public-access/README.md new file mode 100644 index 00000000..9dae8331 --- /dev/null +++ b/examples/account-public-access/README.md @@ -0,0 +1,49 @@ +# S3 account-level Public Access Block + +Configuration in this directory creates S3 account-level Public Access Block. + +## Usage + +To run this example you need to execute: + +```bash +$ terraform init +$ terraform plan +$ terraform apply +``` + +Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources. + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0 | +| [aws](#requirement\_aws) | >= 5.70 | +| [random](#requirement\_random) | >= 2.0 | + +## Providers + +No providers. + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [account\_public\_access](#module\_account\_public\_access) | ../../modules/account-public-access | n/a | + +## Resources + +No resources. + +## Inputs + +No inputs. + +## Outputs + +| Name | Description | +|------|-------------| +| [s3\_account\_public\_access\_block\_id](#output\_s3\_account\_public\_access\_block\_id) | AWS account ID | + diff --git a/examples/account-public-access/main.tf b/examples/account-public-access/main.tf new file mode 100644 index 00000000..3f506fdd --- /dev/null +++ b/examples/account-public-access/main.tf @@ -0,0 +1,21 @@ +provider "aws" { + region = local.region + + # Make it faster by skipping something + skip_metadata_api_check = true + skip_region_validation = true + skip_credentials_validation = true +} + +locals { + region = "eu-west-1" +} + +module "account_public_access" { + source = "../../modules/account-public-access" + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} diff --git a/examples/account-public-access/outputs.tf b/examples/account-public-access/outputs.tf new file mode 100644 index 00000000..9f284883 --- /dev/null +++ b/examples/account-public-access/outputs.tf @@ -0,0 +1,4 @@ +output "s3_account_public_access_block_id" { + description = "AWS account ID" + value = module.account_public_access.s3_account_public_access_block_id +} diff --git a/examples/account-public-access/variables.tf b/examples/account-public-access/variables.tf new file mode 100644 index 00000000..e69de29b diff --git a/examples/account-public-access/versions.tf b/examples/account-public-access/versions.tf new file mode 100644 index 00000000..6d9488f3 --- /dev/null +++ b/examples/account-public-access/versions.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.70" + } + random = { + source = "hashicorp/random" + version = ">= 2.0" + } + } +} diff --git a/modules/account-public-access/README.md b/modules/account-public-access/README.md new file mode 100644 index 00000000..4c6fadd5 --- /dev/null +++ b/modules/account-public-access/README.md @@ -0,0 +1,49 @@ +# S3 account-level Public Access Block + +Manages S3 account-level Public Access Block configuration. + +## Note + +Each AWS account may only have one S3 Public Access Block configuration. + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0 | +| [aws](#requirement\_aws) | >= 3.74 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 3.74 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_s3_account_public_access_block.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_account_public_access_block) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [account\_id](#input\_account\_id) | AWS account ID | `string` | `null` | no | +| [block\_public\_acls](#input\_block\_public\_acls) | Whether Amazon S3 should block public ACLs for buckets in this account. | `bool` | `false` | no | +| [block\_public\_policy](#input\_block\_public\_policy) | Whether Amazon S3 should block public bucket policies for buckets in this account. | `bool` | `false` | no | +| [create](#input\_create) | Whether to create this resource or not? | `bool` | `true` | no | +| [ignore\_public\_acls](#input\_ignore\_public\_acls) | Whether Amazon S3 should ignore public ACLs for buckets in this account. | `bool` | `false` | no | +| [restrict\_public\_buckets](#input\_restrict\_public\_buckets) | Whether Amazon S3 should restrict public bucket policies for buckets in this account. | `bool` | `false` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [s3\_account\_public\_access\_block\_id](#output\_s3\_account\_public\_access\_block\_id) | AWS account ID | + diff --git a/modules/account-public-access/main.tf b/modules/account-public-access/main.tf new file mode 100644 index 00000000..bd27b8f2 --- /dev/null +++ b/modules/account-public-access/main.tf @@ -0,0 +1,10 @@ +resource "aws_s3_account_public_access_block" "this" { + count = var.create ? 1 : 0 + + account_id = var.account_id + + block_public_acls = var.block_public_acls + block_public_policy = var.block_public_policy + ignore_public_acls = var.ignore_public_acls + restrict_public_buckets = var.restrict_public_buckets +} diff --git a/modules/account-public-access/outputs.tf b/modules/account-public-access/outputs.tf new file mode 100644 index 00000000..ce31327c --- /dev/null +++ b/modules/account-public-access/outputs.tf @@ -0,0 +1,4 @@ +output "s3_account_public_access_block_id" { + description = "AWS account ID" + value = try(aws_s3_account_public_access_block.this[0].id, "") +} diff --git a/modules/account-public-access/variables.tf b/modules/account-public-access/variables.tf new file mode 100644 index 00000000..09d9758b --- /dev/null +++ b/modules/account-public-access/variables.tf @@ -0,0 +1,35 @@ +variable "create" { + description = "Whether to create this resource or not?" + type = bool + default = true +} + +variable "account_id" { + description = "AWS account ID" + type = string + default = null +} + +variable "block_public_acls" { + description = "Whether Amazon S3 should block public ACLs for buckets in this account." + type = bool + default = false +} + +variable "block_public_policy" { + description = "Whether Amazon S3 should block public bucket policies for buckets in this account." + type = bool + default = false +} + +variable "ignore_public_acls" { + description = "Whether Amazon S3 should ignore public ACLs for buckets in this account." + type = bool + default = false +} + +variable "restrict_public_buckets" { + description = "Whether Amazon S3 should restrict public bucket policies for buckets in this account." + type = bool + default = false +} diff --git a/modules/account-public-access/versions.tf b/modules/account-public-access/versions.tf new file mode 100644 index 00000000..ff97a040 --- /dev/null +++ b/modules/account-public-access/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.74" + } + } +} diff --git a/wrappers/account-public-access/README.md b/wrappers/account-public-access/README.md new file mode 100644 index 00000000..e9acd236 --- /dev/null +++ b/wrappers/account-public-access/README.md @@ -0,0 +1,100 @@ +# Wrapper for module: `modules/account-public-access` + +The configuration in this directory contains an implementation of a single module wrapper pattern, which allows managing several copies of a module in places where using the native Terraform 0.13+ `for_each` feature is not feasible (e.g., with Terragrunt). + +You may want to use a single Terragrunt configuration file to manage multiple resources without duplicating `terragrunt.hcl` files for each copy of the same module. + +This wrapper does not implement any extra functionality. + +## Usage with Terragrunt + +`terragrunt.hcl`: + +```hcl +terraform { + source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers/account-public-access" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git//wrappers/account-public-access?ref=master" +} + +inputs = { + defaults = { # Default values + create = true + tags = { + Terraform = "true" + Environment = "dev" + } + } + + items = { + my-item = { + # omitted... can be any argument supported by the module + } + my-second-item = { + # omitted... can be any argument supported by the module + } + # omitted... + } +} +``` + +## Usage with Terraform + +```hcl +module "wrapper" { + source = "terraform-aws-modules/s3-bucket/aws//wrappers/account-public-access" + + defaults = { # Default values + create = true + tags = { + Terraform = "true" + Environment = "dev" + } + } + + items = { + my-item = { + # omitted... can be any argument supported by the module + } + my-second-item = { + # omitted... can be any argument supported by the module + } + # omitted... + } +} +``` + +## Example: Manage multiple S3 buckets in one Terragrunt layer + +`eu-west-1/s3-buckets/terragrunt.hcl`: + +```hcl +terraform { + source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers" + # Alternative source: + # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git//wrappers?ref=master" +} + +inputs = { + defaults = { + force_destroy = true + + attach_elb_log_delivery_policy = true + attach_lb_log_delivery_policy = true + attach_deny_insecure_transport_policy = true + attach_require_latest_tls_policy = true + } + + items = { + bucket1 = { + bucket = "my-random-bucket-1" + } + bucket2 = { + bucket = "my-random-bucket-2" + tags = { + Secure = "probably" + } + } + } +} +``` diff --git a/wrappers/account-public-access/main.tf b/wrappers/account-public-access/main.tf new file mode 100644 index 00000000..e0ab498b --- /dev/null +++ b/wrappers/account-public-access/main.tf @@ -0,0 +1,12 @@ +module "wrapper" { + source = "../../modules/account-public-access" + + for_each = var.items + + account_id = try(each.value.account_id, var.defaults.account_id, null) + block_public_acls = try(each.value.block_public_acls, var.defaults.block_public_acls, false) + block_public_policy = try(each.value.block_public_policy, var.defaults.block_public_policy, false) + create = try(each.value.create, var.defaults.create, true) + ignore_public_acls = try(each.value.ignore_public_acls, var.defaults.ignore_public_acls, false) + restrict_public_buckets = try(each.value.restrict_public_buckets, var.defaults.restrict_public_buckets, false) +} diff --git a/wrappers/account-public-access/outputs.tf b/wrappers/account-public-access/outputs.tf new file mode 100644 index 00000000..ec6da5f4 --- /dev/null +++ b/wrappers/account-public-access/outputs.tf @@ -0,0 +1,5 @@ +output "wrapper" { + description = "Map of outputs of a wrapper." + value = module.wrapper + # sensitive = false # No sensitive module output found +} diff --git a/wrappers/account-public-access/variables.tf b/wrappers/account-public-access/variables.tf new file mode 100644 index 00000000..a6ea0962 --- /dev/null +++ b/wrappers/account-public-access/variables.tf @@ -0,0 +1,11 @@ +variable "defaults" { + description = "Map of default values which will be used for each item." + type = any + default = {} +} + +variable "items" { + description = "Maps of items to create a wrapper from. Values are passed through to the module." + type = any + default = {} +} diff --git a/wrappers/account-public-access/versions.tf b/wrappers/account-public-access/versions.tf new file mode 100644 index 00000000..ff97a040 --- /dev/null +++ b/wrappers/account-public-access/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.74" + } + } +}