Skip to content

Commit

Permalink
feat: Added Account-level Public Access Block module, and minor fixes…
Browse files Browse the repository at this point in the history
… as fallback (#299)
  • Loading branch information
antonbabenko authored Dec 21, 2024
1 parent 8b855f8 commit 69f0f4e
Show file tree
Hide file tree
Showing 17 changed files with 343 additions and 7 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.

<!-- BEGIN_TF_DOCS -->
## Requirements
Expand Down
49 changes: 49 additions & 0 deletions examples/account-public-access/README.md
Original file line number Diff line number Diff line change
@@ -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.

<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.70 |
| <a name="requirement_random"></a> [random](#requirement\_random) | >= 2.0 |

## Providers

No providers.

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_account_public_access"></a> [account\_public\_access](#module\_account\_public\_access) | ../../modules/account-public-access | n/a |

## Resources

No resources.

## Inputs

No inputs.

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_s3_account_public_access_block_id"></a> [s3\_account\_public\_access\_block\_id](#output\_s3\_account\_public\_access\_block\_id) | AWS account ID |
<!-- END_TF_DOCS -->
21 changes: 21 additions & 0 deletions examples/account-public-access/main.tf
Original file line number Diff line number Diff line change
@@ -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
}
4 changes: 4 additions & 0 deletions examples/account-public-access/outputs.tf
Original file line number Diff line number Diff line change
@@ -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
}
Empty file.
14 changes: 14 additions & 0 deletions examples/account-public-access/versions.tf
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
8 changes: 3 additions & 5 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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"]], [])
Expand All @@ -55,7 +54,7 @@ resource "aws_s3_bucket_logging" "this" {
}

dynamic "simple_prefix" {
for_each = contains(keys(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 {}
}
Expand Down Expand Up @@ -166,7 +165,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)
Expand Down Expand Up @@ -381,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" {
Expand Down
49 changes: 49 additions & 0 deletions modules/account-public-access/README.md
Original file line number Diff line number Diff line change
@@ -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.

<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 3.74 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [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 |
|------|-------------|------|---------|:--------:|
| <a name="input_account_id"></a> [account\_id](#input\_account\_id) | AWS account ID | `string` | `null` | no |
| <a name="input_block_public_acls"></a> [block\_public\_acls](#input\_block\_public\_acls) | Whether Amazon S3 should block public ACLs for buckets in this account. | `bool` | `false` | no |
| <a name="input_block_public_policy"></a> [block\_public\_policy](#input\_block\_public\_policy) | Whether Amazon S3 should block public bucket policies for buckets in this account. | `bool` | `false` | no |
| <a name="input_create"></a> [create](#input\_create) | Whether to create this resource or not? | `bool` | `true` | no |
| <a name="input_ignore_public_acls"></a> [ignore\_public\_acls](#input\_ignore\_public\_acls) | Whether Amazon S3 should ignore public ACLs for buckets in this account. | `bool` | `false` | no |
| <a name="input_restrict_public_buckets"></a> [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 |
|------|-------------|
| <a name="output_s3_account_public_access_block_id"></a> [s3\_account\_public\_access\_block\_id](#output\_s3\_account\_public\_access\_block\_id) | AWS account ID |
<!-- END_TF_DOCS -->
10 changes: 10 additions & 0 deletions modules/account-public-access/main.tf
Original file line number Diff line number Diff line change
@@ -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
}
4 changes: 4 additions & 0 deletions modules/account-public-access/outputs.tf
Original file line number Diff line number Diff line change
@@ -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, "")
}
35 changes: 35 additions & 0 deletions modules/account-public-access/variables.tf
Original file line number Diff line number Diff line change
@@ -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
}
10 changes: 10 additions & 0 deletions modules/account-public-access/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
terraform {
required_version = ">= 1.0"

required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 3.74"
}
}
}
100 changes: 100 additions & 0 deletions wrappers/account-public-access/README.md
Original file line number Diff line number Diff line change
@@ -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::[email protected]: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::[email protected]: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"
}
}
}
}
```
12 changes: 12 additions & 0 deletions wrappers/account-public-access/main.tf
Original file line number Diff line number Diff line change
@@ -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)
}
5 changes: 5 additions & 0 deletions wrappers/account-public-access/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
output "wrapper" {
description = "Map of outputs of a wrapper."
value = module.wrapper
# sensitive = false # No sensitive module output found
}
11 changes: 11 additions & 0 deletions wrappers/account-public-access/variables.tf
Original file line number Diff line number Diff line change
@@ -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 = {}
}
Loading

0 comments on commit 69f0f4e

Please sign in to comment.