From 2d7ace9b9437679945ec834ebe82a0802d6e9a90 Mon Sep 17 00:00:00 2001
From: RB <7775707+nitrocode@users.noreply.github.com>
Date: Wed, 13 Nov 2024 09:10:34 -0600
Subject: [PATCH 1/3] feat: add eventbridge
---
main.tf | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/main.tf b/main.tf
index 83993ff4..2b7f2813 100644
--- a/main.tf
+++ b/main.tf
@@ -580,11 +580,14 @@ resource "time_sleep" "wait_for_aws_s3_bucket_settings" {
create_duration = "30s"
destroy_duration = "30s"
}
-// S3 event Bucket Notifications
+
+# S3 event Bucket Notifications
resource "aws_s3_bucket_notification" "bucket_notification" {
count = var.event_notification_details.enabled ? 1 : 0
bucket = local.bucket_id
+ eventbridge = var.event_notification_details.eventbridge
+
dynamic "lambda_function" {
for_each = var.event_notification_details.lambda_list
content {
@@ -612,8 +615,8 @@ resource "aws_s3_bucket_notification" "bucket_notification" {
}
}
-/// Directory Bucket
-// https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_directory_bucket
+# Directory Bucket
+# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_directory_bucket
resource "aws_s3_directory_bucket" "default" {
count = var.create_s3_directory_bucket ? 1 : 0
bucket = local.directory_bucket_name
From 89fe74d66e534c609dd7a71ebda90c929b7879b0 Mon Sep 17 00:00:00 2001
From: RB <7775707+nitrocode@users.noreply.github.com>
Date: Wed, 13 Nov 2024 09:13:34 -0600
Subject: [PATCH 2/3] feat: add eventbridge to var definition
---
variables.tf | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/variables.tf b/variables.tf
index 3b9e732b..2b87e9a5 100644
--- a/variables.tf
+++ b/variables.tf
@@ -466,9 +466,11 @@ variable "expected_bucket_owner" {
More information: https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-owner-condition.html
EOT
}
+
variable "event_notification_details" {
type = object({
- enabled = bool
+ enabled = bool
+ eventbridge = optional(bool, false)
lambda_list = optional(list(object({
lambda_function_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
@@ -485,9 +487,8 @@ variable "event_notification_details" {
topic_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
})), [])
-
})
- description = "(optional) S3 event notification details"
+ description = "S3 event notification details"
default = {
enabled = false
}
From ffcd38067c0577f68157393884ce0f49b552fe92 Mon Sep 17 00:00:00 2001
From: nitrocode <7775707+nitrocode@users.noreply.github.com>
Date: Wed, 13 Nov 2024 09:56:07 -0600
Subject: [PATCH 3/3] docs: update event notifications to support eventbridge
Signed-off-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
---
README.md | 2 +-
docs/terraform.md | 74 +++++++++++++++++++++++------------------------
2 files changed, 38 insertions(+), 38 deletions(-)
diff --git a/README.md b/README.md
index 7b65fb64..6eb4b677 100644
--- a/README.md
+++ b/README.md
@@ -284,7 +284,7 @@ Available targets:
| [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no |
| [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no |
| [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |
-| [event\_notification\_details](#input\_event\_notification\_details) | (optional) S3 event notification details |
object({|
enabled = bool
lambda_list = optional(list(object({
lambda_function_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
filter_prefix = string
filter_suffix = string
})), [])
queue_list = optional(list(object({
queue_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
})), [])
topic_list = optional(list(object({
topic_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
})), [])
})
{| no | +| [event\_notification\_details](#input\_event\_notification\_details) | S3 event notification details |
"enabled": false
}
object({|
enabled = bool
eventbridge = optional(bool, false)
lambda_list = optional(list(object({
lambda_function_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
filter_prefix = string
filter_suffix = string
})), [])
queue_list = optional(list(object({
queue_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
})), [])
topic_list = optional(list(object({
topic_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
})), [])
})
{| no | | [expected\_bucket\_owner](#input\_expected\_bucket\_owner) | Account ID of the expected bucket owner.
"enabled": false
}
list(object({| `[]` | no | diff --git a/docs/terraform.md b/docs/terraform.md index d8e7b9a3..37e2f1cb 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -58,74 +58,74 @@ | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [access\_key\_enabled](#input\_access\_key\_enabled) | Set to `true` to create an IAM Access Key for the created IAM user | `bool` | `true` | no | -| [acl](#input\_acl) | The [canned ACL](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl) to apply.
id = string
type = string
permissions = list(string)
uri = string
}))
[| no | -| [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:GetBucketLocation",
"s3:AbortMultipartUpload"
]
[| no | +| [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:GetBucketLocation",
"s3:AbortMultipartUpload"
]
{| no | -| [cors\_configuration](#input\_cors\_configuration) | Specifies the allowed headers, methods, origins and exposed headers when using CORS on this bucket |
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {},
"tenant": null
}
list(object({| `[]` | no | +| [context](#input\_context) | Single object for setting entire context at once.
id = optional(string)
allowed_headers = optional(list(string))
allowed_methods = optional(list(string))
allowed_origins = optional(list(string))
expose_headers = optional(list(string))
max_age_seconds = optional(number)
}))
{| no | +| [cors\_configuration](#input\_cors\_configuration) | Specifies the allowed headers, methods, origins and exposed headers when using CORS on this bucket |
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {},
"tenant": null
}
list(object({| `[]` | no | | [create\_s3\_directory\_bucket](#input\_create\_s3\_directory\_bucket) | Control the creation of the S3 directory bucket. Set to true to create the bucket, false to skip. | `bool` | `false` | no | -| [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.
id = optional(string)
allowed_headers = optional(list(string))
allowed_methods = optional(list(string))
allowed_origins = optional(list(string))
expose_headers = optional(list(string))
max_age_seconds = optional(number)
}))
object({|
enabled = bool
lambda_list = optional(list(object({
lambda_function_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
filter_prefix = string
filter_suffix = string
})), [])
queue_list = optional(list(object({
queue_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
})), [])
topic_list = optional(list(object({
topic_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
})), [])
})
{| no | -| [expected\_bucket\_owner](#input\_expected\_bucket\_owner) | Account ID of the expected bucket owner.
"enabled": false
}
list(object({| `[]` | no | -| [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
id = string
type = string
permissions = list(string)
uri = string
}))
object({|
enabled = bool
eventbridge = optional(bool, false)
lambda_list = optional(list(object({
lambda_function_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
filter_prefix = string
filter_suffix = string
})), [])
queue_list = optional(list(object({
queue_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
})), [])
topic_list = optional(list(object({
topic_arn = string
events = optional(list(string), ["s3:ObjectCreated:*"])
})), [])
})
{| no | +| [expected\_bucket\_owner](#input\_expected\_bucket\_owner) | Account ID of the expected bucket owner.
"enabled": false
}
list(object({| `[]` | no | +| [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
id = string
type = string
permissions = list(string)
uri = string
}))
[| no | -| [lifecycle\_configuration\_rules](#input\_lifecycle\_configuration\_rules) | A list of lifecycle V2 rules |
"default"
]
list(object({| `[]` | no | +| [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
enabled = optional(bool, true)
id = string
abort_incomplete_multipart_upload_days = optional(number)
# `filter_and` is the `and` configuration block inside the `filter` configuration.
# This is the only place you should specify a prefix.
filter_and = optional(object({
object_size_greater_than = optional(number) # integer >= 0
object_size_less_than = optional(number) # integer >= 1
prefix = optional(string)
tags = optional(map(string), {})
}))
expiration = optional(object({
date = optional(string) # string, RFC3339 time format, GMT
days = optional(number) # integer > 0
expired_object_delete_marker = optional(bool)
}))
noncurrent_version_expiration = optional(object({
newer_noncurrent_versions = optional(number) # integer > 0
noncurrent_days = optional(number) # integer >= 0
}))
transition = optional(list(object({
date = optional(string) # string, RFC3339 time format, GMT
days = optional(number) # integer > 0
storage_class = optional(string)
# string/enum, one of GLACIER, STANDARD_IA, ONEZONE_IA, INTELLIGENT_TIERING, DEEP_ARCHIVE, GLACIER_IR.
})), [])
noncurrent_version_transition = optional(list(object({
newer_noncurrent_versions = optional(number) # integer >= 0
noncurrent_days = optional(number) # integer >= 0
storage_class = optional(string)
# string/enum, one of GLACIER, STANDARD_IA, ONEZONE_IA, INTELLIGENT_TIERING, DEEP_ARCHIVE, GLACIER_IR.
})), [])
}))
[| no | +| [lifecycle\_configuration\_rules](#input\_lifecycle\_configuration\_rules) | A list of lifecycle V2 rules |
"default"
]
list(object({| `[]` | no | | [lifecycle\_rule\_ids](#input\_lifecycle\_rule\_ids) | DEPRECATED (use `lifecycle_configuration_rules`): A list of IDs to assign to corresponding `lifecycle_rules` | `list(string)` | `[]` | no | -| [lifecycle\_rules](#input\_lifecycle\_rules) | DEPRECATED (`use lifecycle_configuration_rules`): A list of lifecycle rules |
enabled = optional(bool, true)
id = string
abort_incomplete_multipart_upload_days = optional(number)
# `filter_and` is the `and` configuration block inside the `filter` configuration.
# This is the only place you should specify a prefix.
filter_and = optional(object({
object_size_greater_than = optional(number) # integer >= 0
object_size_less_than = optional(number) # integer >= 1
prefix = optional(string)
tags = optional(map(string), {})
}))
expiration = optional(object({
date = optional(string) # string, RFC3339 time format, GMT
days = optional(number) # integer > 0
expired_object_delete_marker = optional(bool)
}))
noncurrent_version_expiration = optional(object({
newer_noncurrent_versions = optional(number) # integer > 0
noncurrent_days = optional(number) # integer >= 0
}))
transition = optional(list(object({
date = optional(string) # string, RFC3339 time format, GMT
days = optional(number) # integer > 0
storage_class = optional(string)
# string/enum, one of GLACIER, STANDARD_IA, ONEZONE_IA, INTELLIGENT_TIERING, DEEP_ARCHIVE, GLACIER_IR.
})), [])
noncurrent_version_transition = optional(list(object({
newer_noncurrent_versions = optional(number) # integer >= 0
noncurrent_days = optional(number) # integer >= 0
storage_class = optional(string)
# string/enum, one of GLACIER, STANDARD_IA, ONEZONE_IA, INTELLIGENT_TIERING, DEEP_ARCHIVE, GLACIER_IR.
})), [])
}))
list(object({| `null` | no | -| [logging](#input\_logging) | Bucket access logging configuration. Empty list for no logging, list of 1 to enable logging. |
prefix = string
enabled = bool
tags = map(string)
enable_glacier_transition = bool
enable_deeparchive_transition = bool
enable_standard_ia_transition = bool
enable_current_object_expiration = bool
enable_noncurrent_version_expiration = bool
abort_incomplete_multipart_upload_days = number
noncurrent_version_glacier_transition_days = number
noncurrent_version_deeparchive_transition_days = number
noncurrent_version_expiration_days = number
standard_transition_days = number
glacier_transition_days = number
deeparchive_transition_days = number
expiration_days = number
}))
list(object({| `[]` | no | +| [lifecycle\_rules](#input\_lifecycle\_rules) | DEPRECATED (`use lifecycle_configuration_rules`): A list of lifecycle rules |
bucket_name = string
prefix = string
}))
list(object({| `null` | no | +| [logging](#input\_logging) | Bucket access logging configuration. Empty list for no logging, list of 1 to enable logging. |
prefix = string
enabled = bool
tags = map(string)
enable_glacier_transition = bool
enable_deeparchive_transition = bool
enable_standard_ia_transition = bool
enable_current_object_expiration = bool
enable_noncurrent_version_expiration = bool
abort_incomplete_multipart_upload_days = number
noncurrent_version_glacier_transition_days = number
noncurrent_version_deeparchive_transition_days = number
noncurrent_version_expiration_days = number
standard_transition_days = number
glacier_transition_days = number
deeparchive_transition_days = number
expiration_days = number
}))
list(object({| `[]` | no | | [minimum\_tls\_version](#input\_minimum\_tls\_version) | Set the minimum TLS version for in-transit traffic | `string` | `null` | no | -| [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
bucket_name = string
prefix = string
}))
object({| `null` | 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. |
mode = string # Valid values are GOVERNANCE and COMPLIANCE.
days = number
years = number
})
object({| `null` | no | | [privileged\_principal\_actions](#input\_privileged\_principal\_actions) | List of actions to permit `privileged_principal_arns` to perform on bucket and bucket prefixes (see `privileged_principal_arns`) | `list(string)` | `[]` | no | -| [privileged\_principal\_arns](#input\_privileged\_principal\_arns) | List of maps. Each map has a key, an IAM Principal ARN, whose associated value is
mode = string # Valid values are GOVERNANCE and COMPLIANCE.
days = number
years = number
})
list(object({| `null` | no | +| [s3\_replication\_rules](#input\_s3\_replication\_rules) | Specifies the replication rules for S3 bucket replication if enabled. You must also set s3\_replication\_enabled to true. |
id = optional(string)
priority = optional(number)
prefix = optional(string)
status = optional(string, "Enabled")
# delete_marker_replication { status } had been flattened for convenience
delete_marker_replication_status = optional(string, "Disabled")
# Add the configuration as it appears in the resource, for consistency
# this nested version takes precedence if both are provided.
delete_marker_replication = optional(object({
status = string
}))
# destination_bucket is specified here rather than inside the destination object because before optional
# attributes, it made it easier to work with the Terraform type system and create a list of consistent type.
# It is preserved for backward compatibility, but the nested version takes priority if both are provided.
destination_bucket = optional(string) # destination bucket ARN, overrides s3_replica_bucket_arn
destination = object({
bucket = optional(string) # destination bucket ARN, overrides s3_replica_bucket_arn
storage_class = optional(string, "STANDARD")
# replica_kms_key_id at this level is for backward compatibility, and is overridden by the one in `encryption_configuration`
replica_kms_key_id = optional(string, "")
encryption_configuration = optional(object({
replica_kms_key_id = string
}))
access_control_translation = optional(object({
owner = string
}))
# account_id is for backward compatibility, overridden by account
account_id = optional(string)
account = optional(string)
# For convenience, specifying either metrics or replication_time enables both
metrics = optional(object({
event_threshold = optional(object({
minutes = optional(number, 15) # Currently 15 is the only valid number
}), { minutes = 15 })
status = optional(string, "Enabled")
}), { status = "Disabled" })
# To preserve backward compatibility, Replication Time Control (RTC) is automatically enabled
# when metrics are enabled. To enable metrics without RTC, you must explicitly configure
# replication_time.status = "Disabled".
replication_time = optional(object({
time = optional(object({
minutes = optional(number, 15) # Currently 15 is the only valid number
}), { minutes = 15 })
status = optional(string)
}))
})
source_selection_criteria = optional(object({
replica_modifications = optional(object({
status = string # Either Enabled or Disabled
}))
sse_kms_encrypted_objects = optional(object({
status = optional(string)
}))
}))
# filter.prefix overrides top level prefix
filter = optional(object({
prefix = optional(string)
tags = optional(map(string), {})
}))
}))
list(object({| `null` | no | | [s3\_replication\_source\_roles](#input\_s3\_replication\_source\_roles) | Cross-account IAM Role ARNs that will be allowed to perform S3 replication to this bucket (for replication within the same AWS account, it's not necessary to adjust the bucket policy). | `list(string)` | `[]` | no | | [source\_ip\_allow\_list](#input\_source\_ip\_allow\_list) | List of IP addresses to allow to perform all actions to the bucket | `list(string)` | `[]` | no | -| [source\_policy\_documents](#input\_source\_policy\_documents) | List of IAM policy documents (in JSON) that are merged together into the exported document.
id = optional(string)
priority = optional(number)
prefix = optional(string)
status = optional(string, "Enabled")
# delete_marker_replication { status } had been flattened for convenience
delete_marker_replication_status = optional(string, "Disabled")
# Add the configuration as it appears in the resource, for consistency
# this nested version takes precedence if both are provided.
delete_marker_replication = optional(object({
status = string
}))
# destination_bucket is specified here rather than inside the destination object because before optional
# attributes, it made it easier to work with the Terraform type system and create a list of consistent type.
# It is preserved for backward compatibility, but the nested version takes priority if both are provided.
destination_bucket = optional(string) # destination bucket ARN, overrides s3_replica_bucket_arn
destination = object({
bucket = optional(string) # destination bucket ARN, overrides s3_replica_bucket_arn
storage_class = optional(string, "STANDARD")
# replica_kms_key_id at this level is for backward compatibility, and is overridden by the one in `encryption_configuration`
replica_kms_key_id = optional(string, "")
encryption_configuration = optional(object({
replica_kms_key_id = string
}))
access_control_translation = optional(object({
owner = string
}))
# account_id is for backward compatibility, overridden by account
account_id = optional(string)
account = optional(string)
# For convenience, specifying either metrics or replication_time enables both
metrics = optional(object({
event_threshold = optional(object({
minutes = optional(number, 15) # Currently 15 is the only valid number
}), { minutes = 15 })
status = optional(string, "Enabled")
}), { status = "Disabled" })
# To preserve backward compatibility, Replication Time Control (RTC) is automatically enabled
# when metrics are enabled. To enable metrics without RTC, you must explicitly configure
# replication_time.status = "Disabled".
replication_time = optional(object({
time = optional(object({
minutes = optional(number, 15) # Currently 15 is the only valid number
}), { minutes = 15 })
status = optional(string)
}))
})
source_selection_criteria = optional(object({
replica_modifications = optional(object({
status = string # Either Enabled or Disabled
}))
sse_kms_encrypted_objects = optional(object({
status = optional(string)
}))
}))
# filter.prefix overrides top level prefix
filter = optional(object({
prefix = optional(string)
tags = optional(map(string), {})
}))
}))
list(object({| `[]` | no | -| [website\_redirect\_all\_requests\_to](#input\_website\_redirect\_all\_requests\_to) | If provided, all website requests will be redirected to the specified host name and protocol |
index_document = string
error_document = string
routing_rules = list(object({
condition = object({
http_error_code_returned_equals = string
key_prefix_equals = string
})
redirect = object({
host_name = string
http_redirect_code = string
protocol = string
replace_key_prefix_with = string
replace_key_with = string
})
}))
}))
list(object({| `[]` | no | +| [website\_configuration](#input\_website\_configuration) | Specifies the static website hosting configuration object |
host_name = string
protocol = string
}))
list(object({| `[]` | no | +| [website\_redirect\_all\_requests\_to](#input\_website\_redirect\_all\_requests\_to) | If provided, all website requests will be redirected to the specified host name and protocol |
index_document = string
error_document = string
routing_rules = list(object({
condition = object({
http_error_code_returned_equals = string
key_prefix_equals = string
})
redirect = object({
host_name = string
http_redirect_code = string
protocol = string
replace_key_prefix_with = string
replace_key_with = string
})
}))
}))
list(object({| `[]` | no | ## Outputs | Name | Description | |------|-------------| -| [access\_key\_id](#output\_access\_key\_id) | The access key ID, if `var.user_enabled && var.access_key_enabled`.
host_name = string
protocol = string
}))