From 911db9b397baeb2544e9a8ee553557ea3c9ea0da Mon Sep 17 00:00:00 2001 From: Yonatan Koren Date: Wed, 12 Jan 2022 21:18:09 +0200 Subject: [PATCH] Feat: Add Support for S3 Object Ownership Controls (#209) - Add support for S3 object ownership controls. - Misc: add BridgeCrew exceptions. Co-authored-by: cloudpossebot <11232728+cloudpossebot@users.noreply.github.com> --- README.md | 5 +++++ docs/terraform.md | 5 +++++ main.tf | 24 ++++++++++++++++++++++++ variables.tf | 6 ++++++ versions.tf | 4 ++++ 5 files changed, 44 insertions(+) diff --git a/README.md b/README.md index 8504bfb3..3372185d 100644 --- a/README.md +++ b/README.md @@ -438,6 +438,7 @@ Available targets: | [terraform](#requirement\_terraform) | >= 0.13.0 | | [aws](#requirement\_aws) | >= 3.41.0 | | [random](#requirement\_random) | >= 2.2 | +| [time](#requirement\_time) | >= 0.7 | ## Providers @@ -445,6 +446,7 @@ Available targets: |------|---------| | [aws](#provider\_aws) | >= 3.41.0 | | [random](#provider\_random) | >= 2.2 | +| [time](#provider\_time) | >= 0.7 | ## Modules @@ -462,9 +464,11 @@ Available targets: | [aws_cloudfront_distribution.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_distribution) | resource | | [aws_cloudfront_origin_access_identity.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_origin_access_identity) | resource | | [aws_s3_bucket.origin](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource | +| [aws_s3_bucket_ownership_controls.origin](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_ownership_controls) | resource | | [aws_s3_bucket_policy.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource | | [aws_s3_bucket_public_access_block.origin](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource | | [random_password.referer](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | +| [time_sleep.wait_for_aws_s3_bucket_settings](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | | [aws_iam_policy_document.combined](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.deployment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.s3_origin](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | @@ -568,6 +572,7 @@ Available targets: | [s3\_access\_log\_bucket\_name](#input\_s3\_access\_log\_bucket\_name) | Name of the existing S3 bucket where S3 Access Logs will be delivered. Default is not to enable S3 Access Logging. | `string` | `""` | no | | [s3\_access\_log\_prefix](#input\_s3\_access\_log\_prefix) | Prefix to use for S3 Access Log object keys. Defaults to `logs/${module.this.id}` | `string` | `""` | no | | [s3\_access\_logging\_enabled](#input\_s3\_access\_logging\_enabled) | Set `true` to deliver S3 Access Logs to the `s3_access_log_bucket_name` bucket.
Defaults to `false` if `s3_access_log_bucket_name` is empty (the default), `true` otherwise.
Must be set explicitly if the access log bucket is being created at the same time as this module is being invoked. | `bool` | `null` | no | +| [s3\_object\_ownership](#input\_s3\_object\_ownership) | Specifies the S3 object ownership control on the origin bucket. Valid values are `ObjectWriter`, `BucketOwnerPreferred`, and 'BucketOwnerEnforced'. | `string` | `"ObjectWriter"` | no | | [s3\_origins](#input\_s3\_origins) | A list of S3 [origins](https://www.terraform.io/docs/providers/aws/r/cloudfront_distribution.html#origin-arguments) (in addition to the one created by this module) for this distribution.
S3 buckets configured as websites are `custom_origins`, not `s3_origins`.
Specifying `s3_origin_config.origin_access_identity` as `null` or `""` will have it translated to the `origin_access_identity` used by the origin created by the module. |
list(object({
domain_name = string
origin_id = string
origin_path = string
s3_origin_config = object({
origin_access_identity = string
})
}))
| `[]` | no | | [s3\_website\_password\_enabled](#input\_s3\_website\_password\_enabled) | If set to true, and `website_enabled` is also true, a password will be required in the `Referrer` field of the
HTTP request in order to access the website, and Cloudfront will be configured to pass this password in its requests.
This will make it much harder for people to bypass Cloudfront and access the S3 website directly via its website endpoint. | `bool` | `false` | no | | [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | diff --git a/docs/terraform.md b/docs/terraform.md index 851c1f15..eca568ba 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -6,6 +6,7 @@ | [terraform](#requirement\_terraform) | >= 0.13.0 | | [aws](#requirement\_aws) | >= 3.41.0 | | [random](#requirement\_random) | >= 2.2 | +| [time](#requirement\_time) | >= 0.7 | ## Providers @@ -13,6 +14,7 @@ |------|---------| | [aws](#provider\_aws) | >= 3.41.0 | | [random](#provider\_random) | >= 2.2 | +| [time](#provider\_time) | >= 0.7 | ## Modules @@ -30,9 +32,11 @@ | [aws_cloudfront_distribution.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_distribution) | resource | | [aws_cloudfront_origin_access_identity.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_origin_access_identity) | resource | | [aws_s3_bucket.origin](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource | +| [aws_s3_bucket_ownership_controls.origin](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_ownership_controls) | resource | | [aws_s3_bucket_policy.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource | | [aws_s3_bucket_public_access_block.origin](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource | | [random_password.referer](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | +| [time_sleep.wait_for_aws_s3_bucket_settings](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | | [aws_iam_policy_document.combined](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.deployment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.s3_origin](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | @@ -136,6 +140,7 @@ | [s3\_access\_log\_bucket\_name](#input\_s3\_access\_log\_bucket\_name) | Name of the existing S3 bucket where S3 Access Logs will be delivered. Default is not to enable S3 Access Logging. | `string` | `""` | no | | [s3\_access\_log\_prefix](#input\_s3\_access\_log\_prefix) | Prefix to use for S3 Access Log object keys. Defaults to `logs/${module.this.id}` | `string` | `""` | no | | [s3\_access\_logging\_enabled](#input\_s3\_access\_logging\_enabled) | Set `true` to deliver S3 Access Logs to the `s3_access_log_bucket_name` bucket.
Defaults to `false` if `s3_access_log_bucket_name` is empty (the default), `true` otherwise.
Must be set explicitly if the access log bucket is being created at the same time as this module is being invoked. | `bool` | `null` | no | +| [s3\_object\_ownership](#input\_s3\_object\_ownership) | Specifies the S3 object ownership control on the origin bucket. Valid values are `ObjectWriter`, `BucketOwnerPreferred`, and 'BucketOwnerEnforced'. | `string` | `"ObjectWriter"` | no | | [s3\_origins](#input\_s3\_origins) | A list of S3 [origins](https://www.terraform.io/docs/providers/aws/r/cloudfront_distribution.html#origin-arguments) (in addition to the one created by this module) for this distribution.
S3 buckets configured as websites are `custom_origins`, not `s3_origins`.
Specifying `s3_origin_config.origin_access_identity` as `null` or `""` will have it translated to the `origin_access_identity` used by the origin created by the module. |
list(object({
domain_name = string
origin_id = string
origin_path = string
s3_origin_config = object({
origin_access_identity = string
})
}))
| `[]` | no | | [s3\_website\_password\_enabled](#input\_s3\_website\_password\_enabled) | If set to true, and `website_enabled` is also true, a password will be required in the `Referrer` field of the
HTTP request in order to access the website, and Cloudfront will be configured to pass this password in its requests.
This will make it much harder for people to bypass Cloudfront and access the S3 website directly via its website endpoint. | `bool` | `false` | no | | [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | diff --git a/main.tf b/main.tf index 2310fbad..29f317ec 100644 --- a/main.tf +++ b/main.tf @@ -300,6 +300,28 @@ resource "aws_s3_bucket_public_access_block" "origin" { depends_on = [aws_s3_bucket_policy.default] } +resource "aws_s3_bucket_ownership_controls" "origin" { + count = local.create_s3_origin_bucket ? 1 : 0 + + bucket = local.bucket + + rule { + object_ownership = var.s3_object_ownership + } + + depends_on = [time_sleep.wait_for_aws_s3_bucket_settings] +} + +# Workaround for S3 eventual consistency for settings relating to objects +resource "time_sleep" "wait_for_aws_s3_bucket_settings" { + count = local.create_s3_origin_bucket ? 1 : 0 + + create_duration = "30s" + destroy_duration = "30s" + + depends_on = [aws_s3_bucket_public_access_block.origin, aws_s3_bucket_policy.default] +} + module "logs" { source = "cloudposse/s3-log-storage/aws" version = "0.26.0" @@ -327,6 +349,8 @@ data "aws_s3_bucket" "cf_logs" { resource "aws_cloudfront_distribution" "default" { #bridgecrew:skip=BC_AWS_GENERAL_27:Skipping `Ensure CloudFront distribution has WAF enabled` because AWS WAF is indeed configurable and is managed via `var.web_acl_id`. + #bridgecrew:skip=BC_AWS_NETWORKING_63:Skipping `Verify CloudFront Distribution Viewer Certificate is using TLS v1.2` because the minimum TLS version for the viewer certificate is indeed configurable and is managed via `var.minimum_protocol_version`. + #bridgecrew:skip=BC_AWS_NETWORKING_65:Skipping `Ensure CloudFront distribution has a strict security headers policy attached` because the response header policy is indeed configurable and is managed via `var.response_headers_policy_id`. count = local.enabled ? 1 : 0 enabled = var.distribution_enabled diff --git a/variables.tf b/variables.tf index 43017bde..e3b82e48 100644 --- a/variables.tf +++ b/variables.tf @@ -540,6 +540,12 @@ variable "s3_access_log_prefix" { description = "Prefix to use for S3 Access Log object keys. Defaults to `logs/$${module.this.id}`" } +variable "s3_object_ownership" { + type = string + default = "ObjectWriter" + description = "Specifies the S3 object ownership control on the origin bucket. Valid values are `ObjectWriter`, `BucketOwnerPreferred`, and 'BucketOwnerEnforced'." +} + variable "cloudfront_access_logging_enabled" { type = bool default = true diff --git a/versions.tf b/versions.tf index cf8970ac..e14a4e82 100644 --- a/versions.tf +++ b/versions.tf @@ -10,5 +10,9 @@ terraform { source = "hashicorp/random" version = ">= 2.2" } + time = { + source = "hashicorp/time" + version = ">= 0.7" + } } }